浅谈WPF中的MVVM

来源:互联网 发布:守望先锋手机数据查询 编辑:程序博客网 时间:2024/05/29 18:56

浅谈WPF中的MVVM

一些基础知识

  1. WPF中的一个重要特性就是数据绑定(data binding),简单的说就是你有一些数据要显示给用户,你可以把数据和xaml进行绑定。
  2. WPF由2部分组成:描述GUI布局和效果的xaml文件,和xaml关联的cs文件。
  3. 如果你想最大程度上的复用你的代码,最好的方法就是使用MVVM(Model、View、ViewModel)模式,这样可以保证你的View部分包含的代码最少

一些关键点

  1. 你需要一个集合来保存数据,这个集合是ObservableCollection,而不能用List,Dictionary等。ObservableCollection的特点是在添加项、移除项或刷新整个列表时,此集合将提供通知
  2. 包括Window在内的所有的WPF控件都有一个DataContext
  3. 接口INotifyPropertyChanged是数据变化和GUI之间的桥梁

实例

再多的描述也不如一个实例更能够说明问题

我创建了一个Song类,用于存储一首歌曲中的信息,包括了歌曲名和歌手名

public class Song{    private string _songTitle;    private string _artistName;    public string SongTitle    {        get { return _songTitle; }        set { _songTitle = value; }    }    public string ArtistName    {        get { return _artistName;}        set { _artistName = value; }    }}

设置DataContext方法有两种:
在xaml中:

<Window.DataContext>    <local:SongViewModel /></Window.DataContext>

或者在cs文件中设置DataContext

public partial class MainWindow : Window{    SongViewModel _viewModel = new SongViewModel();    public MainWindow()    {        InitializeComponent();        base.DataContext = _viewModel;    }}

在WPF中,这个Song类就是Model,而GUI则是View,ViewModel把这2层之间的数据进行关联。
然后我们继续创建ViewModel层
这个ViewModel层需要继承INotifyPropertyChanged接口,这样这个类中的某个属性值发生变化,我们会接到通知。

public class SongViewModel : INotifyPropertyChanged{    private Song _song;    public Song Song    {        get { return _song; }        set { _song = value; }    }    public string ArtistName    {        get { return Song.ArtistName; }        set        {            if (Song.ArtistName != value)            {                Song.ArtistName = value;                RaisePropertyChanged("ArtistName");            }        }    }    public string SongTitle    {        get { return Song.SongTitle; }        set        {            if (Song.SongTitle != value)            {                Song.SongTitle = value;                RaisePropertyChanged("SongTitle");            }        }    }    public event PropertyChangedEventHandler PropertyChanged;    private void RaisePropertyChanged(string propertyName)    {        PropertyChangedEventHandler handler = PropertyChanged;        if (handler != null)        {            handler(this, new PropertyChangedEventArgs(propertyName));        }    }}

上面的代码中,首先检查属性的值是否真的发生变化if (Song.SongTitle != value),这样做可以在复杂的项目中,稍微提升一下性能,如果属性发生变化了,会引发PropertyChanged事件。

现在Model,ViewModel都已经完成,只差View了。MainWindow.xaml文件如下

<Window x:Class="WVVM.MainWindow"        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"        xmlns:local="clr-namespace:WVVM"        mc:Ignorable="d"        Title="MainWindow" Height="201.288" Width="380.794">    <Window.DataContext>        <local:SongViewModel></local:SongViewModel>    </Window.DataContext>    <Grid>        <Grid.RowDefinitions>            <RowDefinition Height="Auto"></RowDefinition>            <RowDefinition Height="Auto"></RowDefinition>            <RowDefinition Height="Auto"></RowDefinition>        </Grid.RowDefinitions>        <Grid.ColumnDefinitions>            <ColumnDefinition Width="Auto"></ColumnDefinition>            <ColumnDefinition Width="Auto"></ColumnDefinition>        </Grid.ColumnDefinitions>        <Label Grid.Column="0" Grid.Row="0" Content="SongTitle"></Label>        <Label Grid.Column="0" Grid.Row="1" Content="Artist:"></Label>        <Label Grid.Column="1" Grid.Row="1" Content="{Binding ArtistName}"></Label>        <Label Grid.Column="1" Grid.Row="0" Content="{Binding SongTitle}"></Label>        <Button Grid.Column="0" Grid.Row="2" Name="BtUpdate" Content="Update" Click="BtUpdate_OnClick"></Button>    </Grid></Window>

这里写图片描述
这里写图片描述
xaml文件中,Button按钮有一个click事件,在这个事件中更新了viewMode的属性。

CS文件代码如下

    private SongViewModel _viewModel;    public MainWindow()    {        InitializeComponent();        _viewModel = (SongViewModel) base.DataContext;    }    private void BtUpdate_OnClick(object sender, RoutedEventArgs e)    {        _viewModel.ArtistName = "Adele";        _viewModel.SongTitle = "Hello";    }

像上文那样直接在GUI文件中绑定事件(Button的click事件),存在很多问题,WPF提供了一个更好的方法那就是ICommand。许多控件都有Command属性,它的绑定和Content,ItemSource的绑定方式相同。
继承ICommand需要实现2个方法:bool CanExecute(用于判断是否能够执行)和void Execute(在这里写你需要的代码,如更改SongTitle等)。

我建立了一个RelayCommand类来实现ICommand接口,代码如下

 public class RelayCommand :ICommand    {        private readonly Func<Boolean> _canExecute;        private readonly Action _execute;        public RelayCommand(Action execute) : this(execute,null)        {        }        public RelayCommand(Action execute, Func<Boolean> canExecute)        {            if(execute == null)                throw new ArgumentNullException("execute");            _execute = execute;            _canExecute = canExecute;        }        public event EventHandler CanExecuteChanged        {            add            {                if (_canExecute != null)                    CommandManager.RequerySuggested += value;            }            remove            {                if (_canExecute != null)                    CommandManager.RequerySuggested -= value;            }        }        [DebuggerStepThrough]        public Boolean CanExecute(Object parameter)        {            return _canExecute == null ? true : _canExecute();        }        public void Execute(Object parameter)        {            _execute();        }    }

相应的,在SongViewModel类中,增加如下代码

        void UpdateSongExecute()        {            //在这里执行更新数据的操作            ArtistName = "One Direction";            SongTitle = "Taken";        }        bool CanUpdateSongExecute()        {            //在这里检查是否可以更新数据,我直接返回true了            return true;        }        public ICommand UpdateSong        {            get { return new RelayCommand(UpdateSongExecute,CanUpdateSongExecute);}        }

此时,MainWindow.xaml文件中的Button,就不需要写click事件了,只需绑定Command即可

 <Button Grid.Column="0" Grid.Row="2" Name="BtUpdate" Content="Update" Command="{Binding UpdateSong}"></Button>
0 0
原创粉丝点击