【问题标题】:How to separate View data and ViewModel data?如何分离 View 数据和 ViewModel 数据?
【发布时间】:2015-02-18 13:09:04
【问题描述】:

我需要分别管理 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 的绑定(宽度属性):

DataContext = MyViewModel;

我做错了一切,这不是它的本意?

注意:忘记宽度所需的转换器,只要文本有效并且我不关心这个问题,它就可以工作。

【问题讨论】:

标签: c# wpf mvvm


【解决方案1】:
DataContext = this;

糟糕... :)

让视图模型成为数据上下文,并像这样绑定视图的属性:

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

旁注:

class MyView : Window, INotifyPropertyChanged

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

【讨论】:

  • 我认为我不需要完整的 DP,但简单的 INPC 属性可以解决问题,所以我不想在不需要时用 DP 使视图膨胀。
【解决方案2】:

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

理想的情况是让 WPF 通过将 ViewModel 对象绑定到 ContentPresentersContent 属性并为 ViewModel 类型设置 DataTemplate 条目来推断要使用的 View 类。

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

例如在 App.xaml 或类似文件中

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

...然后在 Window/UserControl/XAML 中任何您需要的地方...

<ContentPresenter Content={Binding MyViewModelAsAProperty}/>

...可以是DependencyProperty 或标准INotifyPropertyChanged 启用的另一个ViewModel 上的属性。

【讨论】:

    【解决方案3】:

    在您的 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>
    

    我希望它的工作..

    【讨论】:

      猜你喜欢
      • 2013-11-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-01-30
      • 2011-08-03
      • 2014-05-06
      • 1970-01-01
      相关资源
      最近更新 更多