通过单击复选框获得 listbox.selectedindex
getting listbox.selectedindex by clicking on checkbox
这是我在列表框中的用户模板。我想 "listbox.selectedindex" 单击列表框的任何复选框。我想知道哪一行,复选框是 selected.like 在复选框的点击事件中,它应该聚焦整个选定的行。
<ListView x:Name="listbox3" Visibility="Visible" Margin="540,168,37,46" IsSynchronizedWithCurrentItem="True" BorderBrush="Black">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Width="200" >
<TextBlock Text="{Binding VmName}" Width="129" Visibility="Visible" />
<CheckBox x:Name="cb" IsThreeState="False" IsChecked="{Binding IsCheck, Mode=TwoWay}" Margin="6,0,18,6" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>
<CheckBox x:Name="cb1" IsThreeState="False" IsChecked="{Binding IsCheck1, Mode=TwoWay}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
如果没有 a good, minimal, complete code example that clearly illustrates the problem, it is difficult to know exactly what advice would be most useful to you. Without a clear problem statement,甚至不完全清楚您希望代码做什么。
但是,如果我理解正确的话,您正在显示一些数据项类型,在您的 ListView
中使用相应的 DataTemplate
对象。用户可能会切换复选框,并且您想更新 ListView
中当前 selected 的项目,以便它始终是包含刚刚切换的复选框的项目。
至少有几种合理的方法可以做到这一点。在这两种情况下,您只需将 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>
(由于您没有提供完整的代码示例,其中包含数据项对象 class,我只是根据您的问题编写了自己的代码示例。我更改了 属性 名称这样它们就更有意义了,即 IsChecked1
和 IsChecked2
。请随意使用您自己的 属性 名称:)).
第二种方式一方面更直接一点,另一方面又不那么直接。也就是说,假设您的数据项对象 class 实现了 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;
}
请注意,在上面的示例中,我将 SelectedValue
属性 分配给 any 属性 更改。在我自己的代码示例中,这很好,因为唯一可以更改的属性是与复选框相关的属性。当然,如果您想在任何 属性 值更改时 select 相应的 ListView
项目,这也很好。但是,如果您真的只想更新 IsChecked1
和 IsChecked2
属性的更改,则需要查看处理程序中的 属性 名称。例如:
PropertyChangedEventHandler handler = (sender, e) =>
{
if (e.PropertyName == "IsChecked1" || e.PropertyName == "IsChecked2")
{
listbox3.SelectedValue = sender;
}
}
这是我为上述两种方法编写的代码示例 DataItem
class:
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;
}
这是我在列表框中的用户模板。我想 "listbox.selectedindex" 单击列表框的任何复选框。我想知道哪一行,复选框是 selected.like 在复选框的点击事件中,它应该聚焦整个选定的行。
<ListView x:Name="listbox3" Visibility="Visible" Margin="540,168,37,46" IsSynchronizedWithCurrentItem="True" BorderBrush="Black">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Width="200" >
<TextBlock Text="{Binding VmName}" Width="129" Visibility="Visible" />
<CheckBox x:Name="cb" IsThreeState="False" IsChecked="{Binding IsCheck, Mode=TwoWay}" Margin="6,0,18,6" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>
<CheckBox x:Name="cb1" IsThreeState="False" IsChecked="{Binding IsCheck1, Mode=TwoWay}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
如果没有 a good, minimal, complete code example that clearly illustrates the problem, it is difficult to know exactly what advice would be most useful to you. Without a clear problem statement,甚至不完全清楚您希望代码做什么。
但是,如果我理解正确的话,您正在显示一些数据项类型,在您的 ListView
中使用相应的 DataTemplate
对象。用户可能会切换复选框,并且您想更新 ListView
中当前 selected 的项目,以便它始终是包含刚刚切换的复选框的项目。
至少有几种合理的方法可以做到这一点。在这两种情况下,您只需将 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>
(由于您没有提供完整的代码示例,其中包含数据项对象 class,我只是根据您的问题编写了自己的代码示例。我更改了 属性 名称这样它们就更有意义了,即 IsChecked1
和 IsChecked2
。请随意使用您自己的 属性 名称:)).
第二种方式一方面更直接一点,另一方面又不那么直接。也就是说,假设您的数据项对象 class 实现了 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;
}
请注意,在上面的示例中,我将 SelectedValue
属性 分配给 any 属性 更改。在我自己的代码示例中,这很好,因为唯一可以更改的属性是与复选框相关的属性。当然,如果您想在任何 属性 值更改时 select 相应的 ListView
项目,这也很好。但是,如果您真的只想更新 IsChecked1
和 IsChecked2
属性的更改,则需要查看处理程序中的 属性 名称。例如:
PropertyChangedEventHandler handler = (sender, e) =>
{
if (e.PropertyName == "IsChecked1" || e.PropertyName == "IsChecked2")
{
listbox3.SelectedValue = sender;
}
}
这是我为上述两种方法编写的代码示例 DataItem
class:
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;
}