C#使用Xamarin开发可移植移动应用目录
源码地址:https://github.com/l2999019/DemoApp
可以Star一下,随意 - -
呃 也有半个月没更新了. 本来这篇的Demo早就写完了,文章也构思好了.迟迟没发布..是因为实在太忙..
项目要上线..各种 你们懂的..
正赶上自己十一人生大事..结婚..所以..忙的那叫一个脚不沾地啊.
使用我们前面所学的技术,写一个增删改查.
效果如下:
正文
废话不多说,直接开始吧.
列表ListView,采用继承重写的方式,实现简易的下拉刷新
采用HttpClient的方式访问后端的WebAPI.
使用了一系列的Xamarin提供的插件.
采用了MVVM的方式,来编写我们的业务代码.
前面我们说过,我们访问的是后端WebAPI,内容很简单..就是一个增删改查.
多余的我就不多说了,直接贴出代码如下:
public class ValuesController : ApiController { // GET api/values [HttpGet] public List<ContextTable> Get(int page,int count) { using (Models.School_TestEntities entites = new Models.School_TestEntities()) { var date= entites.ContextTable.OrderBy(c => c.ID).Skip((page - 1) * count).Take(count).ToList(); return date; } } // PUT api/values/5 public bool UpdateDate(Models.ContextTable datemodel) { // var date = JsonConvert.DeserializeObject<Models.ContextTable>(value); using (Models.School_TestEntities entites = new Models.School_TestEntities()) { var model = entites.ContextTable.Where(a => a.ID == datemodel.ID).FirstOrDefault(); model.Title = datemodel.Title; model.AddTime = datemodel.AddTime; model.Context = datemodel.Context; if (entites.SaveChanges() > 0) { return true; } return false; } } public bool AddDate(Models.ContextTable model) { var date = model; using (Models.School_TestEntities entites = new Models.School_TestEntities()) { entites.ContextTable.Add(date); if (entites.SaveChanges() >0) { return true; } } return false; } // DELETE api/values/5 public bool Delete(int id) { using (Models.School_TestEntities entites = new Models.School_TestEntities()) { var date = entites.ContextTable.Where(a => a.ID == id).FirstOrDefault(); entites.ContextTable.Remove(date); if (entites.SaveChanges() > 0) { return true; } return false; } } }
就是编写一个访问WebAPI用的仓储.代码如下:
public class ContextDataStore { HttpClient client; string RestUrl = "http://192.168.3.74:53470/api/values"; public ContextDataStore() { client = new HttpClient(); client.MaxResponseContentBufferSize = 256000; } public async Task<bool> AddItemAsync(ContextModel item) { var uri = new Uri(RestUrl+ "/AddDate/"); var json = JsonConvert.SerializeObject(item); var content = new StringContent(json); content.Headers.ContentType = new MediaTypeHeaderValue("application/json"); var response = await client.PostAsync(uri, content); if (response.IsSuccessStatusCode) { var date = await response.Content.ReadAsStringAsync(); return Convert.ToBoolean(date); } return false; } public async Task<bool> UpdateItemAsync(ContextModel item) { var uri = new Uri(RestUrl + "/UpdateDate/"); var json = JsonConvert.SerializeObject(item); var content = new StringContent(json); content.Headers.ContentType = new MediaTypeHeaderValue("application/json"); var response = await client.PostAsync(uri, content); if (response.IsSuccessStatusCode) { var date = await response.Content.ReadAsStringAsync(); return Convert.ToBoolean(date); } return false; } public async Task<bool> DeleteItemAsync(int id) { var uri = new Uri(string.Format(RestUrl + "/Delete/?id=" + id, string.Empty)); var response = await client.DeleteAsync(uri); if (response.IsSuccessStatusCode) { var content = await response.Content.ReadAsStringAsync(); return Convert.ToBoolean(content); } return false; } public async Task<IEnumerable<ContextModel>> GetItemsAsync(int page,int rows) { var uri = new Uri(string.Format(RestUrl+"/Get/?page="+page+ "&count=" + rows, string.Empty)); var response = await client.GetAsync(uri); List<ContextModel> Items = new List<ContextModel>(); if (response.IsSuccessStatusCode) { var content = await response.Content.ReadAsStringAsync(); try { Items = JsonConvert.DeserializeObject<List<ContextModel>>(content); } catch (Exception ex) { } } return Items; } }
详解请查看系列目录中的MVVM篇
代码如下(注释中有解释):
public class ContextViewModel: INotifyPropertyChanged { //初始化仓储 public ContextDataStore DataStore =new ContextDataStore(); //设置绑定对象 public ObservableCollection<ContextModel> Items { get; set; } //设置刷新命令 public Command LoadItemsCommand { get; set; } public event PropertyChangedEventHandler PropertyChanged; private int page = 1; private int rows = 10; /// <summary> /// 初始化各种数据与监听 /// </summary> public ContextViewModel() { Items = new ObservableCollection<ContextModel>(); LoadItemsCommand = new Command(async () => await ExecuteLoadItemsCommand()); //监听添加的消息 MessagingCenter.Subscribe<ContextModelPage, ContextModel>(this, "AddItem", async (obj, item) => { var _item = item as ContextModel; var date = await DataStore.AddItemAsync(_item); if (date) { LoadDate(); await obj.DisplayAlert("提示", "添加成功!", "关闭"); await obj.Navigation.PopAsync(); } else { await obj.DisplayAlert("提示", "添加失败!", "关闭"); } }); //监听更新的消息 MessagingCenter.Subscribe<ContextModelPage, ContextModel>(this, "UpdateItem", async (obj, item) => { var date = await DataStore.UpdateItemAsync(item); if (date) { LoadDate(); await obj.DisplayAlert("提示", "修改成功!", "关闭"); await obj.Navigation.PopAsync(); } else { await obj.DisplayAlert("提示", "修改失败!", "关闭"); } }); ExecuteLoadItemsCommand(); } /// <summary> /// 删除的方法 /// </summary> /// <param name="id"></param> /// <returns></returns> public async Task<bool> DeleteItem(int id) { var date = await DataStore.DeleteItemAsync(id); if (date) { var item = Items.Where(a => a.ID == id).FirstOrDefault(); Items.Remove(item); OnPropertyChanged("Items"); } return date; } /// <summary> /// 加载数据的命令 /// </summary> /// <returns></returns> async Task ExecuteLoadItemsCommand() { try { //Items.Clear(); var items = await DataStore.GetItemsAsync(page,rows); foreach (var item in items) { Items.Add(item); } OnPropertyChanged("Items"); page++; } catch (Exception ex) { } } /// <summary> /// 重新刷新数据 /// </summary> private async void LoadDate() { Items.Clear(); page = 1; var items = await DataStore.GetItemsAsync(page, rows); foreach (var item in items) { Items.Add(item); } OnPropertyChanged("Items"); page++; } protected virtual void OnPropertyChanged(string propertyName) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } } }
嗯.还是说明一下 这个ViewModel就类似于MVC中的控制器,起到一个承上启下的作用.与页面交互并把这些交互信息传递给仓储,由仓储来访问WebAPI
我们创建一个ContentPage页面如下:
<?xml version="1.0" encoding="utf-8" ?> <ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:local="clr-namespace:DemoApp.HTTPClientDemo.ViewModels" xmlns:Controls="clr-namespace:DemoApp.HTTPClientDemo;" x:Class="DemoApp.HTTPClientDemo.ListViewPage"> <ContentPage.ToolbarItems> <ToolbarItem Text="添加" Order="Default" Clicked="ToolbarItem_Clicked" /> </ContentPage.ToolbarItems> <ContentPage.Content> <StackLayout> <Controls:MyListView ItemsSource="{Binding Items}" VerticalOptions="FillAndExpand" HasUnevenRows="true" LoadMoreCommand="{Binding LoadItemsCommand}" x:Name="listdate" > <ListView.ItemTemplate> <DataTemplate > <ViewCell> <ViewCell.ContextActions> <MenuItem CommandParameter="{Binding}" Clicked="MenuItem_Clicked" Text="修改" /> <MenuItem x:Name="DeleteBtn" CommandParameter="{Binding ID}" Clicked="MenuItem_Clicked_1" Text="删除" IsDestructive="True" /> </ViewCell.ContextActions> <StackLayout Padding="10"> <Label Text="{Binding Title}" LineBreakMode="NoWrap" Style="{DynamicResource ListItemTextStyle}" FontSize="16"/> <Label Text="{Binding AddTime}" LineBreakMode="NoWrap" Style="{DynamicResource ListItemDetailTextStyle}" FontSize="13"/> </StackLayout> </ViewCell> </DataTemplate> </ListView.ItemTemplate> </Controls:MyListView> </StackLayout> </ContentPage.Content> </ContentPage>
这个ContentPage中,我们使用了StackLayout布局,ListView,ToolbarItem 等控件.绑定了我们前面编写的ContextViewModel(后台代码绑定的,在下面)
编写这个ContentPage的后台代码如下:
public partial class ListViewPage : ContentPage { ContextViewModel viewModel; public ListViewPage() { InitializeComponent(); this.BindingContext = viewModel = new ContextViewModel(); } private void MenuItem_Clicked(object sender, EventArgs e) { var mi = ((MenuItem)sender); ContextModel date = mi.CommandParameter as ContextModel; Navigation.PushAsync(new ContextModelPage()); MessagingCenter.Send<ListViewPage,ContextModel>(this, "GetModel", date); } private async void MenuItem_Clicked_1(object sender, EventArgs e) { var mi = ((MenuItem)sender); int id = Convert.ToInt32( mi.CommandParameter); var date = await viewModel.DeleteItem(id); if (!date) { await DisplayAlert("提示", "删除失败,请检查网络", "确定"); } } private void ToolbarItem_Clicked(object sender, EventArgs e) { Navigation.PushAsync(new ContextModelPage()); } }
这里,我们绑定了ContextViewModel,然后编写了界面上的各种交互事件.
以上,我们的列表也就算完成了,下面我们来看看我们的增加和修改页面.(也就是显示详细数据的页面)
如下:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="DemoApp.HTTPClientDemo.ContextModelPage"> <ContentPage.Content> <StackLayout> <Label Text="标题:" /> <Entry Placeholder="请输入标题" x:Name="titel" /> <Label Text="时间:" /> <DatePicker Format="yyyy-MM-dd" x:Name="times" /> <Label Text="内容:" /> <Editor HorizontalOptions="FillAndExpand" HeightRequest="200" x:Name="contexts" /> <Button Text="保存" x:Name="BtnSave" Clicked="BtnSave_Clicked" ></Button> </StackLayout> </ContentPage.Content> </ContentPage>
这里我们采用了前面系列中讲过的Label ,Entry,DatePicker ,Editor ,编写后台代码如下:
public partial class ContextModelPage : ContentPage { private int isUpdate = 0; public ContextModelPage() { InitializeComponent(); MessagingCenter.Subscribe<ListViewPage, ContextModel>(this, "GetModel", (obj, item) => { //DisplayAlert("提示", "传过来的参数为" + item, "确定"); this.times.Date = item.AddTime.Value; this.titel.Text = item.Title; this.contexts.Text = item.Context; isUpdate = item.ID; }); } private void BtnSave_Clicked(object sender, EventArgs e) { if (isUpdate>0) { ContextModel model = new ContextModel(); model.AddTime = times.Date; model.Context = contexts.Text; model.Title = titel.Text; model.ID = isUpdate; MessagingCenter.Send(this, "UpdateItem", model); } else { ContextModel model = new ContextModel(); model.AddTime = times.Date; model.Context = contexts.Text; model.Title = titel.Text; MessagingCenter.Send(this, "AddItem", model); } } protected override void OnDisappearing() { MessagingCenter.Unsubscribe<ListViewPage, ContextModel>(this, "GetModel"); base.OnDisappearing(); } }
这里,我们编写页面的点击等交互事件,然后我们采用通讯中心(MessagingCenter)的方式来传递修改和删除的信息给后台的ViewModel.
至此,就完成了整个的简易增删改查的编写.
写在最后
本系列到此,就已经进行了一大半了..后面会继续更新一些安卓库的绑定等内容,敬请期待.