问题
I have a MainWindow where I navigate between UserControls by clicking on a menu and it works fine.
I am using this following pattern:
https://rachel53461.wordpress.com/2011/05/08/simplemvvmexample/
In one of those usercontrol there is a button. By clicking on this button I want to navigate to another usercontrol.
How do I do that?
MainView
<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;
}
}
}
SecondView
<Grid Background="Blue">
<Button /> <!-- Going to ThirdView?????????-->
</Grid>
回答1:
You have to call the ChangePageCommand
from your button:
<Button DataContext="{Binding Source={StaticResource main}}"
Command="{Binding ChangePageCommand"}
CommandParameter="{Binding PageViewModels[2]}">
I am assuming that you have your FirstViewModel
stored at PageViewModels[0]
, and your SecondViewModel
at PageViewModels[1]
.
You also have to create a ThirdView
link to your ThirdViewModel
, as your other two Views/ViewModels:
<UserControl.Resources>
...
<DataTemplate DataType="{x:Type cvm:ThirdViewModel}">
<cv:ThirdView/>
</DataTemplate>
</UserControl.Resources>
And just as an advice, you can set your UserControl DataContext at the start of your code, instead of using it in any UIElement(Button and Grid in your case), like this:
<UserControl.DataContext>
<cvm:MainViewModel />
</UserControl.DataContext>
EDIT>>>>
Forgot to say that you also have to add your ThirdViewModel to your PageViewModels collection:
PageViewModels.Add(new ThirdViewModel());
回答2:
I finally have my solution.
I use Event Aggregator with Prism 6.
First I create a Singleton.
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;
}
}
}
Then public class GoToThird : PubSubEvent<TEvent> { }
In MainViewModel
I subscribe to the event and add my 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];
}
}
At the end I publish the event in 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;
}
}
Big Thanks to Rachel and Kirenenko
来源:https://stackoverflow.com/questions/34431473/navigate-between-usercontrols-with-event-aggegator