gpt4 book ai didi

c# - 如何使用单击处理程序和命令在 WPF MVVM 中打开另一个 View ? (我的解决方案合理吗?)

转载 作者:行者123 更新时间:2023-12-03 10:36:04 24 4
gpt4 key购买 nike

我正在编写一个有两个窗口的 WPF 应用程序。

我有一个 MainWindowViewModel包含另外两个 View 模型:AllTagsViewModelPlotViewModel .

public AllTagsViewModel AllTagsViewModel { get; private set; }

public PlotViewModel PlotViewModel { get; private set; }

目前,我将此解决方案用作主窗口中的单击处理程序:
private void LaunchPlotWindow_OnClick(object sender, RoutedEventArgs e)
{
if (PlotWindow.GlobalInstanceCount == 0)
{
PlotWindow plotWindow = new PlotWindow();

PlotViewModel context = GetViewModel().PlotViewModel;
plotWindow.DataContext = context;

plotWindow.Show();
}
}

我还将命令绑定(bind)到按钮。命令在 MainWindowViewModel它使用构造函数 PlotViewModel(AllTagsViewModel atvm) 实例化一个新的 PlotViewModel .

问题在于设置数据上下文的命令在单击处理程序之后执行。这意味着 PlotWindow第二次打开时按预期工作。

这个问题有什么更好的解决方案?我可以使用事件来保留 AllTagsViewModelPlotViewModel始终与 MainWindowViewModel 中的那个保持同步?我目前的解决方案感觉就像是一个黑客和非常糟糕的做法。

感谢您的建议。

最佳答案

前言:
通常你不想拥有你的 PlotViewModel 并将它传递给一个窗口,因为它使一些事情变得更加复杂。

有 View-First 和 ViewModel First 的基本方法。在 View-First 中,您创建 View (页面、窗口等)并将 ViewModel 注入(inject)其中(通常通过构造函数)。虽然这使得向它传递参数对象有点困难。

这就是 NavigationService 的来源。您通过 IoC 容器解析 View ,然后将参数传递给 ViewModel,即如果它是 UserViewModel你会通过 userId到它,ViewModel 将加载用户。

解决方案:导航服务
您可以使用现有的(Prism 或其他带有自己的导航服务的 MVVM 框架)。

如果你想要一个自己的简单的,你可以创建一个 INavigationService接口(interface)并将其注入(inject)到您的 ViewModels 中。

public interface INavigationService 
{
// T is whatever your base ViewModel class is called
void NavigateTo<T>() where T ViewModel;
void NavigateToNewWindow<T>();
void NavigateToNewWindow<T>(object parameter);
void NavigateTo<T>(object parameter);
}

并像实现它一样(我假设您使用 IoC 容器,因为 IoC 是 MVVM 的关键,用于键解耦对象。Unity IoC 容器的示例)
public class NavigationService : INavigationService
{
private IUnityContainer container;
public NavigationService(IUnityContainer container)
{
this.container = container;
}
public void NavigateToWindow<T>(object parameter) where T : IView
{
// configure your IoC container to resolve a View for a given ViewModel
// i.e. container.Register<IPlotView, PlotWindow>(); in your
// composition root
IView view = container.Resolve<T>();

Window window = view as Window;
if(window!=null)
window.Show();

INavigationAware nav = view as INavigationAware;
if(nav!= null)
nav.NavigatedTo(parameter);
}
}

// IPlotView is an empty interface, only used to be able to resolve
// the PlotWindow w/o needing to reference to it's concrete implementation as
// calling navigationService.NavigateToWindow<PlotWindow>(userId); would violate
// MVVM pattern, where navigationService.NavigateToWindow<IPlotWindow>(userId); doesn't. There are also other ways involving strings or naming
// convention, but this is out of scope for this answer. IView would
// just implement "object DataContext { get; set; }" property, which is already
// implemented Control objects
public class PlotWindow : Window, IView, IPlotView
{
}

最后你实现你的 PlotViewModel类并使用传递的参数加载对象
public class PlotViewModel : ViewModel, INotifyPropertyChanged, INavigationAware
{
private int plotId;
public void NavigatedTo(object parameter) where T : IView
{
if(!parameter is int)
return; // Wrong parameter type passed

this.plotId = (int)parameter;
Task.Start( () => {
// load the data
PlotData = LoadPlot(plotId);
});
}

private Plot plotData;
public Plot PlotData {
get { return plotData; }
set
{
if(plotData != value)
{
plotData = value;
OnPropertyChanged("PlotData");
}
}
}
}

当然可以修改 NavigationService还要设置 DataContext在里面。或者使用字符串来解析 View /窗口(例如 Prism for Windows Store Apps)。

在最终代码中,您可以通过调用 navigationService.NavigateToWindow<IPlotView>(platId); 打开窗口在您的代码中(即在 ICommand 中,它绑定(bind)到 XAML 中的按钮 Command 属性。

关于c# - 如何使用单击处理程序和命令在 WPF MVVM 中打开另一个 View ? (我的解决方案合理吗?),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28817827/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com