Создание абстрактных ViewModels wpf
Я пытаюсь создать абстрактный класс 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>
Этот код компилируется (я внес изменения, чтобы он работал), но по какой-то причине я всегда получаю "On First Plugin", хотя Change
функция вызывается, а ViewModel
правильно изменен.
Что мне не хватает?
2 ответа
Хорошо, я нашел глюк.
Int 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");
}
}
Пользовательский MVVM начинается с создания абстрактного класса ViewModelBase, который реализует INotifyPropertyChanged
интерфейс.
Тем не менее, на основе вашего RelayCommand
комментарий Я предполагаю, что вы используете MVVM Light Framework? Тогда вместо реализации INotifyPropertyChanged
ваш абстрактный ViewModel должен наследовать от MVVM Lights ViewModelBase
учебный класс.
RelayCommands будут свойствами вашего ViewModelBase, а не базового класса, от которого вы наследуете.