I'm learning creation of menu. I have some issue, maybe the same that this post.
My app contains :
one master container (MainWindow)
one menu (MenuView)
some views
The MainWindow is defined like this (two columns, one for the menu, the other for views):
<Grid Background="{StaticResource PrimaryBackgroundColor}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<ContentControl Grid.Column="0" Content="{Binding Menu}"/>
<ContentControl Grid.Column="1" Content="{Binding SelectedViewModel}"/>
</Grid>
When we click on menu items, there are no displayed views (built with UserControl).
I add the following codes :
MainWindowViewModel.cs
#region Constructor
public MainWindowViewModel()
{
Menu = new MenuViewModel();
}
#endregion Constructor
#region Properties
private object _menu;
public object Menu
{
get
{
return _menu;
}
set
{
_menu = value;
OnPropertyChanged(nameof(Menu));
}
}
private object _selectedViewModel;
public object SelectedViewModel
{
get
{
return _selectedViewModel;
}
set
{
_selectedViewModel = value;
OnPropertyChanged(nameof(SelectedViewModel));
}
}
#endregion Properties
MenuViewModel.cs
#region Variable
MainWindowViewModel mainWindowObj;
#endregion Variable
#region Constructor
public MenuViewModel()
{
menuCommand = new RelayCommand(load_menuChoiced);
}
#endregion Constructor
#region Properties
public ICommand menuCommand { get; set; }
#endregion Properties
#region Public Methods
#endregion Public Method
#region Private Method
public void load_menuChoiced(object obj)
{
switch (obj)
{
case "Home":
mainWindowObj = new MainWindowViewModel()
{
SelectedViewModel = new HomeViewModel()
};
break;
case "Graphic":
break;
case "Setting":
break;
default:
break;
}
}
#endregion Private Method
Could you explain me why it doesn't work and help me to fix it ?
Thanks a lot
It may be that HomeView was not found, Add this code to MainWindow's Resources property.
<DataTemplate DataType="{x:Type vm:HomeViewModel}">
<view:HomeView/>
</DataTemplate>
Related
I'm creating a WPF Molds app that contains 2 windows: MainWindow with DataGrid, and AddEditWindow which allows to Add/Edit Molds.
I have a EditButton which located in a TemplateColumn of DataGrid:
<DataGridTemplateColumn Width="Auto">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Width="150"
Height="40"
BorderThickness="2"
BorderBrush="DarkRed"
Background="Red"
Foreground="White"
Content="Edit"
Name="BtnEdit"
CommandParameter="{Binding}"
Command="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}}, Path=DataContext.AddEditWindowCommand}">
</Button>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
AddEditWindowCommand:
public ICommand AddEditWindowCommand { get; }
private bool CanAddEditWindowCommandExecute(object SelectedRow) => true;
private void OnAddEditWindowCommandExecuted(object SelectedRow)
{
AddEditWindow window = new AddEditWindow();
window.Show();
}
And I want to pass DataContext to the AddEditWindowViewModel. In a Code-Behind, I could done something like this:
private void BtnEdit_Click(object sender, RoutedEventArgs e)
{
AddEditWindow addEditWindow = new AddEditWindow((sender as Button).DataContext as Molds);
addEditWindow.Show();
}
And then retrieve it AddEditWindow like this:
private Molds _currentMold = new Molds();
public GamesEdit(Molds selectedMold)
{
InitializeComponent();
if (selectedMold != null)
{
_currentMold = selectedMold;
}
DataContext = _currentMold;
But in MVVM I can't. So, is there a way to do it without breaking MVVM pattern?
p.s. since I'm new to the MVVM, I would really appreciate detailed explanation.
update:
MainWindowViewModel:
internal class MainWindowViewModel : ViewModel
{
#region Variables
#region Textblocks for search
private Molds newMolds { get; set; } = new Molds();
public string TxtType
{
get => newMolds.Type;
set => newMolds.Type = value;
}
public string TxtName
{
get => newMolds.Name;
set => newMolds.Name = value;
}
public string TxtKus
{
get => newMolds.Kus;
set => newMolds.Kus = value;
}
#endregion
#region AllMolds
private ObservableCollection<Molds> allMolds = new ObservableCollection<Molds>(ApplicationContext.GetContext().Molds.ToList());
public ObservableCollection<Molds> AllMolds
{
get => allMolds;
set => allMolds = value;
}
#endregion
#region FilteredMolds
private ObservableCollection<Molds> filteredMolds = new ObservableCollection<Molds>(ApplicationContext.GetContext().Molds.ToList());
public ObservableCollection<Molds> FilteredMolds
{
get
{
filteredMolds = AllMolds;
var currentfilteredmolds = new List<Molds>(filteredMolds);
if (TxtName != null)
currentfilteredmolds = currentfilteredmolds.Where(p => p.Name.ToLower().Contains(TxtName.ToLower())).ToList();
if (TxtType != null)
currentfilteredmolds = currentfilteredmolds.Where(p => p.Type.ToLower().Contains(TxtType.ToLower())).ToList();
if (TxtKus != null)
currentfilteredmolds = currentfilteredmolds.Where(p => p.Kus.ToLower().Contains(TxtKus.ToLower())).ToList();
return new ObservableCollection<Molds>(currentfilteredmolds);
}
set => filteredMolds = value;
}
#endregion
#endregion
#region Commands
#region CloseApplicationCommand
public ICommand CloseApplicationCommand { get; }
private bool CanCloseApplicationCommandExecute(object p) => true;
private void OnCloseApplicationCommandExecuted(object p)
{
Application.Current.Shutdown();
}
#endregion
#region SearchCommand
public ICommand SearchCommand { get; }
private bool CanSearchCommandExecute(object p) => true;
private void OnSearchCommandExecuted(object p)
{
OnPropertyChanged("FilteredMolds");
}
#endregion
#region Open AddEditWindowCommand
public ICommand AddEditWindowCommand { get; }
private bool CanAddEditWindowCommandExecute(object SelectedRow) => true;
private void OnAddEditWindowCommandExecuted(object SelectedRow)
{
AddEditWindow window = new AddEditWindow();
window.Show();
}
#endregion
#region DeleteMoldCommand
public ICommand DeleteMoldCommand { get; }
private bool CanDeleteMoldCommandExecute(object SelectedItems)
{
if (SelectedItems != null) return true; else return false;
}
private void OnDeleteMoldCommandExecuted(object SelectedItems)
{
System.Collections.IList items = (System.Collections.IList)SelectedItems;
var moldsforRemoving = items?.Cast<Molds>().ToList();
if (MessageBox.Show($"You want to remove the following {moldsforRemoving.Count()} molds?", "Attention",
MessageBoxButton.YesNo, MessageBoxImage.Question) == MessageBoxResult.Yes)
{
try
{
ApplicationContext.GetContext().Molds.RemoveRange(moldsforRemoving);
ApplicationContext.GetContext().SaveChanges();
MessageBox.Show("Data deleted successfully.", "Data deletion",
MessageBoxButton.OK, MessageBoxImage.Information);
AllMolds = new ObservableCollection<Molds>(ApplicationContext.GetContext().Molds.ToList());
OnPropertyChanged("FilteredMolds");
}
catch (Exception ex)
{
MessageBox.Show(ex.Message.ToString(), "Error",
MessageBoxButton.OK, MessageBoxImage.Error);
}
}
}
#endregion
#region DragMoveCommand
public ICommand DragMoveCommand { get; }
private bool CanDragMoveCommandExecute(object p) => true;
private void OnDragMoveCommandExecuted(object p)
{
Application.Current.MainWindow.DragMove();
}
#endregion
#endregion
public MainWindowViewModel()
{
#region Command Samples
CloseApplicationCommand = new LamdaCommand(OnCloseApplicationCommandExecuted, CanCloseApplicationCommandExecute);
SearchCommand = new LamdaCommand(OnSearchCommandExecuted, CanSearchCommandExecute);
AddEditWindowCommand = new LamdaCommand(OnAddEditWindowCommandExecuted, CanAddEditWindowCommandExecute);
DeleteMoldCommand = new LamdaCommand(OnDeleteMoldCommandExecuted, CanDeleteMoldCommandExecute);
DragMoveCommand = new LamdaCommand(OnDragMoveCommandExecuted, CanDragMoveCommandExecute);
#endregion
#region Variable Samples for searching
TxtName = null;
TxtKus = null;
TxtType = null;
#endregion
}
}
AddEditWindowViewModel
internal class AddEditWindowViewModel : ViewModel
{
#region Variables
private Molds _currentMold = new Molds();
#endregion
#region Commands
#region CloseWindowCommand
public ICommand CloseWindowCommand { get; }
private bool CanCloseWindowCommandExecute(object p) => true;
private void OnCloseWindowCommandExecuted(object p)
{
Application.Current.Windows[1].Close();
}
#endregion
#region DragMoveAddEditWindowCommand
public ICommand DragMoveAddEditWindowCommand { get; }
private bool CanDragMoveAddEditWindowCommandExecute(object p) => true;
private void OnDragMoveAddEditWindowCommandExecuted(object p)
{
Application.Current.Windows[1].DragMove();
}
#endregion
#endregion
public AddEditWindowViewModel()
{
#region Command samples
CloseWindowCommand = new LamdaCommand(OnCloseWindowCommandExecuted, CanCloseWindowCommandExecute);
DragMoveAddEditWindowCommand = new LamdaCommand(OnDragMoveAddEditWindowCommandExecuted, CanDragMoveAddEditWindowCommandExecute);
#endregion
}
}
I connect them to the window using <Window.DataContext>:
<Window.DataContext>
<vm:MainWindowViewModel/>
</Window.DataContext>
Same goes for the AddEditWindowViewModel.
DataGrid binding:
<DataGrid x:Name="DGridMolds"
AutoGenerateColumns="False"
IsReadOnly="True"
Foreground="White"
BorderBrush="White"
Background="#2b2a38"
Grid.Column="1"
Grid.Row="1"
ItemsSource="{Binding Path=FilteredMolds}"
>
AddEditWindow.Xaml:
<Window.DataContext>
<vm:AddEditWindowViewModel/>
</Window.DataContext>
<Border Background="#2f2e3c"
CornerRadius="10">
<Border.InputBindings>
<MouseBinding Command="{Binding DragMoveAddEditWindowCommand}" MouseAction="LeftClick"/>
</Border.InputBindings>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="30"/>
<RowDefinition/>
<RowDefinition Height="30"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="30"/>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition Width="30"/>
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="1" Grid.Row="1" Orientation="Vertical">
<TextBlock Text="Add" FontSize="22" Foreground="White" HorizontalAlignment="Center" Margin="0,30,0,0"/>
<TextBox Foreground="White" Text="{Binding Type, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Margin="5, 35, 5, 5" materialDesign:HintAssist.Hint="Type"/>
<TextBox Foreground="White" Text="{Binding Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Margin="5" materialDesign:HintAssist.Hint="Name"/>
<TextBox Foreground="White" Text="{Binding Kus, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Margin="5" materialDesign:HintAssist.Hint="Kus"/>
In a Code-Behind, I could done something like this:
Take a closer look at your XAML.
You have a binding set in the CommanParameter property.
The binding instance is empty - this means that the binding occurs to the DataContext of the element in which it is specified.
Hence, in the command parameter, you will get this Data Context.
private void OnAddEditWindowCommandExecuted(object SelectedRow)
{
AddEditWindow window = new AddEditWindow()
{DataContext = SelectedRow};
window.Show();
}
So, is there a way to do it without breaking MVVM pattern?
You've already broken MVVM.
ViewModel is not allowed to work with UI elements.
The ViewModel doesn't even need to know what type of View is using it: WPF, Forms, or Console.
And you CREATE the Window!
This is unacceptable for the MVVM concept.
Addition in connection with showing more detailed code in the main question:
I can't understand the logic of your code.
Therefore, I will write in the measure as I understand your intentions.
AddEditWindowViewModel class - designed for logic for editing and/or adding an item.
But then he has to get this element and provide it in his property so that he can create a GUI for editing.
It should be something like this:
namespace MoldsApp
{
public class AddEditWindowViewModel : ViewModel
{
public Molds CurrentMold { get; }
// Constructor called to edit an entity
public AddEditWindowViewModel(Molds currentMold)
{
CurrentMold = currentMold;
}
//Constructor called to create and edit an entity
public AddEditWindowViewModel()
: this(new Molds())
{
}
}
}
Also, your DataContext is set incorrectly.
By creating it inside XAML, you cannot set the data for this instance of the ViewModel.
Therefore, in XAML, you can instantiate a ViewModel used only at the time of its designed.
For a design-time DataContext, use the d: prefix.
<d:Window.DataContext>
<vm:MainWindowViewModel/>
</d:Window.DataContext>
With these changes, the item edit command should be like this:
private void OnAddEditWindowCommandExecuted(object SelectedRow)
{
AddEditWindow window = new AddEditWindow()
{
DataContext = new AddEditWindowViewModel((Molds)SelectedRow)
};
window.Show();
}
I have to navigate to another tab by a button click from the first tab in a WPF MVVM Application(c#).
I am trying to achieve this by adding binding to Selected Index property in tab control.There are two different view models are used in the first tab.After adding binding to Selected Index property in tab control it loses the rest of view model's access and No data is present on the text boxes in the first tab. Also navigation is not working . how can I use tab navigation if the window has multiple view models. please see sample code.
XAML file
MainWindow.xaml
<Grid>
<TabControl SelectedIndex="{Binding SelectedTab,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
DataContext="{Binding processVM}">
<TabItem Header="Home">
<Grid ShowGridLines="false" >
<Grid.ColumnDefinitions >
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="50" />
<RowDefinition Height="50" />
<RowDefinition Height="50" />
</Grid.RowDefinitions>
<TextBox Name="txtCustomerName"
Grid.Row="0" Grid.Column="1"
Text="{Binding CustomerName}"
DataContext="{Binding customerVM}"></TextBox>
<TextBox Name="txtDepositAmount"
Grid.Row="1" Grid.Column="1"
Text="{Binding DepositAmount}"
DataContext="{Binding customerVM}"></TextBox>
<Button Content="Click" Width="100" Height="50"
Grid.Row="2"
DataContext="{Binding processVM}"
Command="{Binding ButtonCommand}"
/>
</Grid>
Code behind
MainWindow.xaml.cs
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new MainWindowViewModel()
{
processVM = new ProcessViewModel(),
customerVM = new CustomerViewModel()
};
}
}
View Models
MainWindowViewModel.cs
class MainWindowViewModel
{
public ProcessViewModel processVM { get; set; }
public CustomerViewModel customerVM { get; set; }
}
ProcessViewModel.cs
public class ProcessViewModel: INotifyPropertyChanged
{
private string depositAmount;
public string DepositAmount
{
get { return depositAmount; }
set {
depositAmount = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("DepositAmount"));
}
}
public event PropertyChangedEventHandler PropertyChanged;
private ICommand m_ButtonCommand;
public ICommand ButtonCommand
{
get
{
return m_ButtonCommand;
}
set
{
m_ButtonCommand = value;
}
}
private int selectedTab;
public int SelectedTab
{
get { return selectedTab; }
set
{
selectedTab = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("SelectedTab"));
}
}
public ProcessViewModel()
{
ButtonCommand = new RelayCommand(new Action<object>(clickbutton));
depositAmount = "450";
}
public void clickbutton(object obj)
{
MessageBox.Show("clicked");
SelectedTab = 1;
}
}
CustomerViewModel.cs
class CustomerViewModel: ProcessViewModel, INotifyPropertyChanged
{
private string customerName;
public string CustomerName
{
get { return customerName; }
set { customerName = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("CustomerName"));
}
}
public CustomerViewModel()
{
CustomerName = "Alex";
}
public event PropertyChangedEventHandler PropertyChanged;
}
Before adding binding for selected index there were no issues.
Your problem is that you're setting TabControl.DataContext. DataContext is inherited, so all the controls inside it are now using processVM as their binding source instead of MainWindowViewModel.
Instead of setting TabControl.DataContext, change the SelectedIndex binding to this:
SelectedIndex="{Binding processVM.SelectedTab, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
I have the following problem. I have moved the DelegateCommand from the ViewModel to a separate class. And observe a property in the ViewModel. That works so far.
Then CanExecute will call the first one with NULL when the view is initialized. Which is also correct. Then the first time OnNavigatedTo is called and the TestModel is set. But than CanExecute is called again with NULL which is wrong. If OnNavigatedTo is then called a second time and the TestModel is set, the value is passed correctly to CanExecute methode.
CommandClass:
public class CommandFactory : BindableBase, ICommandFactory
{
#region Fields
private ICommand buttonTestCommandLocal;
#endregion
#region Properties
public ICommand ButtonTestCommand
{
get { return buttonTestCommandLocal ?? (buttonTestCommandLocal = new DelegateCommand<ITestModel>(ButtonTestCommand_Executed, ButtonTestCommand_CanExecute)); }
}
#endregion
#region Methods
private bool ButtonTestCommand_CanExecute(ITestModel parameter)
{
return parameter != null;
}
private void ButtonTestCommand_Executed(ITestModel parameter)
{
int x = 30;
Console.WriteLine(x.ToString());
}
#endregion
}
public interface ICommandFactory
{
ICommand ButtonTestCommand { get; }
}
ViewModel:
public class ButtonRegionViewModel : BindableBase, INavigationAware
{
#region Fields
private ITestModel testModelLocal;
#endregion
#region Constructors and destructors
public ButtonRegionViewModel(ICommandFactory commandFactory)
{
CommandFactory = commandFactory;
//Does not work
if(commandFactory.ButtonTestCommand is DelegateCommand<ITestModel> buttonTestCommand)
buttonTestCommand.ObservesProperty(()=> TestModel);
}
#endregion
#region Properties
public ITestModel TestModel
{
get => testModelLocal;
private set
{
SetProperty(ref testModelLocal, value);
//Does work
//if (CommandFactory.ButtonCommand is IModelCommand modelCommand)
// modelCommand.RaiseCanExecuteChanged();
}
}
#endregion
#region Methods
public bool IsNavigationTarget(NavigationContext navigationContext)
{
return true;
}
public void OnNavigatedFrom(NavigationContext navigationContext)
{
}
public void OnNavigatedTo(NavigationContext navigationContext)
{
if (!(navigationContext.Parameters["Element"] is ITestModel testModel))
return;
TestModel = testModel;
}
#endregion
}
View:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Button Grid.Row="1" Margin="2" Padding="0" HorizontalAlignment="Center" HorizontalContentAlignment="Center"
CommandParameter="{Binding Path=TestModel, Mode=OneWay}" Content="CommandFactory.ButtonTestCommand"
Command="{Binding Path=CommandFactory.ButtonTestCommand}" Width="200" Height="100"/>
</Grid>
I have no idea why this doesn't work the first time. Since RaiseCanExecuteChanged works directly.
Thanks for all your help :-)
I have MainWindow thath holds <ContentControl ... Content="{Binding CurrentViewModel}" in MainViewModel I am switching between two View FirstView,SecondView. FirstView contains usercontrol ContentFirstView that implementing async data sending to ContentSecondViewModel. Data send's with time delay 1000ms. The main question is why when i am clicking on 1,2,1,2,1,2 buttons the speed of updating label Count in ContentSecondView greatly increasing? I think that ContentSecondViewModel do not disposing and every time when i am clicking on button 2, it creates new object of Messenger.Register ...
MainModel.xaml:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<ContentControl Grid.Column="1" Content="{Binding CurrentViewModel}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>
<Button Content="1" Command="{Binding FirstCommand}" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Width="75"/>
<Button Content="2" Command="{Binding SecondCommand}" HorizontalAlignment="Left" Margin="10,78,0,0" VerticalAlignment="Top" Width="75"/>
</Grid>
MainViewModel.cs:
public class MainViewModel : ViewModelBase
{
/// <summary>
/// Initializes a new instance of the MainViewModel class.
/// </summary>
///
public RelayCommand FirstCommand
{
get
{
return new RelayCommand(() => SwitchFirst());
}
}
public RelayCommand SecondCommand
{
get
{
return new RelayCommand(()=>SwitchSecond());
}
}
public static readonly FirstViewModel firstViewModel = new FirstViewModel();
public static readonly SecondViewModel secondViewModel = new SecondViewModel();
ViewModelBase currentViewModel;
public ViewModelBase CurrentViewModel
{
get
{
return currentViewModel;
}
set
{
if (currentViewModel == value)
return;
currentViewModel = value;
RaisePropertyChanged("CurrentViewModel");
}
}
public void SwitchFirst()
{
CurrentViewModel = MainViewModel.firstViewModel;
}
public void SwitchSecond()
{
CurrentViewModel = MainViewModel.secondViewModel;
}
public MainViewModel()
{
CurrentViewModel = MainViewModel.secondViewModel;
////if (IsInDesignMode)
////{
//// // Code runs in Blend --> create design time data.
////}
////else
////{
//// // Code runs "for real"
////}
}
}
SecondView.xaml:
<Grid>
<views:ContentSecondView></views:ContentSecondView>
</Grid>
FirstView.xaml:
<Grid>
<views:ContentFirstView></views:ContentFirstView>
</Grid>
ContentFirstView.xaml:
<Grid>
<Label>View That sending data</Label>
</Grid>
ContentSecondView.xaml:
<Grid>
<Label>View That sending data</Label>
</Grid>
ContentFirstViewModel.cs:
public class ContentFirstViewModel
{
public RelayCommand SendMessage
{
get
{
return new RelayCommand(() => Send());
}
}
public void Send()
{
Messenger.Default.Send<MessageCommuniactor>(new MessageCommuniactor {State=1 });
}
public void Increase()
{
while(true)
{
System.Threading.Thread.Sleep(1000);
Messenger.Default.Send<MessageCommuniactor>(new MessageCommuniactor { State = 1 });
}
}
public ContentFirstViewModel()
{
Action A = new Action(Increase);
IAsyncResult result = A.BeginInvoke(null, null);
}
}
ContentSecondViewModel.cs:
public class ContentSecondViewModel:ViewModelBase
{
private int count;
public int Count
{
get
{
return this.count;
}
set
{
this.count = value;
this.RaisePropertyChanged("Count");
}
}
public ContentSecondViewModel()
{
Messenger.Default.Register<MessageCommuniactor>(this, (key) =>
{
Count += key.State;
});
}
}
Your DataTemplate ensures that a new view is created every time a ContentFirstViewModel is present. Instead, go with a singleton approach where a singleton view is injected when needed. You can use Prism's regionmanager or simple binding for that.
I am switching two Views. after message sending from Messenger.Default.Send<Message>(new Message {LoadingIndication="Loaded" },"Token"); It's reciving two message's because it create's OneViewModel two times first time in BinaryMultiViewModel second into OneView. But i need only one message. I can not remove something because in first case it should not switch in second it should show data.
For example
MultiView.cs
namespace Test.ViewModel
{
class BinaryMultiViewModel : ViewModelBase
{
readonly static OneViewModel OneViewModel = new OneViewModel();
readonly static FourViewModel FourViewModel = new FourViewModel();
private ViewModelBase currentMultiViewModel;
public BinaryMultiViewModel()
{
currentMultiViewModel = BinaryMultiViewModel.OneViewModel;
}
public ViewModelBase CurrentMultiViewModel
{
get
{
return currentMultiViewModel;
}
set
{
if (currentMultiViewModel == value)
{
return;
}
currentMultiViewModel = value;
RaisePropertyChanged("CurrentMultiViewModel");
}
}
}
}
MultiView.xaml
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<ContentControl Grid.Column="0" Content="{Binding CurrentMultiViewModel}" />
</Grid>
OneViewModel.cs:
namespace Test.ViewModel
{
public class OneViewModel : ViewModelBase
{
public OneViewModel()
{
Messenger.Default.Register<Message>(this,"Token", FromMultiModel);
}
private void FromMultiModel(Message input)
{
MessageBox.Show(input.LoadingIndication);
}
}
}
OneView.cs
namespace Test.Views
{
public partial class OneView : UserControl
{
public OneView()
{
DataContext = new OneViewModel();
InitializeComponent();
}
}
}
App.xaml:
<DataTemplate DataType="{x:Type vm:OneViewModel}">
<views:OneView/>
</DataTemplate>
<DataTemplate DataType="{x:Type vm:FourViewModel}">
<views:FourView/>
</DataTemplate>
You cannot create OneViewModel in OneView's ctor and assing it to datacontext.
The OneViewModel instance is created in BinaryMultiViewModel and when you set it to ContentControl using databinding and DataTempate with OneView usercontrol is chosen, then OneViewModel is set automatically as datacontext of OneView
just remove the line DataContext = new OneViewModel(); and it should work.