随笔 - 55  文章 - 15  trackbacks - 0
<2012年10月>
30123456
78910111213
14151617181920
21222324252627
28293031123
45678910

常用链接

留言簿

随笔分类

随笔档案

搜索

  •  

最新评论

阅读排行榜

评论排行榜

MVVM--Model  View  ModelView 设计模式,目的是为了将表现与逻辑分离,使开发者更容易开发大型程序。
一般情况下就是Xaml负责View,描述控件、用户输入、结果输出等,C++文件负责ModelView,负责逻辑。Model是数据和原始内容,一般可省略。
调用关系是Model->View->ModelView,但是可以用event来反向调用。
正向:
Model(文件中或者网站的)数据传给View,View接收数据,传递给ViewModel后台逻辑。
反向:
后台逻辑进行处理,产生一个事件,View通过处理器处理,并显示ModelView更新的数据,View再发生一个事件,被Model接收,Model将最后的数据写入文件或者网络。
MVVM的核心目的就是要降低代码量。

MVVM用于数据绑定
1 数据绑定通知
<TextBlock Text = "{Binding ElementName = slider, Path=Value}"/>
这是两个FrameworkElement派生对象之间的数据绑定,其中源是:Slider对象的Value属性,目标是:TextBlock的Text属性。两个属性都是DependencyProperty(依赖属性),对于数据绑定来说,目标对象的属性必须为依赖属性,源对象的属性可以不是。
上面的程序片段的意思是,当Slider的Value发生变化时,变化的结果实时显示在TextBlock的Text属性里。这个过程是怎么实现的呢?(这里源和目标都是依赖属性,所以后面的过程是自动发生的,相当于编译器自动添加了一段代码,帮助我们做数据绑定)通过事件,Binding是一个对象,当Value属性变化时,它提供了一个处理器来响应Value变化的事件,并将结果放入Text中。当然这些都是WinRT帮我们做了,并且这种绑定感觉只是在View层操作。
当我们要在ViewModel层做数据绑定的时候,跟上面有点不一样。我们的绑定目标依然放在Xaml文件中,而源(source)则放在ViewModel类中。这种方法是View(Xaml)和ViewModel(C++/Cx class)交互的基本模式。

绑定源不必是依赖属性,但是得有一套机制来通知Binding对象,该属性被改变了。如果不是依赖属性的话,这种通知不像上面的代码那样自动发生,必须通过event来实现。

下面是几种实现的方法:
1. 标准方法通过INotifyPropertyChanged接口,该接口非常简单,只有一个event
     public interface class INotifyPropertyChanged{
         event PropertyChangedEventHandler PropertyChanged;//更改属性时fire这个event
     }

     event PropertyChangedEventHandler^ PropertyChanged {
                  void add (PropertyChangedEventHandler^ value);
                  void remove (PropertyChangedEventHandler^ value);
               }

     下面是摘抄的MSDN上的:
     INotifyPropertyChanged 接口用于向客户端(通常是执行绑定的客户端)发出某一属性值已更改的通知。

例如,考虑一个带有名为 FirstName 属性的 Person 对象。 若要提供一般性属性更改通知,则 Person 类型实现 INotifyPropertyChanged 接口并在 FirstName 更改时引发 PropertyChanged 事件。

若要在将客户端与数据源进行绑定时发出更改通知,则绑定类型应具有下列任一功能:

  • 实现 INotifyPropertyChanged 接口(首选)。

  • 为绑定类型的每个属性提供更改事件。

 不能同时执行这两个方法。
摘抄一段程序以便理解:C++代码

 1 [Windows::UI::Xaml::Data::Bindable]
 2    public ref class RgbViewModel sealed : Windows::UI::Xaml::Data::INotifyPropertyChanged
 3    {
 4    private:
 5        double red, green, blue;
 6    public:
 7        virtual event Windows::UI::Xaml::Data::PropertyChangedEventHandler^ PropertyChanged;
 8
 9        property double Red
10        {
11            double get();
12            void set(double value);
13        }

14//
15     protected:
16        void OnPropertyChanged(Platform::String^ propertyName);
17}
;

定义了一个属性Red,当Red改变时,调用OnPropertyChanged(..)方法,该方法调用PropertyChanged()event

void RgbViewModel::Red::set(double value)
{
    
if (red != value)
    
{
        red 
= value;
        OnPropertyChanged(
"Red");
        Calculate();
    }

}


void RgbViewModel::OnPropertyChanged(String^ propertyName)
{
    PropertyChanged(
thisref new PropertyChangedEventArgs(propertyName));
}


到此为止,我了解到的逻辑是这样的:一个类的属性想要作为源数据,必须要实现INotifyPropertyChenged接口,该接口中有一个event,当相应的属性改变时,激发这个event,这时,通知Binding这个对象,将改变了的值放入目标属性中去。所以下一步,就是将源和对象属性用Binding对象联系起来。这一过程是在View中做的,即在Xaml文件中。

<Page.Resources>
        
<local:RgbViewModel x:Key="rgbViewModel" /> //初始化rgbViewModel。将ViewModel作为资源是一种Xaml访问该对象的方法。还有另外一种方法
</Page.Resources>

     
<Slider Grid.Column="0"
                Grid.Row
="1"
                Value
="{Binding Source={StaticResource rgbViewModel}, 
                                Path=Red, 
                                Mode=TwoWay}"

                ThumbToolTipValueConverter
="{StaticResource hexConverter}"
                Orientation
="Vertical"
                Foreground
="Red" />

        
<TextBlock Text="{Binding Source={StaticResource rgbViewModel}, 
                                  Path=Red, 
                                  Converter={StaticResource hexConverter}}"

                   Grid.Column
="0"
                   Grid.Row
="2"
                   Foreground
="Red" />



另外,在做练习的时候发现,在声明一个新类做绑定源的时候,必须加上:[Windows::UI::Xaml::Data::Bindable]这句话,不然不能实现绑定。

2. 书中的另一个方法是用一个BindableBase类来实现,这个类也是继承了INotifyPropertyChanged接口。如果我们从这个类继承,那就省去了OnPropertyChanged()这一步,因为基类已经为我们实现了。但是,在c++中我没有查到这个类,而且书中的程序也是直接继承接口来做,跟第一种方法相同。

3. DataContext属性
目前为止,我们看到了三种方法:
     1). Source and Target are both dependency property, just use <TextBlock Text = "{Binding ElementName = slider, Path=Value}"/> to do binding.
     2). Source property is not denpendency property. Implement a class derived from INotifyPropertyChanged, and add a event which is when property chenged fired. Like : Value="{Binding Source={StaticResource rgbViewModel}, 
                                Path=Red, 
                                Mode=TwoWay}"


     3).Source property is not denpendency property. Implement a class derived from BindableBase class.
第四种方法:指定一个绑定源,如果ElementName, Source, RelativeSource都为NULL的话,那么Binding(它是个对象)将检查绑定目标的DataContext属性。DataContext是FrameworkElement定义的属性,它可以从Visual Tree从上到下传播,不是所有的属性都可以这么做。Foreground,和所有的Font-related属性可以。

在代码中,你可以在构造函数中实例化一个DataContext of Page

先说下我的理解,DataContext翻译过来就是数据上下文,就是说,一些东西包含在这个上下文中,你不需要明确地指出来。像之前的第二种方法,利用INotifyPropertyChanged接口来做的,在Xaml文件中,你要绑定一个东西,要写长长的一段话,如果你明确地表示你要绑定的东西在上下文中,那么你可以省略很多东西。确实也是这样的。
你可以用两种方法设置DataContext
      第一种方法:在code中写,注意这个属性是Page的:
                        第一步,在构造函数中: RgbViewModel^ viewModel = ref new RgbViewModel();
                                                          this->DataContext = viewModel;
                        第二步,在Xaml文件中:
                                                        <Slider Grid.Column="0"
                                                          Grid.Row="1"
                                                          Value="{Binding Red, Mode=TwoWay}"
                        就结束了。
     第二种方法:全部在Xaml文件中做:
                       第一步, 在page.Resources中:
                                                     <Page.Resources>
                                                          <local:rgbColor x:Key="RgbColor"/>
                                                      </Page.Resources>
                       第二步,在Grid中:
                                                     <Grid  DataContext="{StaticResource RgbViewModel}"> or
                                                     <Grid DataContext="{ Binding Source={StaticResource RgbViewModel} }".../>
                       第三步,同第一种方法第二步。


总结:MVVM的目的是为了把表现与逻辑分开来,相互之间不要有太大的影响,让程序员能够专心地做某一块。但有些时候必须要有联系,外部传入数据,控件接收数据,并传入后台处理,后台处理后的数据又要显示在控件上,这就需要数据绑定。数据绑定的方法已经说了几遍了,有3种方法,一种是源和目标都是依赖属性的时候,直接在Xaml文件中binding就行了,方法也比较简单;第二种和第三种方法针对的都是源不是依赖属性的时候,但目标必须是依赖属性,这时第二种方法要使用INotifyPropertyChanged接口,当属性改变的时候,一个Event被激活,并且提醒Binding对象将新值写入目标数据;第三种方法是设置DataContext,这种方法最简单,只需要在Xaml文件中设置一下就好。
附一个OnSizeChanged方法,以

void SliderViewModel::MainPage::OnSizeChanged(Platform::Object^ sender, Windows::UI::Xaml::SizeChangedEventArgs^ e)
{
    
if(e->NewSize.Width < e->NewSize.Height)
    
{
        forChangeRow
->Height = GridLength(1,GridUnitType::Star);
        forChangeColumn
->Width = GridLength(0);
        

        Grid::SetColumn(resultRect, 
0);
        Grid::SetRow(resultRect,
3);
        Grid::SetColumnSpan(resultRect,
3);
    }

    
else
    
{
        forChangeRow
->Height = GridLength(0);
        forChangeColumn
->Width = GridLength(3, GridUnitType::Star);
        Grid::SetColumn(resultRect, 
3);
        Grid::SetRow(resultRect,
0);
        Grid::SetRowSpan(resultRect,
3);
    }

}

后用




posted on 2012-06-26 17:24 Dino-Tech 阅读(1389) 评论(0)  编辑 收藏 引用

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理