DataTrigger doesn't fire when scrolling in ListView

We have a problem with a couple of ListView controls in WPF, these controls are connected to each other to work as a single grid with a frozen column on the right side that contains a checkbox. This is so that the left section will scroll, but the right flag will always remain on the screen.

We also have a range of data that is needed to set the visual state in a custom list style. This is used to highlight the background color for the selected lines (we also have the selected element style).

We decided to use datatriggers to trigger viusal states, rather than setting the background color of the string, as this does not give us the necessary control over the design.

The problem we are currently experiencing is related to the scroll of the ListView when it contains a large number of rows; we believe that this causes the control to redraw the content, however it does not seem to trigger data setting the corresponding visual states for each row.

Two ListView controllers.

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

In order to run datatriggers, we had to set them in the GridViewColumn template table, this may be part of the problem, however, if we put them in another place, they will not respond.

This is a copy of the style used for list items; There is a left and right version of this style, however their content is almost identical.

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

In the view model, an ObservableCollection is delayed, which is bound to both ListView controls. This contains a number of details about the project, but all of them are connected without problems. VisualItemState is used to control datatriggers and is part of the code below.

  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 } 

We are currently at a dead end ..... Help :)

+4
source share
1 answer

The only way we could find a solution to this problem is to use the following operator in both views of the list. I believe that this allows you to physically scroll through the content as opposed to logical scrolling and therefore does not cause redrawing (I'm sure someone can fix me about this :)).

ScrollViewer.CanContentScroll = "False"

It must be installed on both lists, otherwise you may encounter very strange list behavior.

+2
source

Source: https://habr.com/ru/post/1481335/


All Articles