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

相关文章

来自专栏算法+

音频压缩编码 opus 附完整C++代码示例

绝大数人都知道mp3格式编码,以及aac,amr等压缩格式编码。 而在语音通信界有一个强悍的音频格式编码opus. 经过实测,压缩比最高可以达到1:10。 10...

5487
来自专栏生信技能树

你以为的可能不是你以为的

最近生信技能树管理员小朋友XZG跟我炫耀他植物的简化基因组的gvcf模式,两百个测序数据,我一直没用过这个gvcf功能,因为的确没有需求。癌症研究,关注的主要是...

974
来自专栏PPV课数据科学社区

【学习】七天搞定SAS(四):数据输出

弄清楚了基本的PROC之后,开始研究SAS的输出...毕竟有了数据处理的结果之后,还要有一个比较舒服的输出格式才可以嘛。 SAS的结果发送系统:ODS SAS里...

3138
来自专栏james大数据架构

NET实现微信公共平台上传下载多媒体文件

      举个例子,有人对着我们的公共微信号拍个照片发送过来,然后我们处理这个照片,比如进行ocr识别字(随后就会降到这个例子),或者人脸识别,或者拍照取证等...

2707
来自专栏吾真本

Release It! 第2版目录(中英文对照)

注:其中,最后17个小节标题尚未译完,其余译完的标题尚未定稿,会与正式版有出入。仅供参考。

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

ASP.NET MVC5+EF6+EasyUI 后台管理系统(75)-微信公众平台开发-用户管理

前言 本节主要是关注者(即用户)和用户组的管理,微信公众号提供了用户和用户组的管理,我们可以在微信公众号官方里面进行操作,添加备注和标签,以及移动用户组别,同...

3926
来自专栏SAP最佳业务实践

SAP最佳业务实践:MM–组件收费的委外加工(251)-9抵扣的应付帐款

4.11 记录可抵扣的应付帐款 按照委外加工商的类型和冲销方法,基于与收费组件的委外加工商方面的金额,创建可抵扣的应付帐款。 (仅对SAP GUI,需要运行事务...

3776
来自专栏c#开发者

ado.net data services开发框架学习

ado.net data services开发框架学习 什么是ado.net data services Ado.net 数据服务可以很方便的将企业内部数据发...

2606
来自专栏tkokof 的技术,小趣及杂念

浅析OGG VORBIS

虽说OGG VORBIS的登场并未晚过前辈MP3过多时日,其的出现也正是为了阻拦MP3一路高歌猛进的强劲步伐,可是至少在中国这块破解软件的乐土,MP3虚有其表...

812
来自专栏木宛城主

SharePoint 中时间轴 Timeline的实现

客户需要在OA中实现每日动态功能,能够记录每一位员工的每天的工作动态,我很快想到了时间轴,因为时间轴能很直观的现实员工每一刻的动态。就像Facebook的Ti...

1856

扫码关注云+社区