wpf – 在ListView中滚动时DataTrigger不会触发

我们在
WPF中遇到一对ListView控件的问题,这些控件链接在一起作为单个网格,右侧有一个包含复选框的冻结列.这样左侧部分将可滚动,但右侧复选框将始终保留在屏幕上.

我们还有许多数据触发器,需要在自定义列表视图样式中设置可视状态.这用于突出显示所选行的背景颜色(我们还有一个选定的项目样式).

我们选择使用数据触发器来触发viusal状态,而不是设置行的背景颜色,因为这不会给我们提供对设计的必要控制.

我们当前遇到的问题与ListView包含大量行时滚动有关;我们认为这导致控件重绘内容,但是它似乎没有激发数据触发器设置每行的相关视觉状态.

两个ListView控制器.

<StackPanel Name="dataGridProjects" Orientation="Horizontal" Height="300">
    <ListView Name="listView1" ItemsSource="{Binding List}" Width="700" ScrollViewer.VerticalScrollBarVisibility="Hidden" 
        ScrollViewer.ScrollChanged="listView1ScrollChanged" SelectedItem="{Binding ListSelected}" BorderThickness="0" >

        <ListView.View>
            <GridView>
                <!-- This column is used to fire the visual states and is hidden -->
                <GridViewColumn Header="" Width="0">
                    <GridViewColumn.CellTemplate>
                        <DataTemplate>
                            <Grid>
                                <i:Interaction.Triggers>
                                    <ie:DataTrigger Binding ="{Binding VisualItemState}" Value="0">
                                        <ie:GoToStateAction StateName="ItemUnselected" TargetObject="{Binding ElementName=ItemRootGrid}" UseTransitions="False" ></ie:GoToStateAction>
                                    </ie:DataTrigger>
                                    <ie:DataTrigger Binding ="{Binding VisualItemState}" Value="1">
                                        <ie:GoToStateAction StateName="ItemSelected" TargetObject="{Binding ElementName=ItemRootGrid}" UseTransitions="False" ></ie:GoToStateAction>
                                    </ie:DataTrigger>
                                    <ie:DataTrigger Binding ="{Binding VisualItemState}" Value="2">
                                        <ie:GoToStateAction StateName="ItemCompleted" TargetObject="{Binding ElementName=ItemRootGrid}" UseTransitions="False" ></ie:GoToStateAction>
                                    </ie:DataTrigger>
                                    <ie:DataTrigger Binding ="{Binding VisualItemState}" Value="3">
                                        <ie:GoToStateAction StateName="ItemHasConflicts" TargetObject="{Binding ElementName=ItemRootGrid}" UseTransitions="False" ></ie:GoToStateAction>
                                    </ie:DataTrigger>
                                </i:Interaction.Triggers>
                            </Grid>
                        </DataTemplate>
                    </GridViewColumn.CellTemplate>
                </GridViewColumn>

                <GridViewColumn DisplayMemberBinding="{Binding ProjName}" >
                    <GridViewColumn.HeaderTemplate>
                        <DataTemplate>
                            <TextBlock Name="txtProjName" Text="{Binding DescProjectReference}" MinWidth="150" />
                        </DataTemplate>
                    </GridViewColumn.HeaderTemplate>
                </GridViewColumn>
                <GridViewColumn DisplayMemberBinding="{Binding VisualItemState}" >
                    <GridViewColumn.HeaderTemplate>
                        <DataTemplate>
                            <TextBlock Name="txtVisState" Text="VisualItemState" MinWidth="150"/>
                        </DataTemplate>
                    </GridViewColumn.HeaderTemplate>
                </GridViewColumn>
                <GridViewColumn DisplayMemberBinding="{Binding ItemState}" >
                    <GridViewColumn.HeaderTemplate>
                        <DataTemplate>
                            <TextBlock Name="txtItemState" Text="ItemState" MinWidth="150"/>
                        </DataTemplate>
                    </GridViewColumn.HeaderTemplate>
                </GridViewColumn>
                <GridViewColumn DisplayMemberBinding="{Binding IsSelected}" >
                    <GridViewColumn.HeaderTemplate>
                        <DataTemplate>
                            <TextBlock Name="txtIsSelected" Text="IsSelected" MinWidth="250"/>
                        </DataTemplate>
                    </GridViewColumn.HeaderTemplate>
                </GridViewColumn>

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

            <Style TargetType="ListViewItem" BasedOn="{StaticResource ExtendedListViewItemLeft}">
                <Setter Property="IsEnabled" Value="{Binding Path=ProjectSyncRecord.IsEnabled, Mode=TwoWay}"/>
            </Style>

        </ListView.ItemContainerStyle>

    </ListView>

    <ListView Name="listView2" ItemsSource="{Binding List}" ScrollViewer.ScrollChanged="listView2ScrollChanged" SelectedItem="{Binding ListSelected}" BorderThickness="0" >
        <ListView.View>
            <GridView>
                <GridViewColumn Header="IsSelected" >
                    <GridViewColumn.CellTemplate>
                        <DataTemplate>
                            <Grid>
                                <!-- Triggers for the visual states -->
                                <i:Interaction.Triggers>
                                    <ie:DataTrigger Binding ="{Binding Path=VisualItemState}" Value="0">
                                        <ie:GoToStateAction StateName="ItemUnselected" TargetObject="{Binding ElementName=ItemRootGrid}" UseTransitions="False" ></ie:GoToStateAction>
                                    </ie:DataTrigger>
                                    <ie:DataTrigger Binding ="{Binding Path=VisualItemState}" Value="1">
                                        <ie:GoToStateAction StateName="ItemSelected" TargetObject="{Binding ElementName=ItemRootGrid}" UseTransitions="False" ></ie:GoToStateAction>
                                    </ie:DataTrigger>
                                    <ie:DataTrigger Binding ="{Binding Path=VisualItemState}" Value="2">
                                        <ie:GoToStateAction StateName="ItemCompleted" TargetObject="{Binding ElementName=ItemRootGrid}" UseTransitions="False" ></ie:GoToStateAction>
                                    </ie:DataTrigger>
                                    <ie:DataTrigger Binding ="{Binding Path=VisualItemState}" Value="3">
                                        <ie:GoToStateAction StateName="ItemHasConflicts" TargetObject="{Binding ElementName=ItemRootGrid}" UseTransitions="False" ></ie:GoToStateAction>
                                    </ie:DataTrigger>
                                </i:Interaction.Triggers>

                                <CheckBox IsChecked="{Binding Path=IsSelected, Mode=TwoWay}" IsEnabled="{Binding Path=ProjectSyncRecord.IsEnabled}" MinWidth="100"/>
                            </Grid>
                        </DataTemplate>
                    </GridViewColumn.CellTemplate>

                </GridViewColumn>

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

            <Style TargetType="ListViewItem" BasedOn="{StaticResource ExtendedListViewItemRight}">
                <Setter Property="IsEnabled" Value="{Binding Path=ProjectSyncRecord.IsEnabled, Mode=TwoWay}"/>
            </Style>

        </ListView.ItemContainerStyle>
    </ListView>

</StackPanel>

为了让数据触发器触发,我们必须在GridViewColumn celltemplate中设置它们,这可能是问题的一部分,但是如果我们将它们放在其他任何地方它们都不会响应.

这是用于listview项目的样式的副本;这种风格有左右两种版本,但它们的内容几乎完全相同.

<Style x:Key="ExtendedListViewItemLeft" TargetType="ListViewItem">
    <Setter Property="Padding" Value="5"/>
    <Setter Property="HorizontalContentAlignment" Value="Left"/>
    <Setter Property="VerticalContentAlignment" Value="Top"/>
    <Setter Property="Background" Value="Transparent"/>
    <Setter Property="BorderThickness" Value="1"/>
    <Setter Property="FontSize" Value="12" />
    <Setter Property="MinHeight" Value="25" />
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="ListBoxItem">
                <Grid x:Name="ItemRootGrid" Background="{TemplateBinding Background}">
                    <VisualStateManager.VisualStateGroups>
                        <VisualStateGroup x:Name="CommonStates">
                            <VisualState x:Name="Normal"/>
                            <VisualState x:Name="MouseOver">
                                <Storyboard>
                                    <DoubleAnimation Duration="0" To=".35" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="fillColor"/>
                                </Storyboard>
                            </VisualState>
                            <VisualState x:Name="Disabled">
                                <Storyboard>
                                    <DoubleAnimation Duration="0" To=".55" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="contentPresenter"/>
                                    <DoubleAnimation Duration="0" To="1" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="fillColorDisabled"/>
                                </Storyboard>
                            </VisualState>
                        </VisualStateGroup>
                        <VisualStateGroup x:Name="SelectionStates">
                            <VisualState x:Name="Unselected"/>
                            <VisualState x:Name="Selected">
                                <Storyboard>
                                    <ObjectAnimationUsingKeyFrames Duration="0" Storyboard.TargetProperty="Visibility" Storyboard.TargetName="FocusVisualElement">
                                        <DiscreteObjectKeyFrame KeyTime="0">
                                            <DiscreteObjectKeyFrame.Value>
                                                <Visibility>Visible</Visibility>
                                            </DiscreteObjectKeyFrame.Value>
                                        </DiscreteObjectKeyFrame>
                                    </ObjectAnimationUsingKeyFrames>
                                </Storyboard>
                            </VisualState>
                        </VisualStateGroup>
                        <VisualStateGroup x:Name="FocusStates">
                            <VisualState x:Name="Focused" />
                            <VisualState x:Name="Unfocused"/>
                        </VisualStateGroup>
                        <VisualStateGroup Name="SelectedStates">
                            <VisualState x:Name="ItemSelected">
                                <Storyboard>
                                    <DoubleAnimation Duration="00:00:00.25" To=".75" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="fillColorSelected"/>
                                </Storyboard>
                            </VisualState>
                            <VisualState x:Name="ItemUnselected">
                                <Storyboard>
                                    <DoubleAnimation Duration="00:00:00.25" To="0" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="fillColorSelected"/>
                                </Storyboard>
                            </VisualState>
                        </VisualStateGroup>
                    </VisualStateManager.VisualStateGroups>

                    <Border x:Name="fillColor" Background="#FFBADDE9" IsHitTestVisible="False" Opacity="00" CornerRadius="10,0,0,10" Margin="2,2,0,2"/>
                    <Border x:Name="fillColor2" Background="#FFBADDE9" IsHitTestVisible="False" Opacity="0" CornerRadius="10,0,0,10" Margin="2,2,0,2"/>
                    <Border x:Name="fillColorSelected" Background="#FFBADDE9" IsHitTestVisible="False" Opacity="0" CornerRadius="10,0,0,10" Margin="2,2,0,2"/>
                    <Border x:Name="fillColorDisabled" Background="LightGray" IsHitTestVisible="False" Opacity="0" CornerRadius="10,0,0,10" Margin="2,2,0,2"/>

                    <GridViewRowPresenter x:Name="contentPresenter" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" Margin="{TemplateBinding Padding}" />

                    <Border x:Name="FocusVisualElement" BorderBrush="#FF6DBDD1" BorderThickness="1" CornerRadius="10,0,0,10" Margin="2,2,0,2" Visibility="Collapsed"/>
                    <!--<Rectangle x:Name="FocusVisualElement" RadiusY="4" RadiusX="4" Margin="2" Stroke="#FF6DBDD1" StrokeThickness="1" Visibility="Collapsed"/>-->

                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

后面的viewmodel包含一个ObservableCollection,它绑定到两个ListView控件.这包含了关于该项目的一些细节,但是这些都是没有问题的. VisualItemState用于控制数据触发器,并且是下面代码的一部分.

    public class SyncObject : NotificationObject
    {
        #region Fields

        /// <summary>
        /// Is the option selected.
        /// </summary>
        private bool isSelected;

        /// <summary>
        /// The project sync record.
        /// </summary>
        private ProjectSync projectSyncRecord;

        /// <summary>
        /// Set the state for the UI 
        /// </summary>
        private ItemState visualItemState;

        #endregion Fields

        #region Properties

        /// <summary>
        /// Gets or sets a value indicating whether IsSelected.
        /// </summary>
        public bool IsSelected
        {
            get
            {
                return this.isSelected;
            }

            set
            {
                this.isSelected = value;

                this.VisualItemState = value ? ItemState.Selected : ItemState.Unselected;

                this.RaisePropertyChanged(() => this.IsSelected);
            }
        }

        /// <summary>
        /// Gets or sets ProjectSyncRecord.
        /// </summary>
        public ProjectSync ProjectSyncRecord
        {
            get
            {
                return this.projectSyncRecord;
            }

            set
            {
                this.projectSyncRecord = value;
                this.RaisePropertyChanged(() => this.ProjectSyncRecord);
            }
        }

        /// <summary>
        /// Gets or sets VisualItemState.
        /// </summary>
        public ItemState VisualItemState
        {
            get
            {
                return this.visualItemState;
            }

            set
            {
                this.visualItemState = value;
                this.RaisePropertyChanged(() => this.VisualItemState);
            }
        }

        public string ProjName { get; set; }

        #endregion Properties
    }

我们目前难倒…..帮助:)

最佳答案 我们能够找到解决此问题的唯一方法是在两个列表视图上使用以下语句.我认为这将内容设置为物理滚动而不是逻辑滚动,因此不会导致重绘(我确信有人可能会纠正我:)).

ScrollViewer.CanContentScroll = “假”

必须在两个列表视图上设置它,否则您可能会在列表视图中遇到一些非常奇怪的行为.

点赞