Caliburn Micro 内容控制导航
Caliburn Micro content control navigation
我正在为这个项目使用 Caliburn Micro。
我有我的 ShellView 和我的 contentcontrol:
<ContentControl x:Name="ActiveItem"
Grid.Row="0" Grid.Column="0" />
在 ShellViewModel 中,我用它来显示我的用户控件登录视图:
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}" />
从 ShellViewModel 派生的 LoginViewModel:
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());
}
}
您可以使用 EventAggregator 将指示性消息从 LoginViewModel 发布到 ShellViewModel 以更新 UI 来实现此目的。
首先,您需要定义一条消息 class,它会告诉 ShellViewModel 需要更改哪个 ViewModel。例如,
public class ActionInvokedMessage
{
public Screen Page { get; set; }
}
页面 属性 将指示需要加载哪个屏幕。现在,您可以按如下方式更改您的 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 方法加载注册页面的合适位置。
您可以创建导航界面并在视图模型中使用它在应用程序中导航。
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 但您可以设计更好地描述导航请求的类型,以便您可以传递附加参数。
我正在为这个项目使用 Caliburn Micro。 我有我的 ShellView 和我的 contentcontrol:
<ContentControl x:Name="ActiveItem"
Grid.Row="0" Grid.Column="0" />
在 ShellViewModel 中,我用它来显示我的用户控件登录视图:
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}" />
从 ShellViewModel 派生的 LoginViewModel:
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());
}
}
您可以使用 EventAggregator 将指示性消息从 LoginViewModel 发布到 ShellViewModel 以更新 UI 来实现此目的。
首先,您需要定义一条消息 class,它会告诉 ShellViewModel 需要更改哪个 ViewModel。例如,
public class ActionInvokedMessage
{
public Screen Page { get; set; }
}
页面 属性 将指示需要加载哪个屏幕。现在,您可以按如下方式更改您的 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 方法加载注册页面的合适位置。
您可以创建导航界面并在视图模型中使用它在应用程序中导航。
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 但您可以设计更好地描述导航请求的类型,以便您可以传递附加参数。