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 条评论
登录 后参与评论

相关文章

来自专栏智能大石头

老瓶装新酒 - C#调用WM手机发送短信(源码)

一些系统,需要能够发送短信,量很小,平均每日10条。 运营商平台太贵,白名单很严格,小额只能发省内; 各短信平台有各种限制,大事件前后会关闭; 飞信以前可以用W...

1775
来自专栏张善友的专栏

Mono P/Invoke :DLLImport

Mono 的初衷是为了吸引更多的Windows .Net程序员来加入Linux平台的开发。但在Linux世界中C语言依然是主流。很多时候一些关键应用(比如大型笛...

19910
来自专栏逸鹏说道

逆天通用水印扩展篇~新增剪贴板系列的功能和手动配置,卸除原基础不常用的功能

常用技能:http://www.cnblogs.com/dunitian/p/4822808.html#skill 逆天博客:http://dnt.dkil.n...

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

WPF一步一脚印系列(1):万事起头难

  一直从事Asp.Net的开发,而C/S的开发方面简直是一片空白,于是从上星期开始就痛下决心开始学习WPF。我采取的策略是网上看基础资料+做简单的demo练习...

1949
来自专栏恰同学骚年

ASP.Net MVC开发基础学习笔记:五、区域、模板页与WebAPI初步

  为了方便大规模网站中的管理大量文件,在ASP.NET MVC 2.0版本中引入了一个新概念—区域(Area)。

772
来自专栏张善友的专栏

使用 Asp.net Future May 2007 开发Silverlight应用

Microsoft ASP.NET Futures May 2007,这是一个Future的好东西,包括了:ASP.NET AJAX Futures,Silve...

18010
来自专栏一只程序汪的自我修养

手把手教你用.NET Core写爬虫

1412
来自专栏ASP.NETCore

细说ASP.NET Core与OWIN的关系

  最近这段时间除了工作,所有的时间都是在移植我以前实现的一个Owin框架,相当移植到到Core的话肯定会有很多坑,这个大家都懂,以后几篇文章可能会围绕这个说下...

652
来自专栏跟着阿笨一起玩NET

WinForm TreeView的一点用法

TreeView一般都包含父节点和子节点,常规情况下有以下几种情况: 1.选中父节点之后,该父节点下面的所有子节点都被选中,取消选择父节点,则该父节点下面所有的...

511
来自专栏JackeyGao的博客

Golang bongo 简单示例

922

扫码关注云+社区