Привязка представления к DataContext из другого класса ViewModel - PullRequest
1 голос
/ 20 апреля 2020

Я использую шаблон MVVM и натолкнулся на эту проблему.

Я хотел бы создать объект SpecificProductViewModel, передав продукт, для которого я хочу заданное представление c по параметру, из моего класса ProductListViewModel ( который содержит все продукты) со следующей функцией:

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

Затем мне нужно было бы присвоить DataContext моего SpecificProductView для моей SpecificProductViewModel в коде кода следующим образом:

DataContext = new SpecificProductViewModel();

Проблема, однако, заключается в том, что при этом создается новый объект SpecificProductViewModel, и поэтому DataContext не использует данные (продукт tblMATProduct), передаваемые параметром при создании объекта из класса ProductListViewModel.

Будет есть способ назначить DataContext непосредственно из класса ProductListViewModel или получить продукт tblMATProduct из кода или в xaml?

Заранее спасибо!

Редактировать 1: Я думал, что ли ke Lennart, выполнив это:

DataContext = new ProductListViewModel(); 

Проблема, однако, заключается в том, что экземпляр specificViewModel должен быть создан сразу после того, как пользователь щелкнет по указанному c продукту.

Поэтому, если мы создадим новый экземпляр 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 со всеми моими продуктами, где пользователь может выбрать строку (указать c продукт) нажав на нее.

<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 через шаблон данных xaml в ProductListView.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: Объяснение того, как обрабатывается шаблон данных

Вот ContentControl, который запускает представление SpecificProductView. Он использует

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

Он привязывается к этому, что определяет, какой продукт должен отображаться в SpecificProductView.

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

1 Ответ

2 голосов
/ 21 апреля 2020

Поскольку вы используете ContentControl, который привязывается к свойству CurrentProductViewModel, заданному в модели представления, вы должны просто удалить следующую часть, которая устанавливает DataContext UserControl в новый экземпляр модель представления из вашего XAML:

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

UserControl будет затем наследовать модель представления, возвращаемую CurrentProductViewModel как ее DataContext.

Обычно это плохо Идея явно установить свойство DataContext для UserControl, как в XAML, так и в выделенном коде, так как это нарушает наследование DataContext от родительского элемента.

...