在 UserControl WPF MVVM caliburn 内的 UserControl 之间切换

Posted

技术标签:

【中文标题】在 UserControl WPF MVVM caliburn 内的 UserControl 之间切换【英文标题】:Switch between UserControls inside UserControl WPF MVVM caliburn 【发布时间】:2021-06-28 01:31:47 【问题描述】:

我需要通过单击按钮从一个用户控件导航到另一个用户控件,并且我使用了两种不同的方法。

方法 1:我有一个带有一些按钮的主窗口,这些按钮将使用导航控制器选择我的“父”用户控件视图模型。

    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,我选择了正确的“父”用户控件,按钮单击以不同的方式绑定: 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 并且不会再选择正确的用户控件。我在这里错过了什么?

额外问题:如何从 UserControl4 中选择 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));
        
    

【问题讨论】:

“继续传递null”,就像PropertyChanged 事件中的null 一样?取消选择视图时如何单击按钮? @mm8 抱歉忘记提及用户控件继承自 BaseViewModel 是 INotifyPropertyChanged (这就是它传递 null 的地方)。我编辑了帖子 【参考方案1】:

希望我正确理解了您的问题。实现这一点的更简单方法是使用 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&lt;T&gt; 类使您能够处理多个屏幕(视图),其中只有一个处于活动状态。您现在可以将视图更改为

<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 的示例。

【讨论】:

我刚刚用 Conductor 尝试了你的建议,它的工作方式相同。视图之间的第一次导航可以正常工作,但是如果点击太“快”,则不会发生任何变化(并且在 viewModel 端,实例已初始化等) 虽然,如果我强制执行“ActivateItem(myViewModel)”它可以正常工作。我不知道它是否有帮助.. @i.Dio 对不起,这是我的错误,您需要使用 ActivateItem。这样更好。,我已经更正了答案 查看参考这里caliburnmicro.com/documentation/composition

以上是关于在 UserControl WPF MVVM caliburn 内的 UserControl 之间切换的主要内容,如果未能解决你的问题,请参考以下文章

如何在 MVVM 中的 UserControl 之间进行通信 - WPF 应用程序

在 UserControl WPF MVVM caliburn 内的 UserControl 之间切换

wpf mvvm使用问题集锦

使用 MVVM 在 MainWindow 上绑定 UserControl 视图模型

WPF MVVM 通过事件将 UserControl 从一个 ObservableCollection 移动到另一个

如何从作为wpf mvvm模式中的窗口打开的视图模型中关闭用户控件?