Wpf 如何在ListView中捕获按钮按下
我在WPF列表视图中显示一个项目列表,项目有数量、订单代码和描述。这些列绑定到视图模型中保存的ObservableCollection中的字段。这一切都是非常标准的,正如预期的那样。然而,在ListView的Quantity列中,我添加了两个按钮+和-,其思想是当按下它们时,数量的值要么递增,要么递减。问题是,因为这些按钮没有绑定到ObservaleCollection中的字段,所以我无法从列表视图中按下的按钮获取到ObservaleCollection中记录的链接。我尝试在ListView中选择项目,但按下按钮时选择的是按钮,而不是ListView项目。按下按钮时,我还捕获了鼠标指针下的项目,但可以使用键盘按下 我觉得必须有一个(简单的!)方法来做到这一点,但我找不到它 这是XAML:Wpf 如何在ListView中捕获按钮按下,wpf,listview,button,Wpf,Listview,Button,我在WPF列表视图中显示一个项目列表,项目有数量、订单代码和描述。这些列绑定到视图模型中保存的ObservableCollection中的字段。这一切都是非常标准的,正如预期的那样。然而,在ListView的Quantity列中,我添加了两个按钮+和-,其思想是当按下它们时,数量的值要么递增,要么递减。问题是,因为这些按钮没有绑定到ObservaleCollection中的字段,所以我无法从列表视图中按下的按钮获取到ObservaleCollection中记录的链接。我尝试在ListView中选
<ListViewName="AccessoriesContent" >
<ListView.View>
<GridView>
<GridView.Columns>
<GridViewColumn Header="Select">
<GridViewColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Name="QuantityStack">
<Button Name="SubtractAccessoryButton" Command="vx:DataCommands.SubtractAccessory" Content="-" />
<TextBox Name="QuantityTextBox" Text="{Binding Quantity, Mode=TwoWay}" />
<Button Name="AddAccessoryButton" Command="vx:DataCommands.AddAccessory" Content="+" />
</StackPanel>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Order Code" DisplayMemberBinding="{Binding OrderCode}" />
<GridViewColumn Header="Description" DisplayMemberBinding="{Binding Description}" />
</GridView.Columns>
</GridView>
</ListView.View>
</ListView>
以及ViewModel:
class AccessoryViewModel
{
ObservableCollection<AccessoryData> _AccessoryCollection =
new ObservableCollection<AccessoryData>();
public ObservableCollection<AccessoryData> AccessoryCollection
{ get { return _AccessoryCollection; } }
public void PopulateAccessories(string order_code)
{
// Read the data and populate AccessoryCollection
}
}
public class AccessoryData : INotifyPropertyChanged
{
private int _quantity;
public int Quantity
{
get { return _quantity; }
set
{
this._quantity = value;
Notify("Quantity");
}
}
public string OrderCode { get; set; }
public string Description { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
protected void Notify(string propName)
{
if (this.PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
}
}
类访问视图模型
{
ObservableCollection\u AccessoryCollection=
新的可观察集合();
公共可观测集合附件集合
{get{return{U AccessoryCollection;}}
公共void PopulateAccessories(字符串顺序_代码)
{
//读取数据并填充AccessoryCollection
}
}
公共类访问数据:INotifyPropertyChanged
{
私人国际单位数量;
公共整数
{
获取{返回_数量;}
设置
{
这个。_数量=值;
通知(“数量”);
}
}
公共字符串顺序码{get;set;}
公共字符串说明{get;set;}
公共事件属性更改事件处理程序属性更改;
受保护的void Notify(字符串propName)
{
if(this.PropertyChanged!=null)
{
PropertyChanged(这是新PropertyChangedEventArgs(propName));
}
}
}
除此之外,我还有两种方法Subtract Accessory和AddAccessory,它们是由按钮触发的,但我还没有用任何有效的方法填充它们。您可以通过按钮上唯一标识当前项的
命令参数
传递当前项。这样,在执行命令时,你就知道你在说什么了。如果你在物品中找不到唯一的标记,你甚至可以传递整个物品
您似乎没有发布您使用的命令
无论如何,如果您确实使用命令,您可以使用视图模型上存在的实例命令(然后需要将命令绑定到DataContext
上的command属性),从而访问数量
,或者您可以将视图模型作为CommandParameter
传递,只需将其设置为{Binding}
,然后在命令中可以将参数强制转换为VM并更改数量
(如果要使用单击
事件,您可以将发送者
强制转换为按钮
,并将其数据上下文
强制转换为VM)另一个选项是创建RelayCommand(请参阅)。在此模型中,您可以在每个项目上创建ICommand属性。然后将此属性设置为一个新的RelayCommand,该命令接受您希望在激活该命令时运行的委托。所以这可能是对AccessoryData的QuantityUp方法和QuantityDown方法。一旦设置好ICommand属性,您只需像这样绑定到它,其中QuantityUpCommand是您的ICommand属性
<GridViewColumn Header="" >
<GridViewColumn.CellTemplate>
<DataTemplate>
<Button Height="15" Width="15" Content="+" Command="{Binding QuantityUpCommand}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
RelayCommand看起来像这样:
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
public bool CanExecute(object parameter)
{
return _canExecute == null ? true : _canExecute(parameter);
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public void Execute(object parameter)
{
_execute(parameter);
}
#endregion // ICommand Members
}
公共类RelayCommand:ICommand
{
#区域字段
只读操作_执行;
只读谓词_canExecute;
#endregion//字段
#区域构造函数
公共中继命令(操作执行)
:此(执行,空)
{
}
公共RelayCommand(操作执行,谓词canExecute)
{
if(execute==null)
抛出新的ArgumentNullException(“执行”);
_执行=执行;
_canExecute=canExecute;
}
#endregion//构造函数
#区域ICommand成员
公共布尔CanExecute(对象参数)
{
返回_canExecute==null?true:_canExecute(参数);
}
公共事件事件处理程序CanExecuteChanged
{
添加{CommandManager.RequerySuggested+=value;}
删除{CommandManager.RequerySuggested-=value;}
}
public void Execute(对象参数)
{
_执行(参数);
}
#endregion//ICommand成员
}
+1指出您可以从按钮获取ViewModel。DataContext
H.B。感谢您的回答。我使用的是实例命令,但CommandParameter有问题,我将再看一眼。对于MVVM框架的新手,我想在这里指出,DataContext并不总是包含ViewModel。程序员必须在代码中显式地将DataContext设置为与ViewModel相等,以便以后能够从DataContext中获取ViewModel。@MarkRucker:在这种情况下不是这样的,在ListView
中,项模板中的元素总是将VM作为DataContext。@Marcus:正如我所说,如果在实例上有命令,您甚至不需要命令参数,因为命令与数量
位于同一对象上,因此您可以直接访问它。如果您使用某种形式的中继命令,那么值得注意的是,如果您使用lambdas来创建execute方法,您应该初始化constructor中的command backing字段,而不是字段初始化器中的command backing字段,它是准静态的,因此无法访问对象实例
private RelayCommand _quantityUpCommand;
public ICommand QuantityUpCommand
{
get
{
if (_quantityUpCommand == null)
{
_quantityUpCommand = new RelayCommand(QuantityUp);
}
return _quantityUpCommand;
}
}
public void QuantityUp(object obj)
{
Quantity++;
}
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
public bool CanExecute(object parameter)
{
return _canExecute == null ? true : _canExecute(parameter);
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public void Execute(object parameter)
{
_execute(parameter);
}
#endregion // ICommand Members
}