初识MVVM(一)

说明:关于什么是MVVM,园子中已经有很多文章做过介绍,自己对MVVM也有了初步的认识,算是一知半解吧。概念看起来总是有那么点抽象,简单的办法就是通过动手实践来进一步理解。

从网上弄了几个案例,相信有人看过,在此只为了自己加深对MVVM的认识。

1.目录结构,MVVM的目录结构大致如下:

2.类图及实现过程

简单的实现过程大致如下,首先就是手动实现两个接口:INotifyPropertyChanged,ICommand.

2.1 INotifyPropertyChanged 接口的实现

 1 //1.继承INotifyPropertyChanged,要引用该命名空间
 2 using System.ComponentModel;
 3 
 4 namespace MVVMDemo.ViewModels
 5 {
 6     class NotificationObject:INotifyPropertyChanged
 7     {
 8         //(intface INotifyPropertyChanged,向客户端发出某些属性已更改的通知)
 9         //2.实现接口INotifyPropertyChanged
10 
11         public event PropertyChangedEventHandler PropertyChanged;
12 
13         public void RaisePropertyChanged(string propertyName)
14         {
15             if (this.PropertyChanged!=null)
16             {
17                 this.PropertyChanged.Invoke(this,new PropertyChangedEventArgs(propertyName));
18             }
19         }
20     }
21 }


2.2 实现ICommand接口

 1   class DelegateCommand:ICommand
 2     {
 3         //ICommand 两个方法 CanExecute 和Execute,一个事件CanExecuteChanged
 4 
 5         public bool CanExecute(object parameter)
 6         {
 7             //throw new NotImplementedException();
 8             if (this.CanExecuteFunc==null)
 9             {
10                 return true;
11             }
12           return   this.CanExecuteFunc(parameter);
13         }
14 
15         public event EventHandler CanExecuteChanged;
16 
17         //Execute
18         public void Execute(object parameter)
19         {
20            // throw new NotImplementedException();
21             if (this.ExecuteAction==null)
22             {
23                 return;
24             }
25             this.ExecuteAction(parameter);
26         }
27 
28         public Action<object> ExecuteAction { get; set; }
29         public Func<object, bool> CanExecuteFunc { get; set; }
30     }


2.3 ViewModel的实现

ViewModel中主要实现业务逻辑。本例要实现两数的加法运算:

在这个步骤中首先要完成数据属性的定义,例如:

        private double input1;

        public double Input1
        {
            get { return input1; }
            set
            {
                input1 = value;
                this.RaisePropertyChanged("Input1");
            }
        }


如果数据属性的数量比较多,那么输入总是要花费较多的时间,这里有个小技巧,就是使用快捷的输入方法,但是VS自身提供的代码段是有限的,幸运的是我们可以通过:工具>

代码段管理器>添加来添加自定义的代码段。

具体的方法是在安装路径下找到系统内置的代码段来修改,自定义自己需要的代码段。

 1 <CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
 2     <CodeSnippet Format="1.0.0">
 3         <Header>
 4             <Title>propfull</Title>
 5             <Shortcut>propfull</Shortcut>
 6             <Description>属性和支持字段的代码段</Description>
 7             <Author>Microsoft Corporation</Author>
 8             <SnippetTypes>
 9                 <SnippetType>Expansion</SnippetType>
10             </SnippetTypes>
11         </Header>
12         <Snippet>
13             <Declarations>
14                 <Literal>
15                     <ID>type</ID>
16                     <ToolTip>属性类型</ToolTip>
17                     <Default>int</Default>
18                 </Literal>
19                 <Literal>
20                     <ID>property</ID>
21                     <ToolTip>属性名</ToolTip>
22                     <Default>MyProperty</Default>
23                 </Literal>
24                 <Literal>
25                     <ID>field</ID>
26                     <ToolTip>支持此属性的变量</ToolTip>
27                     <Default>myVar</Default>
28                 </Literal>
29             </Declarations>
30             <Code Language="csharp">
31                 <![CDATA[private $type$ $field$;
32 
33     public $type$ $property$
34     {
35         get { return $field$;}
36         set { $field$ = value;}
37     }
38     $end$]]>
39             </Code>
40         </Snippet>
41     </CodeSnippet>
42 </CodeSnippets>

主要修改Title,Shortcut和Code节点中的内容。例如:将上面的Code节点的内容改为如下

            <Code Language="csharp">
            <![CDATA[private $type$ $field$;

    public $type$ $property$
    {
        get { return $field$;}
        set 
        { 
            $field$ = value;
            this.RaisePropertyChanged("$property$");
        }
    }
    $end$]]>
            </Code>

通过输入ShortCut节点中的名称,双击Tab键就可以快速输入代码。

2)命令属性的实现

    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();
           
        }

 

3)在构造函数中实例化委托

1  //构造函数
2         public MainWindowViewModel()
3         {
4             this.AddCommand = new DelegateCommand();
5             this.AddCommand.ExecuteAction = new Action<object>(this.Add);
6 
7             this.SaveCommand = new DelegateCommand();
8             this.SaveCommand.ExecuteAction = new Action<object>(this.Save);
9         }


2.4绑定View

 

1  <Button Content="Save" Height="38" HorizontalAlignment="Left" Margin="163,20,0,0" x:Name="btnSave" VerticalAlignment="Top" Width="110" Command="{Binding SaveCommand}" />
2         <TextBox Background="{StaticResource {x:Static SystemColors.HighlightBrushKey}}" Grid.Row="1" Margin="6" Text="{Binding Input1}" />
3         <TextBox Background="{StaticResource {x:Static SystemColors.HighlightBrushKey}}" Grid.Row="2" Margin="6" Text="{Binding Input2}" />
4         <TextBox Background="{StaticResource {x:Static SystemColors.HighlightBrushKey}}" Grid.Row="3" Margin="6" Text="{Binding Result}" />
5         <Button Content="Add" Height="38" HorizontalAlignment="Left" Margin="163,21,0,0" x:Name="btnAdd" VerticalAlignment="Top" Width="108" Grid.Row="4" Command="{Binding AddCommand}" />

在后台代码中,只需做类似如下的操作:

 

1 public partial class MainWindow : Window
2     {
3         public MainWindow()
4         {
5             InitializeComponent();
6 
7             this.DataContext = new MainWindowViewModel();
8         }
9     }

即使我们将TextBox控件改为使用Slider,我们只需重新对Slider的进行重新绑定。如下:

 

 

 

 <Slider x:Name="slider1" Grid.Row="0" Background="LightBlue" Minimum="-100" Maximum="100" Margin="4"
                    Value="{Binding Input1}" />
                <Slider x:Name="slider2" Grid.Row="1" Background="LightBlue" Minimum="-100" Maximum="100" Margin="4"
                    Value="{Binding Input2}" />
                <Slider x:Name="slider3" Grid.Row="2" Background="LightBlue" Minimum="-100" Maximum="100" Margin="4"
                    Value="{Binding Result}" />
                <Button x:Name="addButton" Grid.Row="3" Content="Add" Width="120" Height="80" Command="{Binding AddCommand}"/>


说明:其实,没有必要自己手动实现两个接口,Prism为你完成了这两件事,你需要做的就是添加引用集并引用相应的命名空间。

 

posted @ 2012-04-09 17:23  January  阅读(1362)  评论(0编辑  收藏  举报