5. 模型(Model)

下面先定义模型,尤其是Book类型。这个类型在UI中显示和编辑。为了支持数据绑定,在用户界面中更新的属性值需要实现变更通知。BookId属性只是显示,而不改变,所以变更通知不需要使用这个属性。SetProperty方法由基类BindableBase定义:

    public class Book:BindableBase
    {
        public int BookId { get; set; }
        private string _title;
        public string Title
        {
            get => _title;
            set => SetProperty(ref _title,value);
        }
        private string _publisher;
        public string Publisher
        {
            get => _publisher;
            set => SetProperty(ref _publisher,value);
        }
        public override string ToString() => Title;
    }

1. 实现变更通知

XAML元素的对象源需要依赖属性或INotifyPropertyChanged,数据绑定时,才允许更改通知更新UI。有了模型类型,才能使用INotifyPropertyChanged,为了用于不同的项目,实现代码在Framewrok库项目的BindableBase内完成。INotifyPropertyChanged接口定义了PropertyChanged事件。为了触发更改通知,SetProperty方法实现为一个泛型函数,以支持任何属性类型。在触发通知之前,检查新值是否与当前值不同:

    public class BindableBase : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        protected void OnPropertyChanged(string propertyName)
        {
            PropertyChanged?.Invoke(this,new PropertyChangedEventArgs(propertyName));
        }
        protected bool SetProperty<T>(ref T item,T value,[CallerMemberName]string propertyName = null)
        {
            if (EqualityComparer<T>.Default.Equals(item,value))
            {
                return false;
            }
            item = value;
            OnPropertyChanged(propertyName);
            return true;
        }
    }

2. 使用Repository模式

接下来,需要一种方法来检索、更新和删除Book对象。使用EF Core可以在数据库中读写图书。虽然EF Core可以在通用Windows平台上访问,但通常这是一个后台任务,因此本章未涉及。为了使后端服务可以在客户端应用程序中访问,在服务器端选择Web API技术。在客户端应用程序中,最好能独立于数据存储。为此,定义Repository设计模式。Repository模式是模型和数据访问层之间的中介,它可以作为对象的内存集合。它抽象出了数据访问层,使单元测试方便。

泛型接口IQueryRepository定义的方法通过ID获取一项,或获取一个条目列表:

    public interface IQueryRepository<T,in TKey> where T:class
    {
        Task<T> GetItemAsync(TKey id);
        Task<IEnumerable<T>> GetItemsAsync();
    }

泛型接口IUpdateRepository定义方法来添加、更新和删除条目:

    public interface IUpdateRepository<T,in TKey> where T:class
    {
        Task<T> AddAsync(T item);
        Task<T> UpdateAsync(T item);
        Task<bool> DeleteAsync(TKey id);
    }

IBooksRepository接口为泛型类型T定义Book类型,使前两个泛型接口更具体:

    public interface IBooksRepository:IQueryRepository<Book,int>,
        IUpdateRepository<Book,int>
    {
    }

使用这些接口,可以改变存储库。创建一个示例库SampleBooksRepository,它实现接口IBooksRepository,包含一个图书的初始列表:

    public class BooksSampleRepository : IBooksRepository
    {
        private List<Book> _books;
        public BooksSampleRepository() => InitSampleBooks();
        private void InitSampleBooks()
        {
            _books = new List<Book>
            {
                new Book{ BookId = 1,Title="Professional C# 7 and .NET Core 2",
                    Publisher="Wrox Pres"},
                new Book{BookId = 2,Title="Professional C# 6 and .NET Core 1.0",
                    Publisher="Wrox Pres"},
                new Book{ BookId = 3,Title="Professional C# 5.0 and .NET Core 4.5.1",
                    Publisher="Wrox Pres"},
                new Book{ BookId = 4,Title="Enterprise Services with the .NET Framework",
                    Publisher="AWL"},
            };
        }
        public Task<Book> AddAsync(Book item)
        {
            item.BookId = _books.Select(b => b.BookId).Max() + 1;
            _books.Add(item);
            return Task.FromResult(item);
        }

        public Task<bool> DeleteAsync(int id)
        {
            //var bookToDelete = _books.SingleOrDefault(b => b.BookId == id);
            var bookToDelete = _books.Find(b => b.BookId == id);
            if (bookToDelete != null)
            {
                return Task.FromResult<bool>(_books.Remove(bookToDelete));
            }
            return Task.FromResult<bool>(false);
        }

        public Task<Book> GetItemAsync(int id) =>
            Task.FromResult(_books.Find(b => b.BookId == id));

        public Task<IEnumerable<Book>> GetItemsAsync() =>
            Task.FromResult<IEnumerable<Book>>(_books);

        public Task<Book> UpdateAsync(Book item)
        {
            var bookToUpdate = _books.Find(b => b.BookId == item.BookId);
            int ix = _books.IndexOf(bookToUpdate);
            _books[ix] = item;
            return Task.FromResult(item);
        }
    }

注意:

存储库定义了异步方法,但这里不需要它们,因为书的检索和更新只在内存中进行。方法定义为异步,是因为用于访问ASP.NET Core API的存储库在本质上是异步的。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值