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}}" />