gpt4 book ai didi

c# - WPF MVVM 从 icommand 执行更改父窗口 View 模型

转载 作者:行者123 更新时间:2023-11-30 16:02:25 28 4
gpt4 key购买 nike

我目前正在掌握 C# WPF MVVM 模式,并且偶然发现了一个相当大的障碍...

我想做的是触发 LoginCommand成功执行后将允许我更改父窗口的 View 模型。唯一的问题是我想不出一种在不破坏 MVVM 设计模式的情况下更改父窗口 View 模型的方法,因为我无法访问父窗口的 ContentControl。将其路径设置为事件 UserControlViewModel在窗口中。

场景如下:

在我们的 App.xaml我们有两个数据模板:
<DataTemplate DataType="{x:Type ViewModels:LoginViewModel}">
<Views:LoginView />
</DataTemplate>
<DataTemplate DataType="{x:Type ViewModels:LoggedInViewModel}">
<Views:LoggedView />
</DataTemplate>

在我们的 MainWindow我们有:
<ContentControl Content="{Binding ViewModel}" />
MainWindow后面的代码将设置 ViewModel = LoginViewModel

在我们的 LoginViewModel我们有:
<Button Command="{Binding LoginCommand}" CommandParameter="{Binding ElementName=pwPasswordBoxControlInXaml}" />

现在为了钱... LoginCommand :
public void Execute(object parameter)
{
// Do some validation
// Async login task stuff
// ...
// Logged in... change the MainWindow's ViewModel to the LoggedInViewModel
}

如何在不破坏 MVVM 模式的情况下使 Execute 方法更改窗口的 View 模型?

到目前为止我尝试过的事情:

  • 让 MainWindow 有一个我可以访问的静态实例单例,然后更改 ViewModel来自命令的属性。
  • 尝试在主窗口中实现某种形式的路由命令监听器,然后让命令触发路由命令事件以由父窗口处理。

最佳答案

我做了一个快速演示来展示一种方法。我尽可能简单地给出了总体思路。有很多不同的方法可以完成同一件事(例如,您可以在 LoginViewModel 中保存对 MainWindowViewModel 的引用,处理那里的所有内容,然后调用 MainWindowViewModel< 上的方法 触发工作区更改,或者您可以使用事件/消息等)。

一定要读一读 Navigation with MVVM尽管。这是一个非常好的介绍,我在开始使用它时发现它很有帮助。

要摆脱这一点的关键是拥有一个外部 MainWindowViewModelApplicationViewModel 来处理导航、保存对工作区的引用等。然后选择如何与此互动取决于您。

在下面的代码中,我省略了定义 WindowUserControl 等的困惑部分,以使其更短。

窗口:

<DockPanel>
<ContentControl Content="{Binding CurrentWorkspace}"/>
</DockPanel>

MainWindowViewModel(这应该设置为 WindowDataContext):

public class MainWindowViewModel : ObservableObject
{
LoginViewModel loginViewModel = new LoginViewModel();
LoggedInViewModel loggedInViewModel = new LoggedInViewModel();

public MainWindowViewModel()
{
CurrentWorkspace = loginViewModel;

LoginCommand = new RelayCommand((p) => DoLogin());
}

private WorkspaceViewModel currentWorkspace;
public WorkspaceViewModel CurrentWorkspace
{
get { return currentWorkspace; }
set
{
if (currentWorkspace != value)
{
currentWorkspace = value;
OnPropertyChanged();
}
}
}

public ICommand LoginCommand { get; set; }

public void DoLogin()
{
bool isValidated = loginViewModel.Validate();
if (isValidated)
{
CurrentWorkspace = loggedInViewModel;
}
}
}

登录 View :

在此示例中,我将 LoginView 上的 Button 绑定(bind)到 Window 上的 LoginCommand DataContext(即 MainWindowViewModel)。

<StackPanel Orientation="Vertical">
<TextBox Text="{Binding UserName}"/>
<Button Content="Login" Command="{Binding RelativeSource={RelativeSource AncestorType=Window}, Path=DataContext.LoginCommand}"/>
</StackPanel>

登录 View 模型:

public class LoginViewModel : WorkspaceViewModel
{
private string userName;
public string UserName
{
get { return userName; }
set
{
if (userName != value)
{
userName = value;
OnPropertyChanged();
}
}
}

public bool Validate()
{
if (UserName == "bob")
{
return true;
}
else
{
return false;
}
}
}

登录 View :

<StackPanel Orientation="Vertical">
<TextBox Text="{Binding RestrictedData}"/>
</StackPanel>

LoggedInViewModel:

public class LoggedInViewModel : WorkspaceViewModel
{
private string restrictedData = "Some restricted data";
public string RestrictedData
{
get { return restrictedData; }
set
{
if (restrictedData != value)
{
restrictedData = value;
OnPropertyChanged();
}
}
}
}

工作区 View 模型:

public abstract class WorkspaceViewModel : ObservableObject
{
}

然后是您可能已经实现(或替代)的一些其他类。

可观察对象:

public abstract class ObservableObject : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this,
new PropertyChangedEventArgs(propertyName));
}
}

中继命令:

public class RelayCommand : ICommand
{
private readonly Action<object> execute;
private readonly Predicate<object> canExecute;

public RelayCommand(Action<object> execute)
: this(execute, null)
{ }

public RelayCommand(Action<object> execute, Predicate<object> canExecute)
{
if (execute == null)
{
throw new ArgumentNullException("execute");
}

this.execute = execute;
this.canExecute = canExecute;
}

public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}

[DebuggerStepThrough]
public bool CanExecute(object parameter)
{
return canExecute == null ? true : canExecute(parameter);
}

public void Execute(object parameter)
{
execute(parameter);
}
}

App.Xaml:

    <DataTemplate DataType="{x:Type ViewModels:LoginViewModel}">
<Views:LoginView />
</DataTemplate>
<DataTemplate DataType="{x:Type ViewModels:LoggedInViewModel}">
<Views:LoggedInView />
</DataTemplate>

关于c# - WPF MVVM 从 icommand 执行更改父窗口 View 模型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37625124/

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