【问题标题】:Creating abstract ViewModels wpf创建抽象视图模型 wpf
【发布时间】:2016-04-03 09:48:13
【问题描述】:

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

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

这样的事情能做到吗?

我正在添加我的代码:

RelayCommand 类:

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 类:

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 类:

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 类:

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 类:

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

SecondViewModel 类:

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>

此代码确实可以编译(我进行了更改以使其工作),但由于某种原因,即使调用了 Change 函数并且正确更改了 ViewModel,我总是得到“在第一个插件上”。

我错过了什么?

【问题讨论】:

  • 你有什么错误?您还可以添加基本 ViewModel 类和 RelayCommand 类的代码吗?
  • 我一直这样做。您是在使用 MVVM 库,还是只是为您的项目滚动您自己的实现?此外,发布无法编译的最小样本对于让我们帮助您大有帮助。您很可能正在实现一个接口并且缺少该方法/属性的抽象声明。
  • 更新了我的问题。

标签: c# wpf inheritance viewmodel relaycommand


【解决方案1】:

好的,我发现了故障。

MainViewModel 类中,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");
    }
}

【讨论】:

    【解决方案2】:

    自定义 MVVM 从创建一个抽象的 ViewModelBase 类开始,该类实现了INotifyPropertyChanged 接口。

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

    RelayCommands 将是您的 ViewModelBase 的属性,而不是您继承的基类。

    【讨论】:

    • 更新了我的问题。
    猜你喜欢
    • 2020-10-03
    • 1970-01-01
    • 2019-11-30
    • 1970-01-01
    • 1970-01-01
    • 2020-09-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多