单击未选中的listviewitem中的按钮并获取所选项目

时间:2023-01-19 08:30:39

I have a question about a listview setup like the example below. When I click the button below in the expander header I want that item to be selected as well, but what I'm seeing is while the button command does work, the item selected is still the previous item selected, not the item my button is in. How can I have the Item selected when the button is clicked?

我有一个关于listview设置的问题,如下例所示。当我在扩展器标题中单击下面的按钮时,我也希望选择该项目,但是我看到的是当按钮命令工作时,所选项目仍然是选择的上一项目,而不是项目我的按钮是in。如何在单击按钮时选择项目?

I tried setting up a ControlTemplate like this, but it did not work.

我尝试像这样设置一个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>

2 个解决方案

#1


1  

I would suggest defining a command SelectItem in the main ViewModel which takes the item which is to be selected as a parameter. The execution method of this command can then set the MySelectedItem property, set a property IsSelected on the item ViewModel to true and invoke all further actions on the item itself (i.e. what is now executed by MyCommand). With the selection logic in the ViewModel and a clean binding you don't even need to use ListView at all but can stick to a plain ItemsControl:

我建议在主ViewModel中定义一个命令SelectItem,它将选择的项目作为参数。然后,此命令的执行方法可以设置MySelectedItem属性,将项目ViewModel上的属性IsSelected设置为true,并调用项目本身的所有进一步操作(即,现在由MyCommand执行的操作)。使用ViewModel中的选择逻辑和干净的绑定,您根本不需要使用ListView,但可以坚持使用普通的ItemsControl:

The XAML then looks like this:

然后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>

The MainViewModel would look something like this:

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();
    }
}

I have always found it way easier to use ItemsControl an implement the few lines of selection logic myself, instead of dealing with the messy binding of the selection of a ListView. In my opinion it is a quite intuitive to implement custom selection behavior (multiple items, allowing only certain combinations, etc.). You can use the IsSelected property easily to apply a custom styling of selected items.

我总是发现使用ItemsControl更容易实现自己选择逻辑的几行,而不是处理ListView选择的混乱绑定。在我看来,实现自定义选择行为(多个项目,仅允许某些组合等)是非常直观的。您可以轻松地使用IsSelected属性来应用所选项目的自定义样式。

#2


0  

You can try something like this in your view model, add if statement in setter:

你可以在你的视图模型中尝试这样的东西,在setter中添加if语句:

private object _mySelectedItem;
    public object MySelectedItem
    {
        get { return _mySelectedItem; }
        set 
        {
            if (_mySelectedItem != value && value != null)
            {
                _mySelectedItem = value;
                OnPropertyChanged("MySelectedItem");
            }
        }
    }

#1


1  

I would suggest defining a command SelectItem in the main ViewModel which takes the item which is to be selected as a parameter. The execution method of this command can then set the MySelectedItem property, set a property IsSelected on the item ViewModel to true and invoke all further actions on the item itself (i.e. what is now executed by MyCommand). With the selection logic in the ViewModel and a clean binding you don't even need to use ListView at all but can stick to a plain ItemsControl:

我建议在主ViewModel中定义一个命令SelectItem,它将选择的项目作为参数。然后,此命令的执行方法可以设置MySelectedItem属性,将项目ViewModel上的属性IsSelected设置为true,并调用项目本身的所有进一步操作(即,现在由MyCommand执行的操作)。使用ViewModel中的选择逻辑和干净的绑定,您根本不需要使用ListView,但可以坚持使用普通的ItemsControl:

The XAML then looks like this:

然后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>

The MainViewModel would look something like this:

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();
    }
}

I have always found it way easier to use ItemsControl an implement the few lines of selection logic myself, instead of dealing with the messy binding of the selection of a ListView. In my opinion it is a quite intuitive to implement custom selection behavior (multiple items, allowing only certain combinations, etc.). You can use the IsSelected property easily to apply a custom styling of selected items.

我总是发现使用ItemsControl更容易实现自己选择逻辑的几行,而不是处理ListView选择的混乱绑定。在我看来,实现自定义选择行为(多个项目,仅允许某些组合等)是非常直观的。您可以轻松地使用IsSelected属性来应用所选项目的自定义样式。

#2


0  

You can try something like this in your view model, add if statement in setter:

你可以在你的视图模型中尝试这样的东西,在setter中添加if语句:

private object _mySelectedItem;
    public object MySelectedItem
    {
        get { return _mySelectedItem; }
        set 
        {
            if (_mySelectedItem != value && value != null)
            {
                _mySelectedItem = value;
                OnPropertyChanged("MySelectedItem");
            }
        }
    }