【问题标题】:WPF/MVVM : How to bind model to view/viewmodel from ItemsControlWPF/MVVM:如何从 ItemsControl 将模型绑定到视图/视图模型
【发布时间】:2016-05-26 09:48:53
【问题描述】:

我有一个 ItemsControl 绑定到 Tasks 列表。我想将该模型Task 赋予它的视图TaskView 和视图模型TaskViewModel

我曾尝试像这样在视图属性上绑定值:

<views:TaskView Model="{Binding}" />

然后绑定视图和视图模型之间的值:

public partial class TaskView
{
    public TaskView()
    {
        InitializeComponent();

        // Attempt to bind view.IdProperty with viewmodel.Id
        var binding = new Binding("Id");
        SetBinding(IdProperty, binding);
    }

    public Task Model
    {
        get { return GetValue(ModelProperty) as Task; }
        set { SetValue(ModelProperty, value); }
    }
    public static readonly DependencyProperty ModelProperty =
      DependencyProperty.Register("Model", typeof(Task), typeof(TaskView));
}

但是它不起作用。由于我是 C#/.NET 的新手,我不知道我的方向是否正确,因为 IMO 的常见问题似乎很复杂。

请注意,它会正确呈现任务列表,因此 ItemsControl 可以按预期工作。

问题:

  1. 如何从数据源构建视图并将模型传递给该视图? (上面解释的问题)
  2. 如何从该模型读取值到视图? (参见 TaskView.xaml)
  3. 有没有更惯用的方法?

以下是关键部分:

型号

namespace Models
{
  public class Task
  {
    public string Id { get; set; }

    public Status Status { get; set; }

    // And other properties ...
  }    
}

列表(父级)

视图模型

public class ListViewModel : ActionViewModelBase
{
    public ObservableCollection<Task> Tasks { get; set; }
}

查看

<ItemsControl x:Name="Tasks"
                Grid.Row="1"
                Grid.ColumnSpan="2"
                ItemsSource="{Binding Path=Tasks, Mode=OneWay}">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <StackPanel Orientation="Vertical" />
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <ItemsControl.ItemTemplate>
        <DataTemplate DataType="models:Task">
            <!-- TODO : Bind model to task view/viewmodel -->
            <views:TaskView Model="{}" />
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

任务(子)

TaskView.xaml.cs

public partial class TaskView
{
    public TaskView()
    {
        InitializeComponent();
    }

    public Task Model
    {
        get { return GetValue(ModelProperty) as Task; }
        set { SetValue(ModelProperty, value); }
    }
    public static readonly DependencyProperty ModelProperty =
      DependencyProperty.Register("Model", typeof(Task), typeof(TaskView));
}  

TaskView.xaml

<UserControl>
  <UserControl.DataContext>
    <viewModels.TaskViewModel />
  </UserControl.DataContext>

  <Border>
      <!-- TODO : Read model attributes -->
      <Grid Background="{Binding Path=Model.Status, Converter={StaticResource StatusBackgroundColourConverter}}">
          <!-- ... -->
      </Grid>
  </Border>
</UserControl>

任务视图模型

class TaskViewModel : ActionViewModelBase
{
    public Task Model { get; set; }
    // ...
}    

【问题讨论】:

  • 也许我只是不认识您正在使用的模式,但是说到 MVVM,您不应该从模型创建视图模型并从视图模型创建视图,而不是让视图处理模型?
  • @grek40 这对我来说看起来不正确。根据 MVVM 模式,Model 不应该知道 ViewModel,ViewModel 不应该知道 View。查看取自 MSDN 文档 i-msdn.sec.s-msft.com/dynimg/IC564167.png 的图像
  • 看图就明白了,view和model之间没有直接的联系。确实,模型不知道视图模型,但是:视图模型知道模型,所以说new viewmodel(modelData) 是合法的。 viewmodel 和 view 类似。
  • @grek40 我同意,但这似乎与您的第一条评论相矛盾,或者我误解了您。

标签: c# wpf xaml .net-4.5 mvvm-light


【解决方案1】:

您的模型和视图模型部分已正确定义,但是您可能想查看INotifyPropertyChanged 接口(以启用与模型的双向数据绑定)。

视图模型通过DataContext 属性自动传递给您的用户控件(请参阅:Property Value Inheritance)。

<DataTemplate DataType="models:Task">
    <!-- DataContext of TaskView is a single Task -->
    <views:TaskView />
</DataTemplate>

您不能在UserControl 中明确指定DataContext,因为这会覆盖继承的DataContext(并将其设置为TaskViewModel 的新实例)。

<UserControl x:Class="TaskView">  
  <!-- DataContext of UserControl is a single Task (inherited) -->
  <Border>
      <Grid Background="{Binding Status, Converter={StaticResource StatusBackgroundColourConverter}}">
          <!-- ... -->
      </Grid>
  </Border>
</UserControl>

【讨论】:

  • 通过将模型作为 DataContext,我可以读取属性(状态和 ID)。换句话说,它有效。但是,我的 ViewModel 不再接收命令。我猜 View 和 ViewModel 不再链接了。
  • 将 ViewModel 作为 View 的 DataContext 并将 Model 作为 ViewModel 的“DataContext”不是更好吗?或类似的东西。
  • 在这种情况下,您需要将Task 重命名为TaskModel,并引入一个具有Task 属性的类TaskViewModel。然后将TaskViewModel 的实例放入您的ObservableCollection&lt;T&gt;
  • 这将是完整的 MVVM 方法,然后您可以将命令放在 TaskViewModel 类中。
  • 有效!简单明了,就是我喜欢的方式! :) 虽然有人告诉我我们不应该像那样实例化 ViewModel,但我个人对这个解决方案非常满意。
猜你喜欢
  • 2011-10-07
  • 1970-01-01
  • 1970-01-01
  • 2018-10-25
  • 2012-07-31
  • 2011-08-25
  • 2023-03-06
  • 2012-09-29
  • 1970-01-01
相关资源
最近更新 更多