How to communicate between UserControl in MVVM - WPF Application
我想创建一个带有左侧菜单的应用程序,该菜单将更改右侧的内容。
为此,我有一个带有两个ContentControl的MainWindow(一个将容纳一个UserControl'菜单',另一个将容纳所选的UserControl'红色'或'绿色'。
问题是右侧的内容不会更改...
我进行了一些研究,看到了诸如依赖注入,委托,事件,消息总线,ViewModelLocator等概念。
但我不知道在这种情况下哪一个最合适,以及如何实现它。 (我不想使用MVVMLight或类似的任何插件)
事先感谢您的关注。
为此,我使用了MVVM模式和DataTemplate绑定:
应用程式
1 2 3 4 5 6 7 8 9 10 11 | <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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 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
1 2 3 4 5 6 7 8 9 10 11 12 13 | <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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | <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> |
红色和绿色只是两个带有红色和绿色网格的UserControl
当你有一个DataTemplate像
1 2 3 | <DataTemplate DataType="{x:Type viewModelMenu:LeftViewModel}"> <viewMenu:Left /> </DataTemplate> |
然后将类型为LeftViewModel的值分配给ContentControl的Content属性,例如
1 | <ContentControl Content="{Binding Path=LeftMenu}"/> |
则将DataTemplate分配给ContentControl的ContentTemplate,实例化的DataTemplate中的元素(即您的UserControl)继承ContentControl的ControlTemplate中ContentPresenter的DataContext,然后该ContentPresenter保存Content值。
但是,这仅在您未显式分配UserControl的DataContext并因此中断DataContext属性的值继承的情况下才有效。
您必须从UserControl中删除显式的DataContext分配,即:
1 2 3 | <UserControl.DataContext> <viewModel:LeftViewModel /> </UserControl.DataContext> |