C#使用Xamarin开发可移植移动应用进阶篇(10.综合演练,来一份增删改查CRUD)

前言

源码地址:https://github.com/l2999019/DemoApp

可以Star一下,随意 - -

说点什么..

呃 也有半个月没更新了. 本来这篇的Demo早就写完了,文章也构思好了.迟迟没发布..是因为实在太忙..

项目要上线..各种  你们懂的..

正赶上自己十一人生大事..结婚..所以..忙的那叫一个脚不沾地啊.

今天的学习内容?

使用我们前面所学的技术,写一个增删改查.

效果如下:

正文

废话不多说,直接开始吧.

1.采用了的技术

   列表ListView,采用继承重写的方式,实现简易的下拉刷新

   采用HttpClient的方式访问后端的WebAPI.

   使用了一系列的Xamarin提供的插件.

   采用了MVVM的方式,来编写我们的业务代码.

2.WebAPI

   前面我们说过,我们访问的是后端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;

            }
        }
    }

3.编写服务仓储

就是编写一个访问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;
        }

    }

4.编写ViewModel来与界面进行绑定交互

详解请查看系列目录中的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

5.编写界面,绑定数据

我们创建一个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.

至此,就完成了整个的简易增删改查的编写.

写在最后

本系列到此,就已经进行了一大半了..后面会继续更新一些安卓库的绑定等内容,敬请期待.

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏草根专栏

用VSCode开发一个asp.net core2.0+angular5项目(5): Angular5+asp.net core 2.0 web api文件上传

这部分就讲从angular5的客户端上传图片到asp.net core 2.0的 web api. 这是需要的源码: https://pan.baidu.com...

3755
来自专栏ASP.NET MVC5 后台权限管理系统

构建ASP.NET MVC4+EF5+EasyUI+Unity2.x注入的后台管理系统(13)-系统日志和异常的处理③

上一节我们讲了如何捕获异常和记录日志,这一节我们讲,没有捕获的或者忘记捕获的异常包括404错误等,我们统一处理这个异常。 这一讲是利用 Application_...

2728
来自专栏菩提树下的杨过

msmq发送速度的测试

在一些并发量比较高的"中小型"应用中,如果短期内有大量的数据插入,利用msmq中转是一个不错的选择(petshop就是这么干的),想知道msmq一秒钟内到底能...

2069
来自专栏飞扬的花生

Html5上传插件封装

      前段时间将flash的上传控件替换成使用纯js实现的,在此记录 1.创建标签 <div class="camera-area" style="dis...

2458
来自专栏魏琼东

本人为巨杉数据库(开源NoSQL)写的C#驱动,支持Linq,全部开源,已提交github

     这些年在做AgileEAS.NET SOA 中间件平台的推广、技术咨询服务过程之中,特别是针对我们最熟悉的医疗行业应用之中,针对大数据分析,大并发性能...

760
来自专栏偏前端工程师的驿站

GridView实战一:自定义分页、排序、修改、插入、删除

前言:   在某次公司面试时被问到对GridView操作的熟悉程度,在那之前一直用Repeater内嵌table标签对GridView操作确实很少,于是最近在项...

31810
来自专栏听雨堂

ASP.NET TreeView相关问题

1、用代码在treeview web控件中,添加node的方法 表字段:编号,父编号,名称 数据: 1 0 中华人民共和国 2 1 湖南 3 1 湖北...

1867
来自专栏飞扬的花生

将Json数据保存在静态脚本文件中读取

      一些常用的数据例如一些网站的区域信息被改变的可能性不大,一般不通过请求获取,于是我们选择存在静态文件中,例如以下Demo: 1.动态加载Json数据...

2226
来自专栏林德熙的博客

win10 uwp 读取保存WriteableBitmap 、BitmapImage 保存 WriteableBitmap 到文件从文件读 WriteableBitmapIma

我们在UWP,经常使用的图片,数据结构就是 BitmapImage 和 WriteableBitmap。关于 BitmapImage 和 WriteableBi...

921
来自专栏我和未来有约会

CaseStudy(showcase)数据篇-从XML中获取数据

做silvelight也有一段时间了,相册、游戏,刚刚完成的showcase这个小程序算是一个阶段了。这里就以showcase这个项目来做一下CaseStudy...

1898

扫码关注云+社区