Clicking a button in a listviewitem that is not se

2019-08-23 06:28发布

问题:

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?

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

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

回答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:

The XAML then looks like this:

<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:

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.



回答2:

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

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