MVVM:将具有可观察集合的命令绑定到列表框并从文本框中获取值
本文关键字:列表 文本 获取 绑定 命令 集合 观察 MVVM | 更新日期: 2023-09-27 18:35:25
我是MVVM的新手,在这个小应用程序中,我有一个列表框,三个文本框和两个按钮,一个是更新,另一个是添加。在 XAML 中,我已经完成了所有列表框列与文本框的绑定,根据命令,当我更改任一文本框中的值时,我的更新按钮功能正常,但我不知道如何使用命令从文本框中获取值并在集合中添加值。
这是 Xaml 代码。
<Grid Height="314">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<ListView Name="ListViewEmployeeDetails" Grid.Row="1" Margin="4,109,12,23" ItemsSource="{Binding Products}" >
<ListView.View>
<GridView x:Name="grdTest">
<GridViewColumn Header="ID" DisplayMemberBinding="{Binding ID}" Width="100"/>
<GridViewColumn Header="Name" DisplayMemberBinding="{Binding Name}" Width="100" />
<GridViewColumn Header="Price" DisplayMemberBinding="{Binding Price}" Width="100" />
</GridView>
</ListView.View>
</ListView>
<TextBox Grid.Row="1" Height="23" HorizontalAlignment="Left" Margin="80,7,0,0" Name="txtID" VerticalAlignment="Top" Width="178" Text="{Binding ElementName=ListViewEmployeeDetails,Path=SelectedItem.ID}" />
<TextBox Grid.Row="1" Height="23" HorizontalAlignment="Left" Margin="80,35,0,0" Name="txtName" VerticalAlignment="Top" Width="178" Text="{Binding ElementName=ListViewEmployeeDetails,Path=SelectedItem.Name}" />
<TextBox Grid.Row="1" Height="23" HorizontalAlignment="Left" Margin="80,61,0,0" Name="txtPrice" VerticalAlignment="Top" Width="178" Text="{Binding ElementName=ListViewEmployeeDetails,Path=SelectedItem.Price}" />
<Label Content="ID" Grid.Row="1" HorizontalAlignment="Left" Margin="12,12,0,274" Name="label1" />
<Label Content="Price" Grid.Row="1" Height="28" HorizontalAlignment="Left" Margin="12,59,0,0" Name="label2" VerticalAlignment="Top" />
<Label Content="Name" Grid.Row="1" Height="28" HorizontalAlignment="Left" Margin="12,35,0,0" Name="label3" VerticalAlignment="Top" />
<Button Content="Update" Grid.Row="1" Height="23" HorizontalAlignment="Left" Margin="311,59,0,0" Name="btnUpdate"
VerticalAlignment="Top" Width="141"
Command="{Binding Path=UpdateCommad}"
/>
<Button Content="Add" Grid.Row="1" Height="23" HorizontalAlignment="Left" Margin="311,17,0,0" Name="btnAdd"
VerticalAlignment="Top" Width="141"
Command="{Binding UpdateCommad}"
/>
</Grid>
这是产品类别
public class Product : INotifyPropertyChanged
{
private int m_ID;
private string m_Name;
private double m_Price;
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
public int ID
{
get
{
return m_ID;
}
set
{
m_ID = value;
OnPropertyChanged("ID");
}
}
public string Name
{
get
{
return m_Name;
}
set
{
m_Name = value;
OnPropertyChanged("Name");
}
}
public double Price
{
get
{
return m_Price;
}
set
{
m_Price = value;
OnPropertyChanged("Price");
}
}
}
这是视图模型类,现在我静态地将产品添加到m_Products中。
class ProductViewModel
{
private ObservableCollection<Product> m_Products;
public ProductViewModel()
{
m_Products = new ObservableCollection<Product>
{
new Product {ID=1, Name ="Pro1", Price=10},
new Product{ID=2, Name="BAse2", Price=12}
};
}
public ObservableCollection<Product> Products
{
get
{
return m_Products;
}
set
{
m_Products = value;
}
}
private ICommand mUpdater;
public ICommand UpdateCommand
{
get
{
if (mUpdater == null)
mUpdater = new Updater();
return mUpdater;
}
set
{
mUpdater = value;
}
}
private ICommand addUpdater;
public ICommand AddCommand
{
get
{
if (addUpdater == null)
addUpdater = new Updater();
return addUpdater;
}
set
{
addUpdater = value;
}
}
private class Updater : ICommand
{
#region ICommand Members
public bool CanExecute(object parameter)
{
return true;
}
public event EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
}
#endregion
}
}
现在我不知道如何使用添加按钮单击上的命令将值(产品)添加到集合中。
命令。它允许您通过传递到其构造函数的委托注入命令的逻辑:
/// <summary>
/// Class representing a command sent by a button in the UI, defines what to launch when the command is called
/// </summary>
public class RelayCommand : ICommand
{
#region Fields
readonly Action<object> _execute;
readonly Predicate<object> _canExecute;
#endregion // Fields
#region Constructors
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;
}
#endregion // Constructors
#region ICommand Members
//[DebuggerStepThrough]
/// <summary>
/// Defines if the current command can be executed or not
/// </summary>
/// <param name="parameter"></param>
/// <returns></returns>
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)
{
_execute(parameter);
}
#endregion // ICommand Members
}
使用这种类型的命令,您可以非常轻松地执行所需的操作,例如,在您的视图模型中,您现在可以执行此操作:
public class ProductViewModel : INotifyPropertyChanged
{
private ObservableCollection<Product> m_Products;
public ProductViewModel()
{
m_Products = new ObservableCollection<Product>
{
new Product {ID = 1, Name = "Pro1", Price = 10},
new Product {ID = 2, Name = "BAse2", Price = 12}
};
}
private Product _selectedProduct;
public Product SelectedProduct
{
get
{
return _selectedProduct;
}
set
{
_selectedProduct = value;
OnPropertyChanged("SelectedProduct");
}
}
public ObservableCollection<Product> Products
{
get
{
return m_Products;
}
set
{
m_Products = value;
}
}
ICommand _addCommand;
public ICommand AddCommand
{
get
{
if (_addCommand == null)
{
_addCommand = new RelayCommand(param => AddItem());
}
return _addCommand;
}
}
ICommand _deleteCommand;
public ICommand DeleteCommand
{
get
{
if (_deleteCommand == null)
{
_deleteCommand = new RelayCommand(param => DeleteItem((Product)param));
}
return _deleteCommand;
}
}
private void DeleteItem(Product product)
{
if (m_Products.Contains(product))
{
m_Products.Remove(product);
}
}
private void AddItem()
{
m_Products.Add(new Product());
}
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
如您所见,有两个命令,一个用于添加产品,另一个用于删除所选产品。您不必担心更新,您使用的是ObservableCollection<>。此外,我将属性 selectedProduct 添加到您的视图模型,以了解在您的视图中选择了哪个元素:
<Grid Height="314">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<ListView Name="ListViewEmployeeDetails" Grid.Row="1" Margin="4,109,12,23" ItemsSource="{Binding Products}" SelectedValue="{Binding SelectedProduct}" >
<ListView.View>
<GridView x:Name="grdTest">
<GridViewColumn Header="ID" DisplayMemberBinding="{Binding ID}" Width="100" />
<GridViewColumn Header="Name" DisplayMemberBinding="{Binding Name}" Width="100" />
<GridViewColumn Header="Price" DisplayMemberBinding="{Binding Price}" Width="100" />
</GridView>
</ListView.View>
</ListView>
<TextBox Grid.Row="1" Height="23" HorizontalAlignment="Left" Margin="80,7,0,0" Name="txtID" VerticalAlignment="Top" Width="178" Text="{Binding SelectedProduct.ID}" />
<TextBox Grid.Row="1" Height="23" HorizontalAlignment="Left" Margin="80,35,0,0" Name="txtName" VerticalAlignment="Top" Width="178" Text="{Binding SelectedProduct.Name}" />
<TextBox Grid.Row="1" Height="23" HorizontalAlignment="Left" Margin="80,61,0,0" Name="txtPrice" VerticalAlignment="Top" Width="178" Text="{Binding SelectedProduct.Price}" />
<Label Content="ID" Grid.Row="1" HorizontalAlignment="Left" Margin="12,12,0,274" Name="label1" />
<Label Content="Price" Grid.Row="1" Height="28" HorizontalAlignment="Left" Margin="12,59,0,0" Name="label2" VerticalAlignment="Top" />
<Label Content="Name" Grid.Row="1" Height="28" HorizontalAlignment="Left" Margin="12,35,0,0" Name="label3" VerticalAlignment="Top" />
<Button Content="Remove" Grid.Row="1" Height="23" HorizontalAlignment="Left" Margin="311,59,0,0" Name="btnUpdate"
VerticalAlignment="Top" Width="141"
Command="{Binding DeleteCommand}" CommandParameter="{Binding SelectedProduct}"
/>
<Button Content="Add" Grid.Row="1" Height="23" HorizontalAlignment="Left" Margin="311,17,0,0" Name="btnAdd"
VerticalAlignment="Top" Width="141"
Command="{Binding AddCommand}"
/>
</Grid>
在删除按钮中,我声明了 CommandParamameter,并将其绑定到 SelectedProduct 属性。这是接收中继命令以删除产品的参数。没有必要,您已经在视图中模型中选择了 SelectedProduct,但我还是这样做是为了展示如何将参数传递给命令。
[编辑1]
若要实现所需的行为,需要在视图模型中添加三个新属性(Id、Name 和 Price)。现在,这些属性应与文本框绑定。若要在 ListView 中编辑所选产品,请在"所选产品"属性集中设置"ID"、"名称"和"价格"属性的值。当文本框也更改其值时,您必须设置所选产品的属性。
视图模型中的更改:
private int _id=1;
public int Id
{
get
{
return _id;
}
set
{
_id = value;
if (SelectedProduct!=null)
{
SelectedProduct.ID = _id;
}
OnPropertyChanged("Id");
}
}
private string _name;
public string Name
{
get
{
return _name;
}
set
{
_name = value;
if (SelectedProduct != null)
{
SelectedProduct.Name = _name;
}
OnPropertyChanged("Name");
}
}
private double _price = 0;
public double Price
{
get
{
return _price;
}
set
{
_price = value;
if (SelectedProduct != null)
{
SelectedProduct.Price = _price;
}
OnPropertyChanged("Price");
}
}
private Product _selectedProduct;
public Product SelectedProduct
{
get
{
return _selectedProduct;
}
set
{
_selectedProduct = value;
Id = _selectedProduct != null ? _selectedProduct.ID : 0;
Name = _selectedProduct != null ? _selectedProduct.Name : "";
Price = _selectedProduct != null ? _selectedProduct.Price : 0;
OnPropertyChanged("SelectedProduct");
}
}
视图更改:
<TextBox Grid.Row="1" Height="23" HorizontalAlignment="Left" Margin="80,7,0,0" Name="txtID" VerticalAlignment="Top" Width="178" Text="{Binding Id}" />
<TextBox Grid.Row="1" Height="23" HorizontalAlignment="Left" Margin="80,35,0,0" Name="txtName" VerticalAlignment="Top" Width="178" Text="{Binding Name}" />
<TextBox Grid.Row="1" Height="23" HorizontalAlignment="Left" Margin="80,61,0,0" Name="txtPrice" VerticalAlignment="Top" Width="178" Text="{Binding Price}" />