• MVVM之ViewModel


    一、观察者模式(一对多的对象归属,当一个对象发生了改变,它的所属对象自动通知和改变)

        System.ComponentModel.INotifyPropertyChanged,该接口是观察者模式的部分,当属性的值发生改变后去通知订阅者(使用者).

        该接口仅包含一个事件event PropertyChangedEventHandler PropertyChanged,当类继承了该接口,并实现该事件即可完成通知,如下:

       public class Product : INotifyPropertyChanged
    {
    private string price;

    public string Price
    {
    get { return price; }
    set
    {
    price = value;
    OnPropertyChanged("Price");
    }
    }


    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged(string propertyName)
    {
    If(PropertyChanged != null)
    {
    PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
    }
    }


    可以看到在属性的Set中调用OnPropertyChanged方法,然后触发PropertyChanged事件通知。

    Systems.Collections.Specialized.INotifyCollectionChanged,和INotifyPropertyChanged类似,不过他是针对集合而不是一个对象,包含事件:

    event NotifyCollectionChangedEventHandler CollectionChanged,接收一个委托事件

    public delegate void NotifyCollectionChangedEventHandler(
    Object sender,
    NotifyCollectionChangedEventArgs e
    )

    事件参数NotifyCollectionChangedEventArgs的Action是一个类型为NotifyCollectionChangedAction的枚举类型,值包括如下:

    值      含义
    Add   当一个新项添加到集合
    Remove 当一个项从集合移除
    Replace 当一个项被另一个对象替换
    Move    当一个项在集合中移动(WPF支持,Silverlight不支持)
    Reset   当集合内容发生显著改变


      System.Collections.ObjectModel.ObservableCollection<T>,表示一个动态数据集合,在添加项、移除项或刷新整个列表时,此集合将提供通知.

      ReadOnlyObservableCollection<T>,表示一个只读的集合。

      CollectionViewSource为CollectionView 的XAML代理,表示用于分组、排序、筛选和导航数据集合的视图。

      Grouping(分组):
      通过CollectionViewSource的GroupDescriptions属性添加PropertyGroupDescription对象(参数为分组的依据)

    CollectionViewSource appointmentsByDate = new CollectionViewSource();
    appointmentsByDate.Source = appointments;
    appointmentsByDate.GroupDescriptions.Add(new
    PropertyGroupDescription("Date"));

      Sorting(排序):
      通过CollectionViewSource的SortDescriptions属性添加SortDescription对象(参数为排序依据和排序方向)

    CollectionViewSource appointmentsByDate = new CollectionViewSource();
    appointmentsByDate.Source = appointments;
    appointmentsByDate.SortDescriptions.Add(new SortDescription("Location",
    ListSortDirection.Ascending));
    appointmentsByDate.SortDescriptions.Add(new
    SortDescription("AttendeeSurname", ListSortDirection.Descending));

    Filtering(过滤):

    Filter属性是一个FilterEventHandler事件

        CollectionViewSource souece = new CollectionViewSource();
    souece.Filter += new FilterEventHandler(souece_Filter);

    e.Item每次为一个对象,Appointment为实体类型,然后通过e.Accepted(为true保留)来决定是否过滤掉

    private void AppointmentsWithinTheNextMonth(object sender, FilterEventArgs e)
    {
    Appointment appointment = e.Item as Appointment;
    if(appointment)
    {
    e.Accepted = DateTime.Now.AddMonths(1) > appointment.Date;
    }
    }


    二、Thread处理

    看个例子:

    IPAddress ipAddress = IPAddress.Parse("127.0.0.1");
    int portNumber = 1500;
    TcpListener server = new TcpListener(ipAddress, portNumber);
    try
    {
    server.Start();
    // This call blocks until a client is received
    TcpClient client = server.AcceptTcpClient();
    Console.WriteLine("Client connected!");
    client.Close();
    }
    catch(SocketException ex)
    {
    Console.WriteLine("Socket Exception caught: {0}", ex);
    }
    finally
    {
    server.Stop();
    }
    Console.ReadKey();

    上述代码去监听1500端口,通过AcceptTcpClient得到返回的结果,但是,如果这句代码不执行完毕,以下的过程是不会进行的,就容易造成线程锁死,面对这样的线程问题,可以使用异步来完成,当调用完方法之后立马返回,优化后如下:

    static void Main(string[] args)
    {
    IPAddress ipAddress = IPAddress.Parse("127.0.0.1");
    int portNumber = 1500;
    TcpListener server = new TcpListener(ipAddress, portNumber);
    try
    {
    server.Start();
    // This call returns immediately, but there is no guarantee when a client
    connects
    server.BeginAcceptTcpClient(new AsyncCallback(ClientConnected), server);
    }
    catch(SocketException ex)
    {
    Console.WriteLine("Socket Exception caught: {0}", ex);
    server.Stop();
    }
    Console.ReadKey();
    }
    private static void ClientConnected(IAsyncResult asyncResult)
    {
    TcpListener server = asyncResult.AsyncState as TcpListener;
    TcpClient client = server.EndAcceptTcpClient(asyncResult);
    Console.WriteLine("Client connected!");
    server.Stop();
    }


    两者的区别在于

    server.AcceptTcpClient()换成了
    server.BeginAcceptTcpClient(new AsyncCallback(ClientConnected), server)
    你猜的没错,前者的操作是同步的,后者的操作是异步的,同时给你起绑定了回调函数,在执行完毕后自动调用,也不会造成代码堵塞。
    
    
    
    
    再看下面的例子:
    public class ViewModel
    {
    public ViewModel()
    {
    Messages = new ObservableCollection<string>();
    _timer = new Timer(5000D);
    _timer.Elapsed += new ElapsedEventHandler(TimerElapsed);
    _timer.Enabled = true;
    _timer.Start();
    }
    public ObservableCollection<string> Messages
    {
    get;
    private set;
    }
    void TimerElapsed(object sender, ElapsedEventArgs e)
    {
    Messages.Add("Timer fired!");
    }
    private Timer _timer;
    }
    
    
    在该类中,使用Timer来执行操作,我们把集合绑定到ListView(ListBox)上去,当Message属性改变后可以通知UI来更新,可是运行后会得到错误,NotSupportedException,因为跨线程了。
    
    
    在Silverlight或者WPF中通过非UI线程来更新UI元素使用Dispather.Invoke(Delegate,object())或者Dispather.BeginInvoke(Delegate,object())来实现UI的更新,如下:
    void TimerElapsed(object sender, ElapsedEventArgs e)
    {
    _uiDispatcher.Invoke(
    (
    Action)delegate
    {
    Messages.Add("Timer fired!");
    }
    );
    }

    但是上述方法的后果是需要给ViewModel传递UI的Dispather过去,然后才能使用。
    
    
    除了这个方法,还可以使用接口来实现:
    public ViewModel(IView view)
    {
    _view = view;
    }
    void TimerElapsed(object sender, ElapsedEventArgs e)
    {
    _view.AddMessage("Timer fired!");
    }
    IView为接口,包含方法AddMessage,修改ViewModel的构造函数传递Iview对象,同时让我们的Ui窗口实现于该接口,实现AddMessage方法,然后就可以正常工作。
    public partial class MainWindow : Window, IView
    {
    public MainWindow()
    {
    InitializeComponent();
    }
    public void AddMessage(string message)
    {
    ViewModel viewModel = DataContext as ViewModel;
    Dispatcher.Invoke(
    (Action)delegate
    {
    viewModel.Messages.Add(message);
    }
    );
    }
    }




    以上只是一些对ViewModel处理上的部分见解。
        

  • 相关阅读:
    Java读取Excel文件(包括xls和xlsx)的样例程序
    Node.js中使用pipe拷贝大文件不能完全拷贝的解决办法
    Spring Boot中一个Servlet主动断开连接的方法
    算法学习笔记1.3.3 质因数分解
    算法学习笔记1.3.2 素数判定
    算法学习笔记1.3.1 素数筛法
    算法学习笔记1.2.2 扩展欧几里得
    算法学习笔记1.2.1 欧几里得算法
    算法学习笔记1.1.3 矩阵的逆
    Windows下Tesseract-OCR的安装
  • 原文地址:https://www.cnblogs.com/ListenFly/p/2387250.html
Copyright © 2020-2023  润新知