自定义ListItemCollection生成的列表视图中的控件名称(Customizing names of controls within a listview generated from a ListItemCollection)

我有一个ListView,它的表填充了ListItemCollection我正在以编程方式创建和管理。

我想检查哪些控件已经收到任何类型的输入,目前我专注于任何类型的TextInput。 我不知道如何确切地找到这个控件来自哪个列和行(按名称或id,以最简单的方式)。

在通常的Windows窗体应用程序中解决此问题的方法是以编程方式为每个控件分配唯一的名称。 使用[control name]_[row]等模板,例如itemName_1 。

似乎无法修改ListItemCollection生成的控件的名称。 我还尝试使用Path="x"绑定控件,但是XAML阻止使用带有name属性的绑定标记。

什么是这个问题的一个很好的解决方案,我可以以某种方式检测哪个精确的控件与之交互,而无需搜索所有这些?

这是我现在所拥有的(在图片中只创建了一行):

I have a ListView which has it's table filled out with a ListItemCollection I am creating and managing programmatically.

I want to check which of the controls have received any kind of input, currently I am focused on any kind of TextInput. I do not have any idea how to find exactly which column and row this control is from (by name or id, whichever is easiest).

A solution to this problem in a usual Windows Forms application would be programmatically assigning a unique name to each control. With a template such as [control name]_[row], such as itemName_1.

It doesn't seem possible to modify the name of a control generated by a ListItemCollection. I also tried binding a control with Path="x", however XAML prevents using the binding tag with the name property.

What is a good solution to this problem, where I can somehow detect which exact control was interacted with, without searching through all of them?

Here is what I have right now (in the picture only one row was created):

最满意答案

这里的问题是你以WinForms的方式使用WPF。 这并不意味着像这样使用,所以你最终会做错综复杂的事情。

这是你应该做的:

假设我们正在操纵包含订单详细信息的订单。

我们首先创建用于保存数据的类

public class Order : INotifyPropertyChanged { private readonly ObservableCollection<OrderDetail> m_details = new ... public ObservableCollection<OrderDetail> Details { get { return m_details; } } public decimal Total { get { decimal total = 0.0; foreach(var detail in m_details) total += detail.SubTotal; return total; } } } public class OrderDetail : INotifyPropertyChanged { private readonly Order m_order; public OrderDetail(Order order) { m_order = order; } private string m_name; public string Name { get { return m_name; } set { if(m_name != value) { m_name = value; RaisePropertyChanged("Name"); } } } private int m_amount; public int Amount { get { return m_amount; } set { if(m_amount != value) { m_amount = value; RaisePropertyChanged("Amount"); RaisePropertyChanged("SubTotal"); m_order.RaisePropertyChanged("Total"); } } } private decimal m_unitPrice; public decimal UnitPrice { get { return m_amount; } set { if(m_unitPrice!= value) { m_unitPrice = value; RaisePropertyChanged("UnitPrice"); RaisePropertyChanged("SubTotal"); m_order.RaisePropertyChanged("Total"); } } } public decimal SubTotal { get { return Amount * UnitPrice; } } }

然后我们将创建一个视图来可视化和编辑我们的数据

... <ListView ItemsSource="{Binding MyOrder}"> <ListView.View> <GridView> <GridViewColumn> <GridViewColumn.CellTemplate> <DataTemplate> <TextBox Text="{Binding Name}"/> </DataTemplate> </GridViewColumn.CellTemplate> </GridViewColumn> ... </GridView> </ListView.View> </ListView> <StackPanel Orientation="Horizontal"> <TextBlock Text="Total: "/> <Textblock Text="{Binding MyOrder.Total}"/> </StackPanel> ...

The problem here is that you use WPF in a WinForms way. It's not meant to be used like that, and so you end up doing intricate and bogus things.

Here is what you should do :

Let's say we are manipulating an order containing order details.

We first create classes to hold our data

public class Order : INotifyPropertyChanged { private readonly ObservableCollection<OrderDetail> m_details = new ... public ObservableCollection<OrderDetail> Details { get { return m_details; } } public decimal Total { get { decimal total = 0.0; foreach(var detail in m_details) total += detail.SubTotal; return total; } } } public class OrderDetail : INotifyPropertyChanged { private readonly Order m_order; public OrderDetail(Order order) { m_order = order; } private string m_name; public string Name { get { return m_name; } set { if(m_name != value) { m_name = value; RaisePropertyChanged("Name"); } } } private int m_amount; public int Amount { get { return m_amount; } set { if(m_amount != value) { m_amount = value; RaisePropertyChanged("Amount"); RaisePropertyChanged("SubTotal"); m_order.RaisePropertyChanged("Total"); } } } private decimal m_unitPrice; public decimal UnitPrice { get { return m_amount; } set { if(m_unitPrice!= value) { m_unitPrice = value; RaisePropertyChanged("UnitPrice"); RaisePropertyChanged("SubTotal"); m_order.RaisePropertyChanged("Total"); } } } public decimal SubTotal { get { return Amount * UnitPrice; } } }

And then we gonna create a view to visualize and edit our data

... <ListView ItemsSource="{Binding MyOrder}"> <ListView.View> <GridView> <GridViewColumn> <GridViewColumn.CellTemplate> <DataTemplate> <TextBox Text="{Binding Name}"/> </DataTemplate> </GridViewColumn.CellTemplate> </GridViewColumn> ... </GridView> </ListView.View> </ListView> <StackPanel Orientation="Horizontal"> <TextBlock Text="Total: "/> <Textblock Text="{Binding MyOrder.Total}"/> </StackPanel> ...自定义ListItemCollection生成的列表视图中的控件名称(Customizing names of controls within a listview generated from a ListItemCollection)

我有一个ListView,它的表填充了ListItemCollection我正在以编程方式创建和管理。

我想检查哪些控件已经收到任何类型的输入,目前我专注于任何类型的TextInput。 我不知道如何确切地找到这个控件来自哪个列和行(按名称或id,以最简单的方式)。

在通常的Windows窗体应用程序中解决此问题的方法是以编程方式为每个控件分配唯一的名称。 使用[control name]_[row]等模板,例如itemName_1 。

似乎无法修改ListItemCollection生成的控件的名称。 我还尝试使用Path="x"绑定控件,但是XAML阻止使用带有name属性的绑定标记。

什么是这个问题的一个很好的解决方案,我可以以某种方式检测哪个精确的控件与之交互,而无需搜索所有这些?

这是我现在所拥有的(在图片中只创建了一行):

I have a ListView which has it's table filled out with a ListItemCollection I am creating and managing programmatically.

I want to check which of the controls have received any kind of input, currently I am focused on any kind of TextInput. I do not have any idea how to find exactly which column and row this control is from (by name or id, whichever is easiest).

A solution to this problem in a usual Windows Forms application would be programmatically assigning a unique name to each control. With a template such as [control name]_[row], such as itemName_1.

It doesn't seem possible to modify the name of a control generated by a ListItemCollection. I also tried binding a control with Path="x", however XAML prevents using the binding tag with the name property.

What is a good solution to this problem, where I can somehow detect which exact control was interacted with, without searching through all of them?

Here is what I have right now (in the picture only one row was created):

最满意答案

这里的问题是你以WinForms的方式使用WPF。 这并不意味着像这样使用,所以你最终会做错综复杂的事情。

这是你应该做的:

假设我们正在操纵包含订单详细信息的订单。

我们首先创建用于保存数据的类

public class Order : INotifyPropertyChanged { private readonly ObservableCollection<OrderDetail> m_details = new ... public ObservableCollection<OrderDetail> Details { get { return m_details; } } public decimal Total { get { decimal total = 0.0; foreach(var detail in m_details) total += detail.SubTotal; return total; } } } public class OrderDetail : INotifyPropertyChanged { private readonly Order m_order; public OrderDetail(Order order) { m_order = order; } private string m_name; public string Name { get { return m_name; } set { if(m_name != value) { m_name = value; RaisePropertyChanged("Name"); } } } private int m_amount; public int Amount { get { return m_amount; } set { if(m_amount != value) { m_amount = value; RaisePropertyChanged("Amount"); RaisePropertyChanged("SubTotal"); m_order.RaisePropertyChanged("Total"); } } } private decimal m_unitPrice; public decimal UnitPrice { get { return m_amount; } set { if(m_unitPrice!= value) { m_unitPrice = value; RaisePropertyChanged("UnitPrice"); RaisePropertyChanged("SubTotal"); m_order.RaisePropertyChanged("Total"); } } } public decimal SubTotal { get { return Amount * UnitPrice; } } }

然后我们将创建一个视图来可视化和编辑我们的数据

... <ListView ItemsSource="{Binding MyOrder}"> <ListView.View> <GridView> <GridViewColumn> <GridViewColumn.CellTemplate> <DataTemplate> <TextBox Text="{Binding Name}"/> </DataTemplate> </GridViewColumn.CellTemplate> </GridViewColumn> ... </GridView> </ListView.View> </ListView> <StackPanel Orientation="Horizontal"> <TextBlock Text="Total: "/> <Textblock Text="{Binding MyOrder.Total}"/> </StackPanel> ...

The problem here is that you use WPF in a WinForms way. It's not meant to be used like that, and so you end up doing intricate and bogus things.

Here is what you should do :

Let's say we are manipulating an order containing order details.

We first create classes to hold our data

public class Order : INotifyPropertyChanged { private readonly ObservableCollection<OrderDetail> m_details = new ... public ObservableCollection<OrderDetail> Details { get { return m_details; } } public decimal Total { get { decimal total = 0.0; foreach(var detail in m_details) total += detail.SubTotal; return total; } } } public class OrderDetail : INotifyPropertyChanged { private readonly Order m_order; public OrderDetail(Order order) { m_order = order; } private string m_name; public string Name { get { return m_name; } set { if(m_name != value) { m_name = value; RaisePropertyChanged("Name"); } } } private int m_amount; public int Amount { get { return m_amount; } set { if(m_amount != value) { m_amount = value; RaisePropertyChanged("Amount"); RaisePropertyChanged("SubTotal"); m_order.RaisePropertyChanged("Total"); } } } private decimal m_unitPrice; public decimal UnitPrice { get { return m_amount; } set { if(m_unitPrice!= value) { m_unitPrice = value; RaisePropertyChanged("UnitPrice"); RaisePropertyChanged("SubTotal"); m_order.RaisePropertyChanged("Total"); } } } public decimal SubTotal { get { return Amount * UnitPrice; } } }

And then we gonna create a view to visualize and edit our data

... <ListView ItemsSource="{Binding MyOrder}"> <ListView.View> <GridView> <GridViewColumn> <GridViewColumn.CellTemplate> <DataTemplate> <TextBox Text="{Binding Name}"/> </DataTemplate> </GridViewColumn.CellTemplate> </GridViewColumn> ... </GridView> </ListView.View> </ListView> <StackPanel Orientation="Horizontal"> <TextBlock Text="Total: "/> <Textblock Text="{Binding MyOrder.Total}"/> </StackPanel> ...