WPF MVVM从icommand执行更改父窗口视图模型
作者:互联网
我目前正在掌握C#WPF MVVM模式,并且偶然遇到了很大的障碍…
我正在尝试执行的LoginCommand可以成功执行后,使我能够更改父窗口的viewmodel.唯一的问题是,我无法完全想到一种在不破坏MVVM设计模式的情况下更改父窗口的视图模型的方法,因为我无法访问父窗口的ContentControl,后者将其路径设置为该窗口中活动的UserControlViewModel.
这是场景:
在App.xaml中,我们有两个DataTemplates:
< 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中,我们有:
<按钮Command =“ {Binding LoginCommand}” CommandParameter =“ {Binding ElementName = pwPasswordBoxControlInXaml}”“ />
现在,为了钱… LoginCommand:
公共无效执行(对象参数)
{
//做一些验证
//异步登录任务的东西
// …
//登录…将MainWindow的ViewModel更改为LoggedInViewModel
}
如何在不破坏MVVM模式的情况下使Execute方法更改窗口的视图模型?
到目前为止我尝试过的事情:
>使MainWindow具有可访问的静态实例单例,然后从命令中更改ViewModel属性.
>尝试在MainWindow中实现某种形式的路由命令侦听器,然后让命令触发由父窗口处理的路由命令事件.
解决方法:
我已经做了一个快速演示,展示了一种实现方法.我已尽可能简单地给出总体思路.有多种方法可以完成同一件事(例如,您可以在LoginViewModel中保存对MainWindowViewModel的引用,处理其中的所有内容,然后在MainWindowViewModel上调用方法以触发工作区更改,或者可以使用事件/消息等).
绝对是Navigation with MVVM.那是一个非常不错的介绍,当我开始使用它时会觉得很有帮助.
要摆脱这一点,关键是要有一个外部MainWindowViewModel或ApplicationViewModel来处理导航,保存对工作区的引用等.然后由您决定如何与之交互.
在下面的代码中,我省略了定义Window,UserControl等的内容,以使其更短.
窗口:
<DockPanel>
<ContentControl Content="{Binding CurrentWorkspace}"/>
</DockPanel>
MainWindowViewModel(应将其设置为Window的DataContext):
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;
}
}
}
登录视图:
在此示例中,我将LoginView上的Button绑定到Window DataContext(即MainWindowViewModel)上的LoginCommand.
<StackPanel Orientation="Vertical">
<TextBox Text="{Binding UserName}"/>
<Button Content="Login" Command="{Binding RelativeSource={RelativeSource AncestorType=Window}, Path=DataContext.LoginCommand}"/>
</StackPanel>
LoginViewModel:
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;
}
}
}
LoggedInView:
<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();
}
}
}
}
WorkspaceViewModel:
public abstract class WorkspaceViewModel : ObservableObject
{
}
然后,您可能已经实现了一些其他类(或替代方法).
ObservableObject:
public abstract class ObservableObject : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this,
new PropertyChangedEventArgs(propertyName));
}
}
RelayCommand:
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>
标签:icommand,wpf,c,mvvm 来源: https://codeday.me/bug/20191118/2029176.html