创建抽象 ViewModels wpf

Creating abstract ViewModels wpf

我正在尝试创建一个抽象 ViewModel class,以及几个将继承抽象 ViewModel 并实现它的 ViewModel classes。

到目前为止,我使用的是 RelayCommand,但无法编译。

这样的事情能做吗?

我正在添加我的代码:

中继命令class:

public class RelayCommand : ICommand
{
    private readonly Action<object> m_executeAction;
    private readonly Predicate<object> m_canExecute;

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

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

        m_executeAction = executeAction;
        m_canExecute = canExecute;
    }

    public bool CanExecute(object canExecuteParameter)
    {
        return (m_canExecute == null || m_canExecute(canExecuteParameter));
    }

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

    public void Execute(object canExecuteParameter)
    {
        m_executeAction(canExecuteParameter);
    }
}

ViewModelsBase class:

public abstract class ViewModelBase : INotifyPropertyChanged, IDisposable
{
    public event PropertyChangedEventHandler PropertyChanged;

    public void OnPropertyChanged(string propertyName)
    {
        if (PropertyChanged == null) return;
        PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }

    protected virtual void OnDispose() {}

    public void Dispose()
    {
        OnDispose();
    }
}

MainViewModel class:

public class MainWindowViewModel : ViewModelBase
{
    private IViewModel m_testViewModel;
    private bool m_isFirstPlugin = true;

    public MainWindowViewModel()
    {
        TestViewModel = new FirstViewModel();
    }

    public IViewModel TestViewModel
    {
        get { return m_testViewModel; }
        set
        {
            m_testViewModel = value;
            OnPropertyChanged("NewViewModel");
        }
    }

    private ICommand m_changeCommand;

    public ICommand ChangeCommand
    {
        get { return m_changeCommand ?? (m_changeCommand = new RelayCommand(Change)); }
        set { m_changeCommand = value; }
    }

    private void Change(object parameter)
    {
        TestViewModel.Dispose();
        TestViewModel = null;

        if (m_isFirstPlugin)
            TestViewModel = new SecondViewModel();
        else
            TestViewModel = new FirstViewModel();

        m_isFirstPlugin = !m_isFirstPlugin;
    }
}

IViewModel class:

public class IViewModel : ViewModelBase
{
    private ICommand m_testCommand;

    public ICommand TestCommand
    {
        get { return m_testCommand ?? (m_testCommand = new RelayCommand(Test)); }
        set { m_testCommand = value; }
    }

    protected virtual void Test(object parameter) { }
}

FirstViewModel class:

public class FirstViewModel : IViewModel
{
    protected override void Test(object parameter)
    {
        MessageBox.Show("On First Plugin.");
    }
}

SecondViewModel class:

public class SecondViewModel : IViewModel
{
    protected override void Test(object parameter)
    {
        MessageBox.Show("On Second Plugin.");
    }
}

Xaml:

<Window x:Class="MvvmInheritence.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Testing" Height="100" Width="180"
    xmlns:Local="clr-namespace:MvvmInheritence" WindowStartupLocation="CenterScreen" Background="Transparent">
    <Window.DataContext>
        <Local:MainWindowViewModel />
    </Window.DataContext>
    <Grid x:Name="MainGrid">
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition />
        </Grid.RowDefinitions>
        <Button x:Name="TestButton" Content="Test!" Foreground="DarkRed" Background="LightBlue"  Height="25" Width="100" Command="{Binding TestCommand, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" DataContext="{Binding TestViewModel, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Grid.Row="0"/>
        <Button x:Name="ChangeButton" Content="Change Plugin" Foreground="DarkRed" Background="LightBlue"  Height="25" Width="100" Command="{Binding ChangeCommand, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Grid.Row="1"/>
    </Grid>
</Window>

此代码确实可以编译(我进行了更改以使其工作)但出于某种原因,我总是得到 "On First Plugin" 即使 Change 函数被调用,并且 ViewModel 已正确更改。

我错过了什么?

自定义 MVVM 从创建实现 INotifyPropertyChanged 接口的抽象 ViewModelBase class 开始。

但是,根据您的 RelayCommand 评论,我假设您使用的是 MVVM Light 框架?然后而不是实施 INotifyPropertyChanged 你的抽象 ViewModel 应该继承自 MVVM Lights ViewModelBase class.

RelayCommands 将是您的 ViewModelBase 的属性,而不是您继承自的基础 class。

好的,我找到了故障。

MainViewModel class 中,TestViewModel 属性 应更改为:

public IViewModel TestViewModel
{
    get { return m_testViewModel; }
    set
    {
        m_testViewModel = value;
        OnPropertyChanged("NewViewModel");
    }
}

收件人:

public IViewModel TestViewModel
{
    get { return m_testViewModel; }
    set
    {
        m_testViewModel = value;
        OnPropertyChanged("TestViewModel");
    }
}