-5

I'm trying to create an abstract ViewModel class, and several ViewModel classes which will inherit the abstract ViewModel and implement it.

So far I'm using RelayCommand and it doesn't compile.

Can such a thing be done?

I'm adding my code:

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);
    }
}

The 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();
    }
}

The 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>

This code does compile (I made changes to make it work) but for some reason, I'm always getting "On First Plugin" even though the Change function is called, and the ViewModel is correctly changed.

What am I missing?

Idanis
  • 1,918
  • 6
  • 38
  • 69
  • What error do you have? Also can you add code of your base ViewModel class and RelayCommand class? – Vadim Martynov Dec 29 '15 at 13:39
  • I do it all the time. Are you using an MVVM library, or just rolling your own implementation for your project? Also, posting the smallest sample of what doesn't compile goes a long way to let us help you. It's quite possible you are implementing an interface and are missing the abstract declaration for that method/property. – Berin Loritsch Dec 29 '15 at 13:41
  • Updated my question. – Idanis Dec 31 '15 at 09:14

2 Answers2

1

Custom MVVM starts with creating an abstract ViewModelBase class that implements the INotifyPropertyChanged interface.

However, based on your RelayCommand comment I assume you are using the MVVM Light framework? Then instead of implementing INotifyPropertyChanged your abstract ViewModel should inherit from MVVM Lights ViewModelBase class.

RelayCommands will be properties of your ViewModelBase not the base class you inherit from.

robaudas
  • 1,538
  • 1
  • 9
  • 12
-1

Ok, I found the glitch.

Int the MainViewModel class, the TestViewModel property should be changed from:

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

To:

public IViewModel TestViewModel
{
    get { return m_testViewModel; }
    set
    {
        m_testViewModel = value;
        OnPropertyChanged("TestViewModel");
    }
}
Idanis
  • 1,918
  • 6
  • 38
  • 69