Home > OS >  Show Control from ViewModel in UI
Show Control from ViewModel in UI

Time:03-29

I have a UserControl in my ViewModel which needs to be changed depending on context of my ViewModel.

For example: my ViewModel contains an enum. When the value of this enum is Test1, the CurrentView property will be changed to an object of type MyCustomTest1. When the value is Test2, the property becomes an object of MyCustomTest2. I already know how to implement this but can't figure out how I can tell my UI to render the CustomControl.

I think I'll need to use ItemsControl for this but I'm not sure about this. This is what I've tried so far.

<StackPanel x:Name="MainContent" Grid.Column="1">
        <ItemsControl ItemsSource="{Binding CurrentView, Mode=OneWay}" />
    </StackPanel>

My Custom component simply contains a StackPanel with a TextBlock.

MyCustomTest1:

<StackPanel>
   <TextBlock>Hello World</TextBlock>
</StackPanel>

My ViewModel calls INotifyPropertyChanged when the CurrentView has been updated.

public UserControl CurrentView 
        { 
            get => currentView;
            private set
            {
                currentView = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(CurrentView)));
            }
        }

Does anyone know how to achive this?

CodePudding user response:

The view model must never know any controls. Controls are only handled in the view.

Your problem is usually solved by making use of data models and an associated DataTemplated, which instructs the view on how to render the data model.

This means you should introduce a data model for each view. Then bind this model to a ContentControl. The ContentControl will then apply the DataTemplate for the data type of the model and the view will get rendered.

MainViewModel.cs

class MainViewModel : INotifyPropertyChanged
{
  // TODO::Let this property raise the PropertyChanged event
  public object CurrentViewModel { get; set; }

  private void LoadView()
  {
    this.CurrentView = new MyCustomControlViewModel();
  }
}

MainWindow.xaml

<Window>
  <Window.DataContext>
    <MainViewModel />
  </Window.Resources>

  <Window.Resources>
    <DataTemplate DataType="{x:Type MyCustomControlViewModel}">
      <MyCustomControl />
    </DataTemplate>
  </Window.Resources>

  <ContentControl Content="{Binding CurrentViewModel}" />
</Window>

CodePudding user response:

You can design a ValueConverter, like:


using System;
using System.Globalization;
using System.Windows.Data;

public class MyValueConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if(value is ControlType type)
        {
            if (type == ControlType.Type1)
                return new MyCustomTest1();
            else if (type == ControlType.Type2)
                return new MyCustomTest2();
        }
        throw new NotImplementedException();
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

Then you can add a ContentControl, and bind its Content to the enum property, and introduce the Converter:

<UserControl.Resources>
    <!-- vc is the namespace where you put the value converter class -->
    <vc:MyValueConverter x:Key="converter" />
</UserControl.Resources>
...
<ContentControl Content="{Binding CurrentView, Converter={StaticResource converter}}" />
  • Related