如何分离View数据和ViewModel数据?

时间:2015-02-18 13:09:04

标签: c# wpf mvvm

我需要分别管理UI特定参数(View)和应用程序数据(Model / ViewModel),因此我使用View的代码隐藏作为第一个,以及一个单独的类(前缀为ViewModel)后来。这是我所拥有的简化版本:

查看(XAML)

<Window x:Class="UrSimulator.View.MyView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MyView" Height="300" Width="300">
<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="{Binding FirstColumnWidth}" />
        <ColumnDefinition />
    </Grid.ColumnDefinitions>
    <StackPanel>
        <Label>Width:</Label>
        <TextBox Text="{Binding FirstColumnWidth}" IsReadOnly="True" Background="LightGray" />
    </StackPanel>
    <StackPanel Grid.Column="1">
        <Label>First Column Width:</Label>
        <TextBox Text="{Binding FirstColumnWidth}" />
        <Label>View Model Data:</Label>
        <TextBox Text="{Binding MyViewModel.PropertyFromVM}" />
        <Label Content="{Binding MyViewModel.PropertyFromVM}" />
    </StackPanel>
</Grid>

查看(代码隐藏)

public partial class MyView : Window, INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    private MyViewModel m_MyViewModel;
    public MyViewModel MyViewModel
    {
        get { return m_MyViewModel; }
        set
        {
            m_MyViewModel = value;
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs("MyViewModel"));
        }
    }

    private GridLength m_FirstColumnWidth;
    public GridLength FirstColumnWidth
    {
        get { return m_FirstColumnWidth; }
        set
        {
            m_FirstColumnWidth = value;
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs("FirstColumnWidth"));
        }
    }

    public MyView()
    {
        MyViewModel = new MyViewModel();
        DataContext = this;
        FirstColumnWidth = new GridLength(100);
        InitializeComponent();
    }
}

视图模型

public class MyViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    private string m_PropertyFromVM;
    public string PropertyFromVM
    {
        get { return m_PropertyFromVM; }
        set
        {
            m_PropertyFromVM = value;
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs("PropertyFromVM"));
        }
    }

    public MyViewModel()
    {
        PropertyFromVM = "Some business data";
    }
}

它有效,但我发现在指向VM的每个绑定上使用MyViewModel.都很麻烦。

问题:

有没有其他方法可以在不使用前缀的情况下执行此操作?

如果不使用this作为DataContext,我应该如何编写UI的绑定(width属性),我会使用:

DataContext = MyViewModel;

我做错了什么,这不是它的目的是什么?

注意:忘记Width所需的转换器,只要文本有效就行,并且不是我对问题的关注。

3 个答案:

答案 0 :(得分:3)

DataContext = this;

Yuck ......:)

让视图模型成为数据上下文,并绑定到视图的属性,如下所示:

<Window x:Name="This" ...>
   ...
   <SomeControl SomeProperty="{Binding MyViewProperty, ElementName=This}"/>
   ...
</Window>

旁注:

class MyView : Window, INotifyPropertyChanged

如果继承Window,为什么视图的属性不是“依赖属性”?

答案 1 :(得分:0)

这是做MVVM的一种方式,但不是一个很好的选择,因为你仍在使用紧密耦合的View对象。

理想的情况是,让WPF通过将View个对象绑定到ViewModel的{​​{1}}属性并设置Content来推断要使用的ContentPresenters类。您DataTemplate类型的条目。

这样,您甚至不需要在代码中的任何地方使用ViewModel语句。

e.g。在App.xaml或类似的

DataContext = blah

...然后在Window / UserControl / XAML中,只要你需要它......

<DataTemplate DataType={x:Type MyViewModel}>
  <local:MyViewModelView/>
</DataTemplate>

...可以是另一个<ContentPresenter Content={Binding MyViewModelAsAProperty}/> 上的DependencyProperty或标准INotifyPropertyChanged已启用媒体资源。

答案 2 :(得分:-1)

在MyViewModel类

上添加此代码
private MyView _ObjMyViewModel;
public MyView ObjMyViewModel
{
    get { return _ObjMyViewModel; }
    set
    {
        _ObjMyViewModel= value;
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs("ObjMyViewModel"));
    }
}

在XAML中

<Window.DataContext>
    <ViewModel:MyViewModel/>
</Window.DataContext>
<Grid>
<Grid.ColumnDefinitions>
    <ColumnDefinition Width="{Binding ObjMyViewModel.FirstColumnWidth}" />
    <ColumnDefinition />
</Grid.ColumnDefinitions>
<StackPanel>
    <Label>Width:</Label>
    <TextBox Text="{Binding ObjMyViewModel.FirstColumnWidth}" IsReadOnly="True" Background="LightGray" />
</StackPanel>
<StackPanel Grid.Column="1">
    <Label>First Column Width:</Label>
    <TextBox Text="{Binding ObjMyViewModel.FirstColumnWidth}" />
    <Label>View Model Data:</Label>
    <TextBox Text="{Binding MyViewModel.PropertyFromVM}" />
    <Label Content="{Binding MyViewModel.PropertyFromVM}" />
</StackPanel>

我希望它的工作......