ListViewItem IsSelected Двухстороннее связывание не работает - PullRequest
0 голосов
/ 19 февраля 2020

Я создал тему «DarkMode» для своего приложения, но привязка IsSelected для ListViewItem не работает. Когда я выбираю элемент / элементы, они выделяются, как и ожидалось (т.е. MultiTriggers применяют правильный цвет выделения), поэтому ListView явно думает IsSelected == True. Но Setter никогда не вызывается, поэтому свойство в моей модели никогда не обновляется.

Если я удаляю стиль x:Key="RemoteComputerItem", он работает нормально (т.е. вызывается Setter и моя модель обновляется). Удаление всех триггеров в этом стиле не имеет значения (очевидно, я не вижу выделенных элементов, но Setter по-прежнему не вызывается). Таким образом, остается только следующее:

<ControlTemplate TargetType="{x:Type ListViewItem}">
    <Border x:Name="Bd">
        <GridViewRowPresenter HorizontalAlignment="{TemplateBinding HorizontalAlignment}" VerticalAlignment="{TemplateBinding VerticalAlignment}" />
    </Border>
</ControlTemplate>

Я считаю, что проблема заключается в приведенном выше шаблоне элемента управления, но я не могу понять, как это исправить. Я что-то пропустил? или мне нужно использовать что-то еще вместо GridViewRowPresenter?

Мой XAML ниже. Я не включил C#, так как думаю, что проблема здесь и не хочу, чтобы вопрос был слишком длинным, но я рад добавить его, если необходимо.

Просмотр:

<ListView x:Name="ADComputers" Margin="0" Padding="0" Grid.Row="1" Grid.Column="2" 
          ItemsSource="{Binding SelectedItem.Computers, ElementName=ADTree, Mode=TwoWay}"
          SelectionMode="Multiple" ItemContainerStyle="{DynamicResource RemoteComputerItem}">
    <ListView.Resources>
        <Style TargetType="{x:Type ListViewItem}" BasedOn="{StaticResource RemoteComputerItem}">
            <Setter Property="IsSelected" Value="{Binding IsSelected}" />
            <Style.Triggers>
                <DataTrigger Binding="{Binding StatusText}" Value="Offline">
                    <Setter Property="Foreground" Value="Gray" />
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </ListView.Resources>
    <ListView.View>
        <GridView>
            <GridViewColumn Header="" Width="20">
                <GridViewColumn.CellTemplate>
                    <DataTemplate>
                        <Image Source="" />
                    </DataTemplate>
                </GridViewColumn.CellTemplate>
            </GridViewColumn>
            <GridViewColumn x:Name="Name" Width="120" DisplayMemberBinding="{Binding Name}">
                <GridViewColumn.Header>
                    <GridViewColumnHeader Content="Computer Name" util:SortOrderGlyph.IsSorted="False" util:SortOrderGlyph.SortDirection="True">
                        <i:Interaction.Triggers>
                            <i:EventTrigger EventName="Click">
                                <cal:ActionMessage MethodName="SortCol">
                                    <cal:Parameter Value="Name" />
                                    <cal:Parameter Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type GridViewColumnHeader}}}" />
                                </cal:ActionMessage>
                            </i:EventTrigger>
                        </i:Interaction.Triggers>
                    </GridViewColumnHeader>
                </GridViewColumn.Header>
            </GridViewColumn>

            <!-- More columns like above, removed to shorten -->

        </GridView>
    </ListView.View>
</ListView>

Отдельный словарь ресурсов для темы DarkMode:

<Style x:Key="RemoteComputerItem" TargetType="{x:Type ListViewItem}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type ListViewItem}">
                <Border x:Name="Bd">
                    <GridViewRowPresenter HorizontalAlignment="{TemplateBinding HorizontalAlignment}" VerticalAlignment="{TemplateBinding VerticalAlignment}" />
                </Border>
                <ControlTemplate.Triggers>
                    <Trigger Property="IsMouseOver" Value="True">
                        <Setter Property="Background" TargetName="Bd">
                            <Setter.Value>
                                <SolidColorBrush Color="{DynamicResource ControlMouseOverColor}" />
                            </Setter.Value>
                        </Setter>
                    </Trigger>
                    <MultiTrigger>
                        <MultiTrigger.Conditions>
                            <Condition Property="Selector.IsSelectionActive" Value="False" />
                            <Condition Property="IsSelected" Value="True" />
                        </MultiTrigger.Conditions>
                        <Setter Property="Background" TargetName="Bd">
                            <Setter.Value>
                                <SolidColorBrush Color="{DynamicResource SelectedBackgroundColor}" />
                            </Setter.Value>
                        </Setter>
                    </MultiTrigger>
                    <MultiTrigger>
                        <MultiTrigger.Conditions>
                            <Condition Property="Selector.IsSelectionActive" Value="True" />
                            <Condition Property="IsSelected" Value="True" />
                        </MultiTrigger.Conditions>
                        <Setter Property="Background" TargetName="Bd">
                            <Setter.Value>
                                <SolidColorBrush Color="{DynamicResource SelectedBackgroundColor}" />
                            </Setter.Value>
                        </Setter>
                    </MultiTrigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

РЕДАКТИРОВАТЬ:

Здесь еще немного кода, чтобы дать вам полную картину привязок, но, как я упоминал выше, привязки отлично работают, когда я удаляю шаблон элемента управления для ListViewItem.

Как вы можете видеть выше, ListView привязан к SelectedItem.Computers элемента ADTree. Вот XAML для ADTree:

<TreeView Margin="0, -1, 0, 0" Grid.Row="1" Grid.Column="0" x:Name="ADTree" ItemsSource="{Binding ADRoot.Children}">
    <TreeView.ItemContainerStyle>
        <Style TargetType="{x:Type TreeViewItem}" BasedOn="{StaticResource {x:Type TreeViewItem}}">
            <Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" />
            <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
        </Style>
    </TreeView.ItemContainerStyle>

    <TreeView.Resources>
        <HierarchicalDataTemplate DataType="{x:Type models:OUModel}" ItemsSource="{Binding Children}">
            <StackPanel Orientation="Horizontal">
                <Image Width="16" Height="16" Margin="3,0" />
                <TextBlock Text="{Binding Name}" />
            </StackPanel>
        </HierarchicalDataTemplate>
    </TreeView.Resources>
</TreeView>

TreeView привязан к ADRoot.Children:

class ADTreeViewModel : OUModel
{
    public OUModel ADRoot { get; set; } = new OUModel(null, false);
}

class OUModel : PropertyChangedBase, ITreeViewItemViewModel
{
    // TreeView is bound to this property, which holds a collection of more OUModel objects
    public BindableCollection<ITreeViewItemViewModel> Children { get; set; } = new BindableCollection<ITreeViewItemViewModel>();

    // The ListView's ItemSource is bound to ADTree.SelectedItem.Computers which is this property
    public List<RemoteComputer> Computers
    {
        get { return computers; }
        set { computers = value; NotifyOfPropertyChange(); } 
    }

// PropertyChangedBase is from Caliburn.Micro
class RemoteComputer : PropertyChangedBase
{

    // All other properties in this class are being displayed correctly in the ListView, so the DataContext is correct E.g.:
    public string Name { get; set; }

    private bool isSelected = false;

    // The ListViewItem's IsSelected property is bound to this
    public bool IsSelected
    {
        get { return isSelected; }
        set
        {
            isSelected = value;
            NotifyOfPropertyChange(); // Caliburn.Micro gets the property name itself

            // I've also tried adding the following
            NotifyOfPropertyChange(() => Parent.Children);
            NotifyOfPropertyChange(() => Parent);
        }
    }
}

Вот проводник Live Property для выбранного элемента:

Live Property Explorer

1 Ответ

0 голосов
/ 19 февраля 2020

Try UpdateSourceTrigger=PropertyChanged

<Setter Property="IsSelected" Value="{Binding IsSelected, UpdateSourceTrigger=PropertyChanged}" />

Свойство IsSelected должно присутствовать в классе, который связан с DataContext Control, реализующим интерфейс INotifyPropertyChanged, таким образом

private bool _isSelected
public bool IsSelected
{
    get => _isSelected;
    set
    {
        _isSelected = value;
        OnPropertyChanged(nameof(IsSelected));
    }
}
...