创建抽象 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");
}
}
我正在尝试创建一个抽象 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");
}
}