在 UserControl WPF MVVM caliburn 内部的 UserControl 之间切换
Switch between UserControls inside UserControl WPF MVVM caliburn
我需要通过单击按钮从一个用户控件导航到另一个用户控件,我使用了两种不同的方法。
方法 1:我有一个主 window 和一些按钮,这些按钮将 select 我的“父”用户控件视图模型,使用导航控制器。
public NavigationController(MainWindowViewModel viewModel)
{
this.viewModel = viewModel;
}
public void Execute(object parameter)
{
string par = parameter.ToString();
switch (par)
{
case "0":
viewModel.SelectedViewModel = new ViewModel1();
break;
case "1":
viewModel.SelectedViewModel = new ViewModel2();
break;
}
}
XAML 边 (...)
<Button Command="{Binding NavigationController}" CommandParameter="1" />
<ContentControl Content="{Binding SelectedViewModel}" />
到目前为止一切顺利,我相信这是一个很好的策略。
但是对于方法 2,我有适当的“父”用户控件 selected,按钮点击以不同的方式绑定:
XAML
<Button cal:Message.Attach="ShowUserControl3()"/>
虚拟机
public object SelectedActionViewModel
{
get => _selectedActionViewModel;
set
{
_selectedActionViewModel = value;
}
}
public void ShowUserControl3()
{
_selectedActionViewModel = new VMusercontrol3();
OnPropertyChanged(nameof(SelectedActionViewModel));
}
第二种方法效果很好.. 在我第一次或第二次单击按钮时。在那之后,OnPropertyChanged
一直传递 null 并且不再 select 正确的用户控件。我在这里错过了什么?
额外的问题:如何从 UserControl4 中 select UserControl3?
编辑:所有用户控件都继承自 BaseViewModel,这就是奇怪的地方,因为 propertyChanged 为 null
public class BaseViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public event EventHandler ClosingRequest;
protected void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
希望我正确理解了你的问题。实现此目的的更简单方法是使用 Caliburn Micro 的内置支持。例如,将您的 shell 视图模型修改为
public class ShellViewModel:Conductor<object> // Replace object with your base viewmodel if any
{
private UserControl1ViewModel _uc1Instance;
public UserControl1ViewModel UC1Instance => _uc1Instance ?? (_uc1Instance = new UserControl1ViewModel());
private UserControl2ViewModel _uc2Instance;
public UserControl2ViewModel UC2Instance => _uc2Instance ?? (_uc2Instance = new UserControl2ViewModel());
public void ActivateUserControl1()
{
ActivateItem(UC1Instance);
}
public void ActivateUserControl2()
{
ActivateItem(UC2Instance);
}
}
来自 Caliburn Micro 的 Conductor<T>
class 使您能够在只有一个活动的情况下处理多个屏幕(视图)。您现在可以将您的观点更改为
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<StackPanel Orientation="Vertical">
<Button x:Name="ActivateUserControl1" Content="Show UC 1"/>
<Button x:Name="ActivateUserControl2" Content="Show UC 2"/>
</StackPanel>
<ContentControl Grid.Column="1" x:Name="ActiveItem"/>
</Grid>
可以在您的 UserControl1 和 UserControl2 中重复相同的过程以实现设置 UserControl3 和 UserControl4 的选项。
关于您的第二个问题,即关于 UserControl3 和 UserControl4 之间的通信,您可以使用 EventAggregators。
您可以在 here 中找到 EventAggregator 的示例。
我需要通过单击按钮从一个用户控件导航到另一个用户控件,我使用了两种不同的方法。
方法 1:我有一个主 window 和一些按钮,这些按钮将 select 我的“父”用户控件视图模型,使用导航控制器。
public NavigationController(MainWindowViewModel viewModel)
{
this.viewModel = viewModel;
}
public void Execute(object parameter)
{
string par = parameter.ToString();
switch (par)
{
case "0":
viewModel.SelectedViewModel = new ViewModel1();
break;
case "1":
viewModel.SelectedViewModel = new ViewModel2();
break;
}
}
XAML 边 (...)
<Button Command="{Binding NavigationController}" CommandParameter="1" />
<ContentControl Content="{Binding SelectedViewModel}" />
到目前为止一切顺利,我相信这是一个很好的策略。 但是对于方法 2,我有适当的“父”用户控件 selected,按钮点击以不同的方式绑定: XAML
<Button cal:Message.Attach="ShowUserControl3()"/>
虚拟机
public object SelectedActionViewModel
{
get => _selectedActionViewModel;
set
{
_selectedActionViewModel = value;
}
}
public void ShowUserControl3()
{
_selectedActionViewModel = new VMusercontrol3();
OnPropertyChanged(nameof(SelectedActionViewModel));
}
第二种方法效果很好.. 在我第一次或第二次单击按钮时。在那之后,OnPropertyChanged
一直传递 null 并且不再 select 正确的用户控件。我在这里错过了什么?
额外的问题:如何从 UserControl4 中 select UserControl3?
编辑:所有用户控件都继承自 BaseViewModel,这就是奇怪的地方,因为 propertyChanged 为 null
public class BaseViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public event EventHandler ClosingRequest;
protected void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
希望我正确理解了你的问题。实现此目的的更简单方法是使用 Caliburn Micro 的内置支持。例如,将您的 shell 视图模型修改为
public class ShellViewModel:Conductor<object> // Replace object with your base viewmodel if any
{
private UserControl1ViewModel _uc1Instance;
public UserControl1ViewModel UC1Instance => _uc1Instance ?? (_uc1Instance = new UserControl1ViewModel());
private UserControl2ViewModel _uc2Instance;
public UserControl2ViewModel UC2Instance => _uc2Instance ?? (_uc2Instance = new UserControl2ViewModel());
public void ActivateUserControl1()
{
ActivateItem(UC1Instance);
}
public void ActivateUserControl2()
{
ActivateItem(UC2Instance);
}
}
来自 Caliburn Micro 的 Conductor<T>
class 使您能够在只有一个活动的情况下处理多个屏幕(视图)。您现在可以将您的观点更改为
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<StackPanel Orientation="Vertical">
<Button x:Name="ActivateUserControl1" Content="Show UC 1"/>
<Button x:Name="ActivateUserControl2" Content="Show UC 2"/>
</StackPanel>
<ContentControl Grid.Column="1" x:Name="ActiveItem"/>
</Grid>
可以在您的 UserControl1 和 UserControl2 中重复相同的过程以实现设置 UserControl3 和 UserControl4 的选项。
关于您的第二个问题,即关于 UserControl3 和 UserControl4 之间的通信,您可以使用 EventAggregators。
您可以在 here 中找到 EventAggregator 的示例。