MVVM简单实例到MVVMLight

看了刘铁猛老师的《深入浅出WPF》视频后,对MVVM有了初步了解,但还是一知半解。真的是如刘老师所说,学习MVVM是一个顿悟的过程,就像当初理解面向对象和面向过程一样,书和视频只是一个引导,其中的内涵还需要自己去顿悟。

经过几天的对MVVM的学习,结合着MVVMLight,终于对MVVM有所领悟。这里只是一个视频中的小例子,我用自己的理解把它复制过来,然后用MVVMLight进行实现,加深对MVVM的理解。


无框架MVVM模式下的例子:

未绑定数据的View:

<Window x:Class="Test.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <Button Content="Save" x:Name="Save" />
        <Grid Grid.Row="1">
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="*"/>
            </Grid.RowDefinitions>
            <TextBox x:Name="tb1" Grid.Row="0" Background="LightBlue" FontSize="24" Margin="5"/>
            <TextBox x:Name="tb2" Grid.Row="1" Background="LightBlue" FontSize="24" Margin="5" />
            <TextBox x:Name="tb3" Grid.Row="2" Background="LightBlue" FontSize="24" Margin="5" />
            <Button x:Name="addButton" Grid.Row="3" Content="Add" Width="120" Height="80" />
        </Grid>
    </Grid>
</Window>

ViewModel:

INotifyProPertyChange接口:

INotifyPropertyChange:通知界面某一属性值发生了改变,类型为interface,如果不使用框架,则需要自己手动去实现该接口,MVVMLight已经封装了一个现成的类ObservableObject,可以直接调用,很方便。如果是初学MVVM还是自己手动去实现这个接口,否则用着MVVMLight也会是一头雾水。
 //INotifyPropertyChanged 向客户端发出某一属性值已更改的通知。
    class NotificationObject : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;


        public void RaisePropertyChange(string PropertyName)
        {
            if (this.PropertyChanged != null)
            {
              /* Invoke或者BeginInvoke方法都需要一个委托对象作为参数。
                委托类似于回调函数的地址,因此调用者通过这两个方法就可以把需要调用的函
                数地址封送给界面线程。这些方法里面如果包含了更改控件状态的代码,
                那么由于最终执行这个方法的是界面线程,
                从而避免了竞争条件,避免了不可预料的问题。
                如果其它线程直接操作界面线程所属的控件,
                那么将会产生竞争条件,造成不可预料的结果。 */
                this.PropertyChanged.Invoke(this, new PropertyChangedEventArgs(PropertyName));
            }
        }
    }

ICommand接口:

viewmodel中实现,在view中进行调用。

该接口包括2个方法和一个事件。CanExecute方法返回命令的状态——指示命令是否可执行,例如,文本框中没有选择任何文本,此时Copy命令是不用的,CanExecute则返回为false。Execute方法就是命令执行的方法,即处理程序。当命令状态改变时,会触发CanExecuteChanged事件。

同INotifyProPertyChange一样为interface类型,如果不使用用框架,需要手动去实现。MVVMLight已经实现该接口:RelayCommand

 class DelegateCommand : ICommand
    {
        public bool CanExecute(object parameter)
        {
            //如果忽略了检查 CanExecute ,则永远都可以执行
            if (this.CanExecuteFunc == null)
            {
                return true;
            }
            this.CanExecuteFunc(parameter);
            return true;
        }
        public event EventHandler CanExecuteChanged;
        public void Execute(object parameter)
        {
            if (this.ExecuteAction == null)
            {
                return;
            }
            this.ExecuteAction(parameter);
        }
        //参数为object 无返回值
        public Action<object> ExecuteAction { get; set; }
        //参数为object 返回值为bool
        public Func<object, bool> CanExecuteFunc { get; set; }
    }

MainViewModel:

view调用的ViewModel,不要被名字Main迷惑,这个demo只有一个界面就是程序主界面(Mainwindow),如果有多个界面,view和viewmodel前缀相同,文件结构更加清晰。
该类继承了上面实现的Notification类,里面包含了数据Input1, Input2, Result,命令AddCommand,SaveCommand
    class MainWindowViewmode : NotificationObject
    {
        public double input1;
        public double Input1 
        { 
            get {return input1;}
            set 
            {
                input1 = value;
		//此处调用的是NotificationObject的RaiseProperty
                this.RaisePropertyChange("Input1");
            }
        }

        public double input2;
        public double Input2
        {
            get { return input2; }
            set
            {
                input2 = value;
                this.RaisePropertyChange("Input2");
            }
        }


        public double result;
        public double Result 
        {
            get { return result; }
            set
            {
                result = value;
                this.RaisePropertyChange("Result");
            }
        }

        public DelegateCommand AddCommand { get; set; }
        public DelegateCommand SaveCommand { get; set; }
        private void Add(object parameter)
        {
            this.Result = this.Input1 + this.Input2;
        }

        private void Save(object parameter)
        {
            SaveFileDialog dlg = new SaveFileDialog();
            dlg.ShowDialog();
        }

        public MainWindowViewmode()
        {
            this.AddCommand = new DelegateCommand();
this.AddCommand.ExecuteAction = new Action<object>(this.Add); this.SaveCommand = new DelegateCommand(); this.SaveCommand.ExecuteAction = new Action<object>(this.Save); } }

绑定数据和命令的view:

<Window x:Class="Test.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <Button Content="Save" x:Name="Save" Command="{Binding SaveCommand}"/>
        <Grid Grid.Row="1">
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="*"/>
            </Grid.RowDefinitions>
            <TextBox x:Name="tb1" Grid.Row="0" Background="LightBlue" FontSize="24" Margin="5" Text="{Binding Input1}"/>
            <TextBox x:Name="tb2" Grid.Row="1" Background="LightBlue" FontSize="24" Margin="5" Text="{Binding Input2}"/>
            <TextBox x:Name="tb3" Grid.Row="2" Background="LightBlue" FontSize="24" Margin="5" Text="{Binding Result}"/>
            <Button x:Name="addButton" Grid.Row="3" Content="Add" Width="120" Height="80" Command="{Binding AddCommand}"/>
        </Grid>
    </Grid>
</Window>





展开阅读全文

没有更多推荐了,返回首页