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>





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章