C# 在UserControl WPF MVVM caliburn中的UserControl之间切换

C# 在UserControl WPF MVVM caliburn中的UserControl之间切换,c#,wpf,caliburn.micro,C#,Wpf,Caliburn.micro,我需要通过单击按钮从一个用户控件导航到另一个用户控件,我使用两种不同的方法。 方法1:我有一个带有一些按钮的主窗口,可以使用导航控制器选择我的“父”用户控件视图模型 public NavigationController(MainWindowViewModel viewModel) { this.viewModel = viewModel; } public void Execute(object parameter) {

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

方法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侧(…)

第二种方法很好用。。在第一次或第二次单击按钮时。在此之后,
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));
        }
    }
}

我希望我正确理解了你的问题。实现这一点的一个简单方法是使用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);
        }
}
public类ShellViewModel:Conductor//如果有,用基本viewmodel替换对象
{
私有用户控制1视图模型_uc1实例;
public UserControl1ViewModel UC1Instance=>\u UC1Instance??(\u UC1Instance=new UserControl1ViewModel());
私有用户控制2视图模型_uc2实例;
public UserControl2ViewModel UC2Instance=>\u UC2Instance??(\u UC2Instance=new UserControl2ViewModel());
公共无效激活UserControl1()
{
激活时间(UC1Instance);
}
公共无效激活UserControl2()
{
激活时间(UC2持续时间);
}
}
Caliburn Micro的
导体
类使您能够在只有一个活动屏幕的情况下处理多个屏幕(视图)。您现在可以根据需要更改视图

<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之间的通信,您可以利用


您可以在中找到EventAggregator的示例。

“保持传递
null
”,如
属性更改中的
事件为
null
?取消选择视图后,如何单击该按钮?@mm8抱歉,忘记提及用户控件继承自INotifyPropertyChanged的BaseViewModel(这就是它传递null的地方)。我编辑了这篇帖子。我刚刚试过你对指挥的建议,效果也一样。视图之间的第一次导航工作正常,但如果单击太“快”,则不会发生任何更改(并且在viewModel端实例已初始化等),尽管如果强制执行“ActivateItem(myViewModel)”,它工作正常。我不知道这是否有帮助。@I.Dio对不起,这是我的错误,你需要使用ActivateItem。这样更好。我已经更正了答案。请看这里的参考资料
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));
        }
    }
}
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);
        }
}
<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>