单击未选中的 listviewitem 中的按钮并获取选中的项目
Clicking a button in a listviewitem that is not selected and getting selected item
我对如下例所示的列表视图设置有疑问。当我单击扩展器下方的按钮时 header 我也希望该项目也被选中,但我看到的是虽然按钮命令有效,但所选项目仍然是上一个所选项目,而不是我的按钮所在的项目。单击按钮时如何选择项目?
我试过像这样设置一个 ControlTemplate,但是没有用。
<Style TargetType="{x:Type ListViewItem}">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListViewItem}">
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
<ControlTemplate.Triggers>
<Trigger Property="IsKeyboardFocusWithin" Value="True">
<Setter Property="IsSelected" Value="True" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<ListView ItemsSource="{Binding MyItemSource,
Mode=TwoWay}"
SelectedItem="{Binding MySelectedItem,
Mode=TwoWay}">
<ListView.ItemTemplate>
<DataTemplate>
<Expander IsExpanded="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListViewItem}}, Path=IsSelected}">
<Expander.Header>
<Button Command={Binding MyCommand}>Click Me</Button>
</Expander.Header>
<!-- content here -->
</Expander>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
我建议在主 ViewModel 中定义一个命令 SelectItem
,它将要选择的项目作为参数。此命令的执行方法然后可以设置 MySelectedItem
属性,将项目 ViewModel 上的 属性 IsSelected
设置为 true
并调用所有进一步的操作项目本身(即现在由 MyCommand
执行的内容)。使用 ViewModel 中的选择逻辑和干净的绑定,您甚至根本不需要使用 ListView
,但可以坚持使用普通的 ItemsControl
:
然后 XAML 看起来像这样:
<ItemsControl ItemsSource="{Binding MyItemSource}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Expander IsExpanded="{Binding IsSelected}">
<Expander.Header>
<Button Command="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ItemsControl}, Path=DataContext.SelectItem}"
CommandParameter="{Binding"}>Click Me</Button>
</Expander.Header>
<!-- content here -->
</Expander>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
MainViewModel 看起来像这样:
public class MainViewModel : INotifyPropertyChanged
{
public ObservableCollection<ItemViewModel> MyItemsSource { get; private set; }
public ItemViewModel SelectedItem { get... set... }
public ICommand SelectItem { get; private set; }
ctor()...
private void ExecuteSelectItem(ItemViewModel item)
{
SelectedItem = item;
foreach (var i in MyItemsSource) i.IsSelected = false;
item.IsSelected = true;
item.DoSomething();
}
}
我一直发现使用 ItemsControl
自己实现几行选择逻辑更容易,而不是处理 ListView
选择的混乱绑定。在我看来,实现自定义选择行为(多个项目,只允许某些组合等)是非常直观的。您可以使用 IsSelected
属性 轻松地为所选项目应用自定义样式。
您可以在您的视图模型中尝试类似的操作,在 setter 中添加 if 语句:
private object _mySelectedItem;
public object MySelectedItem
{
get { return _mySelectedItem; }
set
{
if (_mySelectedItem != value && value != null)
{
_mySelectedItem = value;
OnPropertyChanged("MySelectedItem");
}
}
}
我对如下例所示的列表视图设置有疑问。当我单击扩展器下方的按钮时 header 我也希望该项目也被选中,但我看到的是虽然按钮命令有效,但所选项目仍然是上一个所选项目,而不是我的按钮所在的项目。单击按钮时如何选择项目?
我试过像这样设置一个 ControlTemplate,但是没有用。
<Style TargetType="{x:Type ListViewItem}">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListViewItem}">
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
<ControlTemplate.Triggers>
<Trigger Property="IsKeyboardFocusWithin" Value="True">
<Setter Property="IsSelected" Value="True" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<ListView ItemsSource="{Binding MyItemSource,
Mode=TwoWay}"
SelectedItem="{Binding MySelectedItem,
Mode=TwoWay}">
<ListView.ItemTemplate>
<DataTemplate>
<Expander IsExpanded="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListViewItem}}, Path=IsSelected}">
<Expander.Header>
<Button Command={Binding MyCommand}>Click Me</Button>
</Expander.Header>
<!-- content here -->
</Expander>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
我建议在主 ViewModel 中定义一个命令 SelectItem
,它将要选择的项目作为参数。此命令的执行方法然后可以设置 MySelectedItem
属性,将项目 ViewModel 上的 属性 IsSelected
设置为 true
并调用所有进一步的操作项目本身(即现在由 MyCommand
执行的内容)。使用 ViewModel 中的选择逻辑和干净的绑定,您甚至根本不需要使用 ListView
,但可以坚持使用普通的 ItemsControl
:
然后 XAML 看起来像这样:
<ItemsControl ItemsSource="{Binding MyItemSource}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Expander IsExpanded="{Binding IsSelected}">
<Expander.Header>
<Button Command="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ItemsControl}, Path=DataContext.SelectItem}"
CommandParameter="{Binding"}>Click Me</Button>
</Expander.Header>
<!-- content here -->
</Expander>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
MainViewModel 看起来像这样:
public class MainViewModel : INotifyPropertyChanged
{
public ObservableCollection<ItemViewModel> MyItemsSource { get; private set; }
public ItemViewModel SelectedItem { get... set... }
public ICommand SelectItem { get; private set; }
ctor()...
private void ExecuteSelectItem(ItemViewModel item)
{
SelectedItem = item;
foreach (var i in MyItemsSource) i.IsSelected = false;
item.IsSelected = true;
item.DoSomething();
}
}
我一直发现使用 ItemsControl
自己实现几行选择逻辑更容易,而不是处理 ListView
选择的混乱绑定。在我看来,实现自定义选择行为(多个项目,只允许某些组合等)是非常直观的。您可以使用 IsSelected
属性 轻松地为所选项目应用自定义样式。
您可以在您的视图模型中尝试类似的操作,在 setter 中添加 if 语句:
private object _mySelectedItem;
public object MySelectedItem
{
get { return _mySelectedItem; }
set
{
if (_mySelectedItem != value && value != null)
{
_mySelectedItem = value;
OnPropertyChanged("MySelectedItem");
}
}
}