【问题标题】:Caliburn Micro content control navigationCaliburn Micro 内容控制导航
【发布时间】:2019-10-30 12:06:56
【问题描述】:

我在这个项目中使用 caliburn micro。 我有我的 ShellView 和我的 contentcontrol:

<ContentControl x:Name="ActiveItem"
                        Grid.Row="0" Grid.Column="0" />

在 ShellViewModel 中,我用它来显示我的用户控件 LoginView:

 public class ShellViewModel : Conductor<object>
    {
        public ShellViewModel()
        {
            ActivateItem(new LoginViewModel());
        }

        public void ShowSignUp()
        {
            ActivateItem(new SignUpViewModel());
        }
    }

但是,我无法使用按钮从 LoginView 导航到 SignUpView:

<!-- Row 4 -->
<Button x:Name="ShowSignUp"
        Content="Sign Up Now!"
        Grid.Row="3" Grid.Column="1"
        Style="{StaticResource LoginBtnsStyle}" />

LoginViewModel 派生自 ShellViewModel:

public class LoginViewModel : ShellViewModel
    {

    }

如何使用 LoginView 上的按钮从 LoginView 导航到 SignUpView? 我没有收到任何错误,只是没有改变视图。 我也尝试将 ShowSignUp() 放在 LoginViewModel 上,但没有成功。

更新 1 ShellViewModel:

public class ShellViewModel : Conductor<object>, IHandle<ActionInvokedMessage>
    {
        DispatcherTimer dt = new DispatcherTimer();
        private SplashScreenViewModel _splashVM;
        private LoginViewModel _loginVM;
        private SignUpViewModel _signUpVM;
        private IEventAggregator _eventAggregator;

        public ShellViewModel(SplashScreenViewModel splashVM, LoginViewModel loginVM, SignUpViewModel signUpVM)
        {
            _loginVM = loginVM;
            _signUpVM = signUpVM;
            _splashVM = splashVM;
            ActivateItem(_splashVM);

            dt.Tick += new EventHandler(Dt_Tick);
            dt.Interval = new TimeSpan(0, 0, 2);
            dt.Start();
        }

        private void Dt_Tick(object sender, EventArgs e)
        {
            dt.Stop();
            ActivateItem(_loginVM);
        }

        public ShellViewModel(IEventAggregator eventAggregator)
        {
            _eventAggregator = eventAggregator;
            _eventAggregator.Subscribe(this);
            ActivateItem(new LoginViewModel(_eventAggregator));
        }

        public void Handle(ActionInvokedMessage message)
        {
            ActivateItem(message.Page);
        }

        public void ShowSignUp()
        {
            ActivateItem(new SignUpViewModel());
        }



    }

【问题讨论】:

    标签: wpf mvvm caliburn.micro


    【解决方案1】:

    您可以使用EventAggregator 将指示性消息从 LoginViewModel 发布到 ShellViewModel 以更新 UI。

    首先,您需要定义一个消息类,它会告诉 ShellViewModel 需要更改哪个 ViewModel。例如,

    public class ActionInvokedMessage
        {
            public Screen Page { get; set; }
        }
    

    Page 属性将指示需要加载哪个屏幕。现在,您可以将 LoginViewModel 更改为以下内容。

    public class LoginViewModel: Screen
        {
            private IEventAggregator _eventAggregator;
            public LoginViewModel(IEventAggregator eventAggregator)
            {
    
                _eventAggregator = eventAggregator;
                _eventAggregator.Subscribe(this);
            }
    
            public void ShowSignUp()
            {
                _eventAggregator.PublishOnUIThread(new ActionInvokedMessage { Page = new SignupViewModel() }); ;
            }
        }
    

    PublishOnUIThread 方法将向消息类型 ActionInvokedMessage 的所有侦听器广播一条消息以进行更改。下一步是确保 ShellViewModel 能够监听更改。

    public class ShellViewModel : Conductor<object>, IHandle<ActionInvokedMessage>
        {
            private IEventAggregator _eventAggregator;
            public ShellViewModel(IEventAggregator eventAggregator)
            {
                _eventAggregator = eventAggregator;
                _eventAggregator.Subscribe(this);
                ActivateItem(new LoginViewModel(_eventAggregator));
            }
    
            public void Handle(ActionInvokedMessage message)
            {
                ActivateItem(message.Page);
            }
    
            public void ShowSignUp()
            {
                ActivateItem(new SignupViewModel());
            }
    
    
        }
    

    IHandle 接口的实现允许我们处理当 ShellViewModel 收到 ActionInvokedMessage 时需要执行的操作。从代码中可以看出,这将是使用 ActivateItem 方法加载注册页面的合适位置。

    【讨论】:

    • 我得到一个 system.nullreferenceexception: object reference not set to an instance of an object. public void ShowSignUp() { _eventAggregator.PublishOnUIThread(new ActionInvokedMessage { Page = new SignUpViewModel() }); ; }
    • @Martin 请检查一下_eventAggregator 是否已初始化?
    • @Martin 如果不是 _eventAggregator,您能否调试并查看 null 到底是什么。
    • 对不起,我的错。 _eventAggregator 为空。
    • @Martin 这就是原因。你需要初始化它。您可以在构造函数中这样做,如上面的代码所示。
    【解决方案2】:

    您可以创建一个导航界面并在视图模型中使用它来导航应用程序。

    interface INavigation {
        void NavigateTo(System.Type typeId);
    }
    
    class ShellViewModel: Conductor<object>,  INavigation  {
    
        private List<object> pages = new List<Object>();
    
        public ShellViewModel() {
            pages.Add(new SignupViewModel(this));
            pages.Add(new LoginViewModel(this));
        }
    
        void NavigateTo(System.Type typeId) {
            var page = pages.Where(x => x.GetType() == typeId).FirstOrDefault()
            ActivateItem(page);
        }
    }
    
    class SignupViewModel {
        public SignupViewModel(INavigation navigation) {
            this.ShowLoginCommand= new NavigateCommand<LoginViewModel>(navigation);
        }
    }
    
    class LoginViewModel {
        public LoginViewModel (INavigation navigation) {
            this.ShowSignUpCommand = new NavigateCommand<SignupViewModel>(navigation);
        }
    }
    

    导航命令的实现方式如下:

    public class NavigateCommand<T> : ICommand
    {
        public event EventHandler CanExecuteChanged;
        private readonly INavigation navigation;
    
        public NavigateCommand(INavigation navigation)
        {
            this.navigation = navigation;
        }
    
        public bool CanExecute(object parameter) => true;
        public void Execute(object parameter) => this.navigation.NavigateTo(typeof(T));
    }
    

    我在这里传递 System.Type,但您可以设计更好地描述导航请求的类型,以便您可以传递附加参数。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-02-09
      • 2016-03-24
      • 2015-07-07
      • 1970-01-01
      • 1970-01-01
      • 2018-07-23
      • 1970-01-01
      相关资源
      最近更新 更多