WPF MVVM 使用文本框和 ICommand 将新对象添加到 ObservableCollection
WPF MVVM Add new object to ObservableCollection using textboxes and ICommand
WPF 和 MVVM 模式的新世界。我希望有人可以提供一个超级简单的描述,说明我如何使用文本框设置属性和通过按钮触发的命令来创建新对象并将其添加到 observableCollection。
我目前拥有的:
型号
public class CarModel : NotifyBase
{
#region Private Members
/// <summary>
/// Private members for the class Car
/// </summary>
private string _manufacturer;
private string _model;
private string _year;
private string _color;
private string _regNumber;
private EngineModel _eng;
#endregion
#region Public Properties
/// <summary>
/// Public properties for the class Car (used for view binding)
/// </summary>
public string Manufacturer {
get { return _manufacturer; }
set {
if (_manufacturer != value)
{
_manufacturer = value;
RaisePropertyChanged("Manufacturer");
}
}
}
public string Model {
get { return _model; }
set {
if (_model != value)
{
_model = value;
RaisePropertyChanged("Model");
}
}
}
.
.
.
ViewModel
class MainViewModel : NotifyBase
{
#region Private Members
/// <summary>
/// Privtae members for the class MainViewModel
/// </summary>
private ObservableCollection<CarModel> _carRegistry;
private CarModel _selectedCar;
private CarModel _car;
private ICommand _addCarCommand;
#endregion
#region Public Properties
/// <summary>
/// Public members for the class MainModelView (used for view binding)
/// </summary>
public ObservableCollection<CarModel> CarRegistry{
get { return _carRegistry; }
set {
_carRegistry = value;
RaisePropertyChanged("CarRegistry");
}
}
public CarModel SelectedCar
{
get { return _selectedCar; }
set
{
_selectedCar = value;
RaisePropertyChanged("SelectedCar");
}
}
public CarModel Car
{
get { return _car; }
set {
_car = value;
RaisePropertyChanged("Car");
}
}
public ICommand AddCarCommand
{
get {
if (_addCarCommand == null)
{
_addCarCommand = new RelayCommand(param =>new CarModel(), param => true);
}
return _addCarCommand;
}
}
#endregion
#region Constructor
/// <summary>
/// MainViewModel constructor
/// </summary>
public MainViewModel()
{
CarRegistry = new ObservableCollection<CarModel>()
{
//Dummy data
new CarModel(){Manufacturer = "Volvo", Model = "V70", Year = "2000", Color = "White", RegNumber = "CDC-123",
Engine = new EngineModel(){Serial = "END125456#", Volume = "2.0"}},
new CarModel(){Manufacturer = "Volvo", Model = "V40", Year = "2005", Color = "Black", RegNumber = "ITI-456",
Engine = new EngineModel(){Serial = "IND554567#", Volume = "1.6"}},
new CarModel(){Manufacturer = "Ford", Model = "Escort", Year = "1995", Color = "Blue", RegNumber = "GHD-777",
Engine = new EngineModel(){Serial = "GHTSJ5556#", Volume = "2.0"}},
};
}
#endregion
#region Methods
private void AddCar(object o)
{
//add new carModel to _carRegistry
}
#endregion
}
中继命令
class RelayCommand:ICommand
{
#region Private Members
readonly Action<object> _execute;
readonly Predicate<object> _canExecute;
#endregion
public RelayCommand(Action<object> execute)
: this(execute, null)
{
}
public RelayCommand(Action<object> execute, Predicate<object> canExecute)
{
if (execute == null)
throw new ArgumentNullException("execute");
_execute = execute;
_canExecute = canExecute;
}
public bool CanExecute(object parameter)
{
return _canExecute == null || _canExecute(parameter);
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public void Execute(object parameter)
{
//if(parameter != null)
_canExecute(parameter);
}
}
如果我理解正确,那么我需要将文本框绑定到 ViewModel 中的属性和一个按钮来触发 AddCarCommand
,但我不清楚它应该如何实现。任何帮助将不胜感激!!!
//内森
编辑
XAML
目前我的 xaml 看起来像这样:
<Window x:Class="CarData_Test.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:CarData_Test"
Title="Car Data Test" Height="606.645" Width="758.759">
<Window.DataContext>
<local:MainViewModel/>
</Window.DataContext>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="1" HorizontalAlignment="Left" Margin="10,10,0,0" TextWrapping="Wrap" Text="CAR INFORMATION" VerticalAlignment="Top" FontWeight="Bold" FontFamily="Segoe WP Light" RenderTransformOrigin="0.497,-1.834" FontSize="16"/>
<TextBlock HorizontalAlignment="Left" Margin="28,10,0,0" TextWrapping="Wrap" Text="CAR REGISTER" VerticalAlignment="Top" FontFamily="Segoe WP Light" FontSize="16"/>
<ListView HorizontalAlignment="Left" Height="446" Margin="28,31,0,0" VerticalAlignment="Top" Width="323" ItemsSource="{Binding CarRegistry}" SelectedItem="{Binding SelectedCar}">
<ListView.View>
<GridView>
<GridViewColumn Width="Auto" Header="Reg Number" DisplayMemberBinding="{Binding RegNumber}"/>
<GridViewColumn Width="Auto" Header="Manufacturer" DisplayMemberBinding="{Binding Manufacturer}"/>
<GridViewColumn Width="Auto" Header="Model" DisplayMemberBinding="{Binding Model}"/>
<GridViewColumn Width="Auto" Header="Year" DisplayMemberBinding="{Binding Year}"/>
<GridViewColumn Width="Auto" Header="Color" DisplayMemberBinding="{Binding Color}"/>
</GridView>
</ListView.View>
</ListView>
<StackPanel Grid.Column="1" HorizontalAlignment="Left" Height="446" Margin="10,31,0,0" VerticalAlignment="Top" Width="335">
<TabControl DataContext="{Binding SelectedCar}" Height="446">
<TabItem Header="Overview">
<Grid Background="#FFE5E5E5">
<StackPanel>
<StackPanel Orientation="Horizontal">
<Label Margin="20 30 0 0" Content="Registration Number"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBox Name="txtbox_regNumber" Text="{Binding RegNumber, UpdateSourceTrigger=PropertyChanged}" Width="112" Margin="25 3 0 0"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<Label Content="Manufacturer" Margin="21 0 0 0"/>
<Label Content="Model" Margin="76 0 0 0"></Label>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBox Name="txtbox_manufacturer" Text="{Binding Manufacturer, UpdateSourceTrigger=PropertyChanged}" Width="112" Margin="25 0 0 0"/>
<TextBox Name="txtbox_model" Text="{Binding Model, UpdateSourceTrigger=PropertyChanged}" Width="112" Margin="44 0 0 0"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<Label Content="Year" Margin="22 0 0 0"/>
<Label Content="Color" Margin="123 0 0 0"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBox Name="txtbox_year" Text="{Binding Year, UpdateSourceTrigger=PropertyChanged}" Width="112" Margin="25 0 0 0"/>
<TextBox Name="txtbox_color" Text="{Binding Color, UpdateSourceTrigger=PropertyChanged}" Width="112" Margin="44 0 0 0"/>
</StackPanel>
</StackPanel>
<GroupBox Header="Edit" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Height="182" Width="291"/>
</Grid>
</TabItem>
<TabItem Header="Engine Data">
<Grid Background="#FFE5E5E5">
<StackPanel>
<StackPanel>
<Label Content="Serial Number" Margin="20 30 0 0"/>
</StackPanel>
<StackPanel>
<TextBox HorizontalAlignment="Left" Text="{Binding Engine.Serial, UpdateSourceTrigger=PropertyChanged}" Width="112" Margin="25 3 0 0"/>
</StackPanel>
<StackPanel>
<Label Content="Volume" Margin="20 15 0 0"/>
</StackPanel>
<StackPanel>
<TextBox HorizontalAlignment="Left" Text="{Binding Engine.Volume, UpdateSourceTrigger=PropertyChanged}" Width="112" Margin="25,0,0,0"/>
</StackPanel>
</StackPanel>
<GroupBox Header="Edit" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Height="182" Width="291"/>
</Grid>
</TabItem>
</TabControl>
</StackPanel>
<Button Command="{Binding AddCarCommand}" Content="Add" Grid.Column="1" HorizontalAlignment="Left" Margin="10,494,0,0" VerticalAlignment="Top" Width="75"/>
</Grid>
View
理想情况下,我希望能够通过选项卡中的文本框进行添加,但它们当前已绑定到 selectedCar。
在您看来,基本上XAML您需要将命令绑定到按钮。按钮有命令 属性。绑定命令到它
例如
<Button Command={Binding AddCarCommand} CommandParameter="{Binding SelectedCar}">
对于所有这些工作,您必须将视图的 DataContext 属性 设置为 MainViewModel
您的 RelayCommand
应该调用您的 AddCar
方法:
public ICommand AddCarCommand
{
get
{
if (_addCarCommand == null)
{
_addCarCommand = new RelayCommand(param => AddCar(param), param => true);
}
return _addCarCommand;
}
}
在此方法中,您将新的 Car
对象添加到源集合中:
private void AddCar(object o)
{
CarRegistry.Add(new CarModel { Model = Car.Model });
}
在视图中,您可以将 TextBoxes
绑定到 Car 对象的属性:
<TextBox Text="{Binding Car.Model, UpdateSourceTrigger=PropertyChanged}" />
...和 Button
命令 属性:
<Button Command="{Binding AddCarCommand}" />
不要忘记设置视图的DataContext
:
public MainWindow()
{
InitializeComponent();
DataContext = new MainViewModel();
}
...并在视图模型的某处实际创建一个 Car
对象:
private CarModel _car = new CarModel();
编辑:
您命令的 Execute
方法应调用 _execute
操作:
public void Execute(object parameter)
{
_execute(parameter);
}
WPF 和 MVVM 模式的新世界。我希望有人可以提供一个超级简单的描述,说明我如何使用文本框设置属性和通过按钮触发的命令来创建新对象并将其添加到 observableCollection。
我目前拥有的:
型号
public class CarModel : NotifyBase
{
#region Private Members
/// <summary>
/// Private members for the class Car
/// </summary>
private string _manufacturer;
private string _model;
private string _year;
private string _color;
private string _regNumber;
private EngineModel _eng;
#endregion
#region Public Properties
/// <summary>
/// Public properties for the class Car (used for view binding)
/// </summary>
public string Manufacturer {
get { return _manufacturer; }
set {
if (_manufacturer != value)
{
_manufacturer = value;
RaisePropertyChanged("Manufacturer");
}
}
}
public string Model {
get { return _model; }
set {
if (_model != value)
{
_model = value;
RaisePropertyChanged("Model");
}
}
}
.
.
.
ViewModel
class MainViewModel : NotifyBase
{
#region Private Members
/// <summary>
/// Privtae members for the class MainViewModel
/// </summary>
private ObservableCollection<CarModel> _carRegistry;
private CarModel _selectedCar;
private CarModel _car;
private ICommand _addCarCommand;
#endregion
#region Public Properties
/// <summary>
/// Public members for the class MainModelView (used for view binding)
/// </summary>
public ObservableCollection<CarModel> CarRegistry{
get { return _carRegistry; }
set {
_carRegistry = value;
RaisePropertyChanged("CarRegistry");
}
}
public CarModel SelectedCar
{
get { return _selectedCar; }
set
{
_selectedCar = value;
RaisePropertyChanged("SelectedCar");
}
}
public CarModel Car
{
get { return _car; }
set {
_car = value;
RaisePropertyChanged("Car");
}
}
public ICommand AddCarCommand
{
get {
if (_addCarCommand == null)
{
_addCarCommand = new RelayCommand(param =>new CarModel(), param => true);
}
return _addCarCommand;
}
}
#endregion
#region Constructor
/// <summary>
/// MainViewModel constructor
/// </summary>
public MainViewModel()
{
CarRegistry = new ObservableCollection<CarModel>()
{
//Dummy data
new CarModel(){Manufacturer = "Volvo", Model = "V70", Year = "2000", Color = "White", RegNumber = "CDC-123",
Engine = new EngineModel(){Serial = "END125456#", Volume = "2.0"}},
new CarModel(){Manufacturer = "Volvo", Model = "V40", Year = "2005", Color = "Black", RegNumber = "ITI-456",
Engine = new EngineModel(){Serial = "IND554567#", Volume = "1.6"}},
new CarModel(){Manufacturer = "Ford", Model = "Escort", Year = "1995", Color = "Blue", RegNumber = "GHD-777",
Engine = new EngineModel(){Serial = "GHTSJ5556#", Volume = "2.0"}},
};
}
#endregion
#region Methods
private void AddCar(object o)
{
//add new carModel to _carRegistry
}
#endregion
}
中继命令
class RelayCommand:ICommand
{
#region Private Members
readonly Action<object> _execute;
readonly Predicate<object> _canExecute;
#endregion
public RelayCommand(Action<object> execute)
: this(execute, null)
{
}
public RelayCommand(Action<object> execute, Predicate<object> canExecute)
{
if (execute == null)
throw new ArgumentNullException("execute");
_execute = execute;
_canExecute = canExecute;
}
public bool CanExecute(object parameter)
{
return _canExecute == null || _canExecute(parameter);
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public void Execute(object parameter)
{
//if(parameter != null)
_canExecute(parameter);
}
}
如果我理解正确,那么我需要将文本框绑定到 ViewModel 中的属性和一个按钮来触发 AddCarCommand
,但我不清楚它应该如何实现。任何帮助将不胜感激!!!
//内森
编辑
XAML
目前我的 xaml 看起来像这样:
<Window x:Class="CarData_Test.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:CarData_Test"
Title="Car Data Test" Height="606.645" Width="758.759">
<Window.DataContext>
<local:MainViewModel/>
</Window.DataContext>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="1" HorizontalAlignment="Left" Margin="10,10,0,0" TextWrapping="Wrap" Text="CAR INFORMATION" VerticalAlignment="Top" FontWeight="Bold" FontFamily="Segoe WP Light" RenderTransformOrigin="0.497,-1.834" FontSize="16"/>
<TextBlock HorizontalAlignment="Left" Margin="28,10,0,0" TextWrapping="Wrap" Text="CAR REGISTER" VerticalAlignment="Top" FontFamily="Segoe WP Light" FontSize="16"/>
<ListView HorizontalAlignment="Left" Height="446" Margin="28,31,0,0" VerticalAlignment="Top" Width="323" ItemsSource="{Binding CarRegistry}" SelectedItem="{Binding SelectedCar}">
<ListView.View>
<GridView>
<GridViewColumn Width="Auto" Header="Reg Number" DisplayMemberBinding="{Binding RegNumber}"/>
<GridViewColumn Width="Auto" Header="Manufacturer" DisplayMemberBinding="{Binding Manufacturer}"/>
<GridViewColumn Width="Auto" Header="Model" DisplayMemberBinding="{Binding Model}"/>
<GridViewColumn Width="Auto" Header="Year" DisplayMemberBinding="{Binding Year}"/>
<GridViewColumn Width="Auto" Header="Color" DisplayMemberBinding="{Binding Color}"/>
</GridView>
</ListView.View>
</ListView>
<StackPanel Grid.Column="1" HorizontalAlignment="Left" Height="446" Margin="10,31,0,0" VerticalAlignment="Top" Width="335">
<TabControl DataContext="{Binding SelectedCar}" Height="446">
<TabItem Header="Overview">
<Grid Background="#FFE5E5E5">
<StackPanel>
<StackPanel Orientation="Horizontal">
<Label Margin="20 30 0 0" Content="Registration Number"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBox Name="txtbox_regNumber" Text="{Binding RegNumber, UpdateSourceTrigger=PropertyChanged}" Width="112" Margin="25 3 0 0"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<Label Content="Manufacturer" Margin="21 0 0 0"/>
<Label Content="Model" Margin="76 0 0 0"></Label>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBox Name="txtbox_manufacturer" Text="{Binding Manufacturer, UpdateSourceTrigger=PropertyChanged}" Width="112" Margin="25 0 0 0"/>
<TextBox Name="txtbox_model" Text="{Binding Model, UpdateSourceTrigger=PropertyChanged}" Width="112" Margin="44 0 0 0"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<Label Content="Year" Margin="22 0 0 0"/>
<Label Content="Color" Margin="123 0 0 0"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBox Name="txtbox_year" Text="{Binding Year, UpdateSourceTrigger=PropertyChanged}" Width="112" Margin="25 0 0 0"/>
<TextBox Name="txtbox_color" Text="{Binding Color, UpdateSourceTrigger=PropertyChanged}" Width="112" Margin="44 0 0 0"/>
</StackPanel>
</StackPanel>
<GroupBox Header="Edit" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Height="182" Width="291"/>
</Grid>
</TabItem>
<TabItem Header="Engine Data">
<Grid Background="#FFE5E5E5">
<StackPanel>
<StackPanel>
<Label Content="Serial Number" Margin="20 30 0 0"/>
</StackPanel>
<StackPanel>
<TextBox HorizontalAlignment="Left" Text="{Binding Engine.Serial, UpdateSourceTrigger=PropertyChanged}" Width="112" Margin="25 3 0 0"/>
</StackPanel>
<StackPanel>
<Label Content="Volume" Margin="20 15 0 0"/>
</StackPanel>
<StackPanel>
<TextBox HorizontalAlignment="Left" Text="{Binding Engine.Volume, UpdateSourceTrigger=PropertyChanged}" Width="112" Margin="25,0,0,0"/>
</StackPanel>
</StackPanel>
<GroupBox Header="Edit" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Height="182" Width="291"/>
</Grid>
</TabItem>
</TabControl>
</StackPanel>
<Button Command="{Binding AddCarCommand}" Content="Add" Grid.Column="1" HorizontalAlignment="Left" Margin="10,494,0,0" VerticalAlignment="Top" Width="75"/>
</Grid>
View
理想情况下,我希望能够通过选项卡中的文本框进行添加,但它们当前已绑定到 selectedCar。
在您看来,基本上XAML您需要将命令绑定到按钮。按钮有命令 属性。绑定命令到它 例如
<Button Command={Binding AddCarCommand} CommandParameter="{Binding SelectedCar}">
对于所有这些工作,您必须将视图的 DataContext 属性 设置为 MainViewModel
您的 RelayCommand
应该调用您的 AddCar
方法:
public ICommand AddCarCommand
{
get
{
if (_addCarCommand == null)
{
_addCarCommand = new RelayCommand(param => AddCar(param), param => true);
}
return _addCarCommand;
}
}
在此方法中,您将新的 Car
对象添加到源集合中:
private void AddCar(object o)
{
CarRegistry.Add(new CarModel { Model = Car.Model });
}
在视图中,您可以将 TextBoxes
绑定到 Car 对象的属性:
<TextBox Text="{Binding Car.Model, UpdateSourceTrigger=PropertyChanged}" />
...和 Button
命令 属性:
<Button Command="{Binding AddCarCommand}" />
不要忘记设置视图的DataContext
:
public MainWindow()
{
InitializeComponent();
DataContext = new MainViewModel();
}
...并在视图模型的某处实际创建一个 Car
对象:
private CarModel _car = new CarModel();
编辑:
您命令的 Execute
方法应调用 _execute
操作:
public void Execute(object parameter)
{
_execute(parameter);
}