質問

We are having an issue with a pair of ListView controls in WPF, these controls are linked together to work as a single grid with a frozen column on the right hand side which contains a checkbox. This is so that the left hand section will be scrollable but the right checkbox will always remain on the screen.

We also have a number of datatriggers which are required to set the visual state in the customized listview style. This is used to highlight the background colour of the selected rows (we also have a selected item style).

We have chosen to use datatriggers to fire the viusal states, rather than setting the background colour of the row as this doesn't give us the required control over the design.

The issue we are currently experiencing is related to scrolling the ListView when it contains a large number of rows; we believe that this is causing the control to redraw the content, however it then does not seem to fire the datatriggers setting the relevant visual states for each row.

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

To get the datatriggers to fire we had to set them in a GridViewColumn celltemplate, this may be part of the issue, however if we put them anywhere else they would not respond.

This is a copy of the style being used for the listview 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>

The viewmodel behind holds an ObservableCollection which is bound to both of the ListView controls. This holds a number of details about the project, however these are all being bound without issue. The VisualItemState is being used to control the 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 stumped..... Help :)

役に立ちましたか?

解決

The only way we were able to find to resolve this issue was to use the following statement on both of the list views. I believe this sets the content to physically scroll as opposed to logically scrolling and therefore doesn't cause a redraw (I'm sure someone may correct me on this :) ).

ScrollViewer.CanContentScroll="False"

It must be set on both listviews, otherwise you may experience some very strange behaviour accross the listviews.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top