如果没有明确说明问题的a good, minimal, complete code example,很难确切知道哪些建议对您最有用。如果没有a clear problem statement,甚至无法完全清楚您想要代码做什么。
但是,如果我理解正确,您正在显示某些数据项类型,在您的 ListView 中使用相应的 DataTemplate 对象。用户可以切换复选框,而您想要更新ListView 中当前选中的项目,以便它始终是包含刚刚切换的复选框的项目。
至少有几种合理的方法可以做到这一点。在这两种情况下,您只需将ListView.SelectedValue 属性设置为与正在修改的CheckBox 对应的数据项对象引用。
第一种方法涉及处理CheckBox 控件本身上的Checked 和Unchecked 事件,回溯到ListViewItem,然后获取该ListViewItem 的数据项。
首先,您需要编写一个处理程序来执行上述操作:
private void cb_Checked(object sender, RoutedEventArgs e)
{
ListViewItem listViewItem =
GetVisualAncestor<ListViewItem>((DependencyObject)sender);
listbox3.SelectedValue =
listbox3.ItemContainerGenerator.ItemFromContainer(listViewItem);
}
private static T GetVisualAncestor<T>(DependencyObject o) where T : DependencyObject
{
do
{
o = VisualTreeHelper.GetParent(o);
} while (o != null && !typeof(T).IsAssignableFrom(o.GetType()));
return (T)o;
}
注意辅助方法GetVisualAncestor<T>()。它使用VisualTreeHelper 将树返回到包含受影响的CheckBox 控件的ListViewItem 对象。
找到该对象后,代码调用ItemContainerGenerator.ItemFromContainer() 来查找实际的数据项对象引用,并将该引用分配给SelectedValue 属性。
当然,要使处理程序有用,您需要为其订阅相关的Checked 和Unchecked 事件。例如:
<DataTemplate DataType="{x:Type local:DataItem}">
<StackPanel Orientation="Horizontal" Width="200" >
<TextBlock Text="{Binding VmName}" Width="129" Visibility="Visible" />
<CheckBox x:Name="cb" IsThreeState="False"
IsChecked="{Binding IsChecked1, Mode=TwoWay}"
Margin="6,0,18,6"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
Checked="cb_Checked" Unchecked="cb_Checked"/>
<CheckBox x:Name="cb1" IsThreeState="False"
IsChecked="{Binding IsChecked2, Mode=TwoWay}"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
Checked="cb_Checked" Unchecked="cb_Checked"/>
</StackPanel>
</DataTemplate>
(由于您没有提供包含数据项对象类的完整代码示例,因此我只是根据您的问题编写了自己的代码示例。我更改了属性名称以使其更有意义,即@987654343 @ 和 IsChecked2。请随意使用您自己的属性名称 :) )。
第二种方式在一个方面更直接,但在另一个方面不那么直接。也就是说,假设您的数据项对象类实现了INotifyPropertyChanged,您可以为每个数据项对象订阅PropertyChanged 事件,只需将事件的sender 分配为ListView.SelectedValue 属性即可。
这更直接,因为您不必添加将可视化树返回到某个控件的父级的代码。但它也不太直接,因为您需要将必要的事件处理程序附加到每个数据项对象的代码。
一个例子可能如下所示:
List<DataItem> dataItems = new List<DataItem>
{
new DataItem { VmName = "sagar" },
new DataItem { VmName = "kaustubh" },
new DataItem { VmName = "gaurav" },
new DataItem { VmName = "abhi" },
};
listbox3.ItemsSource = dataItems;
PropertyChangedEventHandler handler =
(sender, e) => listbox3.SelectedValue = sender;
foreach (DataItem item in dataItems)
{
item.PropertyChanged += handler;
}
请注意,在上面的示例中,我在 any 属性更改时分配了 SelectedValue 属性。在我自己的代码示例中,这很好,因为唯一可以更改的属性是与复选框相关的属性。当然,如果您想在任何属性值更改时选择相应的ListView 项,这也可以。但是,如果您真的只想更新 IsChecked1 和 IsChecked2 属性的更改,则需要查看处理程序中的属性名称。例如:
PropertyChangedEventHandler handler = (sender, e) =>
{
if (e.PropertyName == "IsChecked1" || e.PropertyName == "IsChecked2")
{
listbox3.SelectedValue = sender;
}
}
这是我为上述两种方法的代码示例编写的DataItem 类:
class DataItem : INotifyPropertyChanged
{
private string _vmName;
private bool _isChecked1;
private bool _isChecked2;
public string VmName
{
get { return _vmName; }
set { _vmName = value; OnPropertyChanged(); }
}
public bool IsChecked1
{
get { return _isChecked1; }
set { _isChecked1 = value; OnPropertyChanged(); }
}
public bool IsChecked2
{
get { return _isChecked2; }
set { _isChecked2 = value; OnPropertyChanged(); }
}
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}