使用事件聚合器在用户控件之间导航
Navigate between UserControls with Event Aggegator
我有一个 MainWindow,我可以通过单击菜单在 UserControl 之间导航,它工作正常。
我正在使用以下模式:
https://rachel53461.wordpress.com/2011/05/08/simplemvvmexample/
在其中一个用户控件中有一个按钮。通过单击此按钮,我想导航到另一个用户控件。
我该怎么做?
主视图
<UserControl.Resources>
<DataTemplate DataType="{x:Type cvm:FirstViewModel}">
<cv:FirstView/>
</DataTemplate>
<DataTemplate DataType="{x:Type cvm:SecondViewModel}">
<cv:SecondView/>
</DataTemplate>
<cvm:MainViewModel x:Key="main"/>
</UserControl.Resources>
<Grid DataContext="{Binding Source={StaticResource main}}">
<Border Grid.Row="0">
<Menu Height="58">
<ItemsControl ItemsSource="{Binding PageViewModels}" Width="289" Height="58">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock>
<Hyperlink Command="{Binding ChangePageCommand, Mode=OneWay, Source={StaticResource main}}" CommandParameter="{Binding}" TextDecorations="{x:Null}">
<InlineUIContainer>
<TextBlock Text="{Binding Name}"/>
</InlineUIContainer>
</Hyperlink>
</TextBlock>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Menu>
</Border>
<Border Grid.Row="1" >
<ContentControl Content="{Binding CurrentUserControl}"/>
</Border>
</Grid>
MainViewModel
public class MainViewModel : ViewModelBase
{
public MainViewModel()
{
PageViewModels.Add(new FirstViewModel());
PageViewModels.Add(new SecondViewModel());
// Set starting page
CurrentUserControl = PageViewModels[0];
}
#region Fields
private List<IUserContentViewModel> _pageViewModels;
public List<IUserContentViewModel> PageViewModels
{
get
{
if (_pageViewModels == null)
_pageViewModels = new List<IUserContentViewModel>();
return _pageViewModels;
}
}
private IUserContentViewModel _currentUserControl;
public IUserContentViewModel CurrentUserControl
{
get { return _currentUserControl; }
set
{
if (value != _currentUserControl)
{
_currentUserControl = value;
OnPropertyChanged("CurrentUserControl");
}
}
}
#region Methods
private void ChangeViewModel(IUserContentViewModel viewModel)
{
if (!PageViewModels.Contains(viewModel))
PageViewModels.Add(viewModel);
CurrentUserControl = PageViewModels
.FirstOrDefault(vm => vm == viewModel);
}
#endregion
private ICommand _changePageCommand;
#endregion
public ICommand ChangePageCommand
{
get
{
if (_changePageCommand == null)
{
_changePageCommand = new RelayCommand(
p => ChangeViewModel((IUserContentViewModel)p),
p => p is IUserContentViewModel);
}
return _changePageCommand;
}
}
}
第二视图
<Grid Background="Blue">
<Button /> <!-- Going to ThirdView?????????-->
</Grid>
您必须通过按钮调用 ChangePageCommand
:
<Button DataContext="{Binding Source={StaticResource main}}"
Command="{Binding ChangePageCommand"}
CommandParameter="{Binding PageViewModels[2]}">
我假设您的 FirstViewModel
存储在 PageViewModels[0]
,您的 SecondViewModel
存储在 PageViewModels[1]
。
您还必须为您的 ThirdViewModel
创建一个 ThirdView
link,因为您的其他两个 Views/ViewModels:
<UserControl.Resources>
...
<DataTemplate DataType="{x:Type cvm:ThirdViewModel}">
<cv:ThirdView/>
</DataTemplate>
</UserControl.Resources>
作为建议,您可以在代码的开头设置 UserControl DataContext,而不是在任何 UIElement(在您的情况下为 Button 和 Grid)中使用它,如下所示:
<UserControl.DataContext>
<cvm:MainViewModel />
</UserControl.DataContext>
编辑>>>>
忘了说您还必须将 ThirdViewModel 添加到 PageViewModels 集合中:
PageViewModels.Add(new ThirdViewModel());
我终于有了解决方案。
我在 Prism 6 中使用事件聚合器。
首先我创建了一个单例。
internal sealed class ApplicationService
{
private ApplicationService() { }
private static readonly ApplicationService _instance = new ApplicationService();
internal static ApplicationService Instance { get { return _instance; } }
private IEventAggregator _eventAggregator;
internal IEventAggregator EventAggregator
{
get
{
if (_eventAggregator == null)
_eventAggregator = new EventAggregator();
return _eventAggregator;
}
}
}
然后public class GoToThird : PubSubEvent<TEvent> { }
在 MainViewModel
我订阅了活动并添加了我的 ThirdViewModel()
。
public class MainViewModel : ViewModelBase
{
protected readonly IEventAggregator _eventAggregator;
public MainViewModel(IEventAggregator eventAggregator)
{
PageViewModels.Add(new FirstViewModel());
PageViewModels.Add(new SecondViewModel(ApplicationService.Instance.EventAggregator)));
PageViewModels.Add(new ThirdViewModel());
// Set starting page
CurrentUserControl = PageViewModels[0];
this._eventAggregator = eventAggregator;
}
private void GoToThird()
{
CurrentUserControl = PageViewModels[2];
}
}
最后我在 SecondViewModel()
中发布了活动
public class SecondViewModel
{
protected readonly IEventAggregator _eventAggregator;
public SecondViewModel(IEventAggregator eventAggregator)
{
this._eventAggregator = eventAggregator;
}
private void Go()
{
_eventAggregator.GetEvent<GoToThird>().Publish();
}
private ICommand goToThirdCommand;
public ICommand GoToThirdCommand
{
get
{
return goToThirdCommand ?? (goToThirdCommand = new RelayCommand(p => this.Go(), p => this.CanGo()));
}
}
private bool CanGo()
{
return true;
}
}
非常感谢 Rachel 和 Kirenenko
我有一个 MainWindow,我可以通过单击菜单在 UserControl 之间导航,它工作正常。
我正在使用以下模式:
https://rachel53461.wordpress.com/2011/05/08/simplemvvmexample/
在其中一个用户控件中有一个按钮。通过单击此按钮,我想导航到另一个用户控件。
我该怎么做?
主视图
<UserControl.Resources>
<DataTemplate DataType="{x:Type cvm:FirstViewModel}">
<cv:FirstView/>
</DataTemplate>
<DataTemplate DataType="{x:Type cvm:SecondViewModel}">
<cv:SecondView/>
</DataTemplate>
<cvm:MainViewModel x:Key="main"/>
</UserControl.Resources>
<Grid DataContext="{Binding Source={StaticResource main}}">
<Border Grid.Row="0">
<Menu Height="58">
<ItemsControl ItemsSource="{Binding PageViewModels}" Width="289" Height="58">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock>
<Hyperlink Command="{Binding ChangePageCommand, Mode=OneWay, Source={StaticResource main}}" CommandParameter="{Binding}" TextDecorations="{x:Null}">
<InlineUIContainer>
<TextBlock Text="{Binding Name}"/>
</InlineUIContainer>
</Hyperlink>
</TextBlock>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Menu>
</Border>
<Border Grid.Row="1" >
<ContentControl Content="{Binding CurrentUserControl}"/>
</Border>
</Grid>
MainViewModel
public class MainViewModel : ViewModelBase
{
public MainViewModel()
{
PageViewModels.Add(new FirstViewModel());
PageViewModels.Add(new SecondViewModel());
// Set starting page
CurrentUserControl = PageViewModels[0];
}
#region Fields
private List<IUserContentViewModel> _pageViewModels;
public List<IUserContentViewModel> PageViewModels
{
get
{
if (_pageViewModels == null)
_pageViewModels = new List<IUserContentViewModel>();
return _pageViewModels;
}
}
private IUserContentViewModel _currentUserControl;
public IUserContentViewModel CurrentUserControl
{
get { return _currentUserControl; }
set
{
if (value != _currentUserControl)
{
_currentUserControl = value;
OnPropertyChanged("CurrentUserControl");
}
}
}
#region Methods
private void ChangeViewModel(IUserContentViewModel viewModel)
{
if (!PageViewModels.Contains(viewModel))
PageViewModels.Add(viewModel);
CurrentUserControl = PageViewModels
.FirstOrDefault(vm => vm == viewModel);
}
#endregion
private ICommand _changePageCommand;
#endregion
public ICommand ChangePageCommand
{
get
{
if (_changePageCommand == null)
{
_changePageCommand = new RelayCommand(
p => ChangeViewModel((IUserContentViewModel)p),
p => p is IUserContentViewModel);
}
return _changePageCommand;
}
}
}
第二视图
<Grid Background="Blue">
<Button /> <!-- Going to ThirdView?????????-->
</Grid>
您必须通过按钮调用 ChangePageCommand
:
<Button DataContext="{Binding Source={StaticResource main}}"
Command="{Binding ChangePageCommand"}
CommandParameter="{Binding PageViewModels[2]}">
我假设您的 FirstViewModel
存储在 PageViewModels[0]
,您的 SecondViewModel
存储在 PageViewModels[1]
。
您还必须为您的 ThirdViewModel
创建一个 ThirdView
link,因为您的其他两个 Views/ViewModels:
<UserControl.Resources>
...
<DataTemplate DataType="{x:Type cvm:ThirdViewModel}">
<cv:ThirdView/>
</DataTemplate>
</UserControl.Resources>
作为建议,您可以在代码的开头设置 UserControl DataContext,而不是在任何 UIElement(在您的情况下为 Button 和 Grid)中使用它,如下所示:
<UserControl.DataContext>
<cvm:MainViewModel />
</UserControl.DataContext>
编辑>>>>
忘了说您还必须将 ThirdViewModel 添加到 PageViewModels 集合中:
PageViewModels.Add(new ThirdViewModel());
我终于有了解决方案。
我在 Prism 6 中使用事件聚合器。
首先我创建了一个单例。
internal sealed class ApplicationService
{
private ApplicationService() { }
private static readonly ApplicationService _instance = new ApplicationService();
internal static ApplicationService Instance { get { return _instance; } }
private IEventAggregator _eventAggregator;
internal IEventAggregator EventAggregator
{
get
{
if (_eventAggregator == null)
_eventAggregator = new EventAggregator();
return _eventAggregator;
}
}
}
然后public class GoToThird : PubSubEvent<TEvent> { }
在 MainViewModel
我订阅了活动并添加了我的 ThirdViewModel()
。
public class MainViewModel : ViewModelBase
{
protected readonly IEventAggregator _eventAggregator;
public MainViewModel(IEventAggregator eventAggregator)
{
PageViewModels.Add(new FirstViewModel());
PageViewModels.Add(new SecondViewModel(ApplicationService.Instance.EventAggregator)));
PageViewModels.Add(new ThirdViewModel());
// Set starting page
CurrentUserControl = PageViewModels[0];
this._eventAggregator = eventAggregator;
}
private void GoToThird()
{
CurrentUserControl = PageViewModels[2];
}
}
最后我在 SecondViewModel()
public class SecondViewModel
{
protected readonly IEventAggregator _eventAggregator;
public SecondViewModel(IEventAggregator eventAggregator)
{
this._eventAggregator = eventAggregator;
}
private void Go()
{
_eventAggregator.GetEvent<GoToThird>().Publish();
}
private ICommand goToThirdCommand;
public ICommand GoToThirdCommand
{
get
{
return goToThirdCommand ?? (goToThirdCommand = new RelayCommand(p => this.Go(), p => this.CanGo()));
}
}
private bool CanGo()
{
return true;
}
}
非常感谢 Rachel 和 Kirenenko