其他分享
首页 > 其他分享> > WPF MVVM从icommand执行更改父窗口视图模型

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