Как общаться между UserControl в MVVM - WPF Application - PullRequest
0 голосов
/ 26 сентября 2019

Я хочу создать приложение с меню слева, которое изменит содержание справа.Для этого у меня есть MainWindow с двумя ContentControl (один, который будет Content 'UserControl' Menu ', а другой, который будет Content, выбранный UserControl' Red 'или' Green '.

Проблема в том, что Contentсправа не меняется ...

Я провел некоторое исследование и увидел такие концепции, как инъекция зависимостей, делегат, событие, шина сообщений, ViewModelLocator ... но я не знаю, какой из них будет наиболееподходит в этом случае и как его реализовать. (Я не хочу использовать MVVMLight или любой подобный плагин)

Заранее спасибо за интерес.

Для этого я использую MVVMпривязка к шаблону и шаблону данных:

App.xaml

<Application.Resources>
    <DataTemplate DataType="{x:Type viewModel:MainViewModel}">
        <view:MainWindow />
    </DataTemplate>
    <DataTemplate DataType="{x:Type viewModelMenu:LeftViewModel}">
        <viewMenu:Left />
    </DataTemplate>
    <DataTemplate DataType="{x:Type viewModelContent:RedViewModel}">
        <viewContent:Red />
    </DataTemplate>
</Application.Resources>

ViewModel.cs

public abstract class ViewModel : INotifyPropertyChanged
{
    #region Properties

    private ViewModel _mainContent;

    public ViewModel MainContent
    {
        get => _mainContent;
        set
        {
            _mainContent = value;
            OnPropertyChanged();
            MessageBox.Show(nameof(MainContent));
        }
    }

    #endregion Properties

    public ViewModel()
    {
        InitCommands();
    }

    protected abstract void InitCommands();

    #region Factory Method - CreateCommand

    protected ICommand CreateCommand(Action execute, Func<bool> canExecute)
    {
        return new RelayCommand(
            execute: execute,
            canExecute: canExecute
            );
    }

    protected ICommand CreateCommand<T>(Action<T> execute, Predicate<T> canExecute)
    {
        return new RelayCommand<T>(
            execute: execute,
            canExecute: canExecute
            );
    }

    #endregion Factory Method - CreateCommand

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = "")
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

MainViewModel.cs

internal class MainViewModel : ViewModel
{
    private ViewModel _leftMenu;
    public ViewModel LeftMenu
    {
        get => _leftMenu;
        set
        {
            _leftMenu = value;
            OnPropertyChanged();
        }
    }

    public MainViewModel()
    {
        LeftMenu = new LeftViewModel();
    }

    protected override void InitCommands()
    {
    }

LeftViewModel.cs

internal class LeftViewModel : ViewModel
{
    public ICommand ChangeContentToRed { get; set; }
    public ICommand ChangeContentToGreen { get; set; }

    protected override void InitCommands()
    {
        ChangeContentToRed = new RelayCommand(
            execute: () => MainContent = new RedViewModel(),
            canExecute: () => !(MainContent is RedViewModel)
            );

        ChangeContentToGreen = new RelayCommand(
            execute: () => MainContent = new GreenViewModel(),
            canExecute: () => !(MainContent is GreenViewModel)
            );
    }
}

RedViewModel и GreenViewModel пусты, поэтому я не показываю код, а расширяю ViewModel

Window.xaml

 <Window.DataContext>
    <viewModel:MainViewModel />
</Window.DataContext>

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*" />
        <ColumnDefinition Width="3*" />
    </Grid.ColumnDefinitions>

    <ContentControl Grid.Column="0" Content="{Binding Path=LeftMenu}" />
    <ContentControl Grid.Column="1" Content="{Binding Path=MainContent}" />
</Grid>

Left.xaml

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

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="*" />
        <RowDefinition Height="*" />
    </Grid.RowDefinitions>
    <Button
        Grid.Row="0"
        Command="{Binding Path=ChangeContentToRed}"
        Content="Red" />
    <Button
        Grid.Row="1"
        Command="{Binding Path=ChangeContentToGreen}"
        Content="Green" />
</Grid>

Красный и Зеленый только два UserCoнтрол с красной и зеленой сеткой

1 Ответ

0 голосов
/ 26 сентября 2019

Если у вас есть DataTemplate, например

<DataTemplate DataType="{x:Type viewModelMenu:LeftViewModel}">
    <viewMenu:Left />
</DataTemplate>

, а затем присваивайте значение типа LeftViewModel свойству Content ContentControl, например

<ContentControl Content="{Binding Path=LeftMenu}"/>

, DataTemplate назначается дляContentTemplate ContentControl и элемент в созданном экземпляре DataTemplate (т. Е. Ваш UserControl) наследует DataContext ContentPresenter в ControlTemplate ContentControl, который затем содержит значение Content.

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

Вы должны удалить явное назначение DataContext из UserControl, т.е. это:

<UserControl.DataContext>
    <viewModel:LeftViewModel />
</UserControl.DataContext>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...