【问题标题】:Binding View to DataContext from another ViewModel Class从另一个 ViewModel 类将 View 绑定到 DataContext
【发布时间】:2020-04-20 20:04:39
【问题描述】:

我正在使用 MVVM 模式并遇到了这个问题。

我想通过使用以下函数从我的 ProductListViewModel 类(包含所有产品)传递我想要特定视图的产品来创建一个 SpecificProductViewModel 对象:

private void OnProductNav(tblMATProduct product)
    {
        if (product != null)
        {
            CurrentProduct = product;
            SpecificProductVM = new SpecificProductViewModel(product);
            CurrentProductViewModel = SpecificProductVM;
            SpecificProductVM.Product = product;
        }
    }

然后我需要在代码隐藏中将我的 SpecificProductView 的 DataContext 分配给我的 SpecificProductViewModel,如下所示:

DataContext = new SpecificProductViewModel();

但问题是,通过这样做会创建 SpecificProductViewModel 的新对象,因此 DataContext 不使用从 ProductListViewModel 类创建对象时通过参数传递的数据(tblMATProduct 产品)。

是否有办法直接从 ProductListViewModel 类分配 DataContext 或能够从代码隐藏或 xaml 中获取 tblMATProduct 产品?

提前致谢!

编辑 1:我这样做是像 Lennart 一样思考:

DataContext = new ProductListViewModel(); 

但问题在于,需要在用户单击特定产品后立即创建 specificViewModel 实例。

因此,如果我们在代码隐藏中创建一个 ProductListViewModel 的新实例并将其分配给 ProductListViewModel,则该实例将不知道用户点击了什么,也不会调用函数 OnProductNav。

编辑 2: 增加精度。

class ProductListViewModel : ViewModelBase
{

  private SpecificProductViewModel SpecificProductVM;

  public tblMATProduct CurrentProduct { set; get; }

  public ViewModelBase CurrentProductViewModel
    {
        get { return _currentProductViewModel; }
        set { SetProperty(ref _currentProductViewModel, value); }
    }

  public ProductListViewModel() {
    ProductNavCommand = new MyICommand<tblMATProduct>(OnProductNav);
  }

  private void OnProductNav(tblMATProduct product)
    {
        if (product != null)
        {
            SpecificProductVM = new SpecificProductViewModel(product);
            CurrentProductViewModel = SpecificProductVM;
        }

    }
}

在我的 ProductListView 中,我有一个包含所有产品的 DataGrid,用户可以通过单击它来选择一行(特定产品)。

<Datagrid>
   <i:Interaction.Triggers>
      <i:EventTrigger EventName="SelectionChanged">
          <i:InvokeCommandAction Command="{Binding ProductNavCommand}" 
    CommandParameter="{Binding Path=SelectedItem, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=DataGrid}}" />
          </i:EventTrigger>
   </i:Interaction.Triggers>
</DataGrid>

这是我的SpecificProductViewModel

class SpecificProductViewModel : ViewModelBase
{
    private tblMATProduct _product;


    public tblMATProduct Product
    {
        get { return _product; }
        set { SetProperty(ref _product, value); }
    }

    public SpecificProductViewModel()
    {

    }

    public SpecificProductViewModel(tblMATProduct product)
    {
        Product = product;
    }
}

下面是来自 SpecificProductView.xaml 的几行代码,它们将绑定到 SpecificProductViewModel.cs

<Grid Background="Red" Height="800" Width="1350" HorizontalAlignment="Center" VerticalAlignment="Center">
    <TextBlock Text="{Binding Product.FormatID}" FontSize="32" Foreground="White" HorizontalAlignment="Center" VerticalAlignment="Center"/>
    <TextBlock Text="{Binding Product.SpecificProductVM, RelativeSource={RelativeSource  Mode=FindAncestor, AncestorType=UserControl}}" FontSize="32" Foreground="White" HorizontalAlignment="Center" VerticalAlignment="Bottom"/>
    <TextBlock Text="{Binding Product.GradeID}" FontSize="32" Foreground="White" HorizontalAlignment="Center" VerticalAlignment="Top"/>
</Grid>

编辑 3:添加另一层精度

回答mm8的问题,因为我刚开始使用WPF和MVVM,我一直假设如果View's DataContext绑定到对应的ViewModel,那么View的实例会自动创建ViewModel 实例是通过 ProductListView.xaml 中的 xaml 数据模板创建的:

<DataTemplate DataType = "{x:Type viewModels:SpecificProductViewModel}">
    <products:SpecificProductView/>
</DataTemplate>

这就是我通常创建DataContext 的地方。

SpecificProductView.xaml.cs

public partial class SpecificProductView : UserControl
{
    public SpecificProductView()
    {
        InitializeComponent();
        DataContext = new SpecificProductViewModel();
    }
}

编辑 4:解释如何处理数据模板

这里是启动SpecificProductView 视图的ContentControl。它使用

    <Grid HorizontalAlignment="Center" VerticalAlignment="Center" Grid.Column="0" Grid.Row="0">
        <ContentControl Content="{Binding CurrentProductViewModel}"/>
    </Grid>

它与 this 绑定,确定应在SpecificProductView 中显示哪个产品。

public ViewModelBase CurrentProductViewModel
{
    get { return _currentProductViewModel; }
    set { SetProperty(ref _currentProductViewModel, value); }
}

【问题讨论】:

  • 你在ProductListViewModel中实现了INotifyPropertyChanged了吗?如果是这样,您可以将 SpecificProductView 的 DataContext 绑定到 XAML 中的 CurrentProductViewModel。另一种方法是使用事件。但我会尽量避免。
  • OnProductNav 是否在代码隐藏或 ProductListViewModel 中定义?
  • 您的问题很难理解,并且您发布的代码没有显示您如何实现(相关)视图和视图模型。只是无意义的片段。无论如何,您的产品应该使用ListBox 显示。然后,您可以将ListBox.SelectedItem(我假设它的类型为tblMATProduct )绑定到您的视图模型的属性。这样您就可以获得当前的tblMATProduct 实例。现在,当此属性更改时,您可以执行您的过程并创建适当的视图模型并将它们分配给属性。您将此属性绑定到您的视图的DataContext
  • 请发布课程(减少)和您的观点(减少)以显示上下文以及如何链接它们。这些代码片段根本无助于了解上下文。对于不了解您的应用程序的人来说,必须清楚地了解您提到的类是如何协同工作的。您正在谈论视图模型和代码隐藏,但您的代码片段来自哪里并不明显。没有信息就不可能提供帮助。
  • 谢谢,这样好多了。问题是,为什么不将SpecificProductViewDataContext 绑定到ProductListViewModel.CurrentProductViewModel 属性? SpecificProductViewWindow 吗?

标签: wpf mvvm view viewmodel datacontext


【解决方案1】:

由于您使用的是绑定到您在视图模型中设置的CurrentProductViewModel 属性的ContentControl,因此您只需删除以下将UserControlDataContext 设置为新实例的部分XAML 中的视图模型:

<UserControl.DataContext>
    <viewModel:SpecificProductViewModel/>
</UserControl.DataContext>

然后UserControl 将继承CurrentProductViewModel 返回的视图模型作为其DataContext

一般来说,在 XAML 和代码隐藏中显式设置 UserControlDataContext 属性是一个坏主意,因为这会破坏 DataContext 从父元素的继承.

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-11
    • 1970-01-01
    • 1970-01-01
    • 2012-03-18
    • 1970-01-01
    • 2013-08-29
    相关资源
    最近更新 更多