绑定数据在VirtualizingStackPanel上断开连接

18
首先,免责声明,我正在使用.NET 3.5的虚拟堆栈面板。如果您在未来版本中获得不同的行为,请让我知道。你可以很容易地设置一个带有listviews的测试用例来测试这个问题。 我在虚拟堆栈面板中有一个物品容器样式,将IsSelected属性绑定到视图模型上。 当我选择视图模型中屏幕外的未选择项目,然后滚动到该项目时,数据上下文(视图模式)和实际的listviewitem都具有IsSelected属性为true(期望行为)。该触发器被正确应用于listviewitem并突出显示它。 然而,当我取消选择不在视图中的项目的数据上下文,然后向下滚动直到该项目在视图中,达到项目并创建它时,该项目的数据上下文现在具有IsSelected=true,listviewitem的IsSelected属性也为true,因此listviewitem最终会从触发器中选择矩形(不正确的行为)。 这几乎就像ListViewItem的所有属性在创建项时都被恢复了(这对我来说是有道理的,但是然后它们应该将数据上下文的值绑定到项之后)。 但是似乎并没有发生这种情况。而且,在无法取消选择该项并滚回找到它被选中之后,如果我然后选择/取消选择它,则绑定对该项没有影响。 我看不出来为什么选择视图模型中屏幕外的项目会起作用,而取消选择屏幕外的项目则不会起作用。在两种情况下,新创建的项都应需要重新绑定到视图模型的当前值。但是,一个可以工作而另一个不行。 编辑:啊,好的,所以我不能同时使用回收模式和绑定。谢谢@devhedgehog。我会给你奖励,但你需要一个答案。我发誓我之前已经尝试过了,但也许之前我没有处理绑定列表视图中的点击事件,所以我在物理选择时破坏了绑定或其他原因。我记得在某个时候尝试了两种模式,但可能有其他东西干扰了它,所以它无法工作。反正现在它能用了。 由于您提到它,我希望最好避免保留不必要的代码,并从VirtualizingPanel而不是VirtualizingStackPanel继承。但是我想能够设置水平滚动范围,这需要我重新实现IScrollInfo。但是,我无法让虚拟堆栈面板与IScrollInfo良好地交互。
      <ListView
        x:Name="TestLV"
        VerticalAlignment="Stretch"
        HorizontalAlignment="Stretch"
        Background="Green" 
        ItemsSource="{Binding Path=AddedItems, Mode=OneWay}"
        SnapsToDevicePixels="True"
        VirtualizingStackPanel.VirtualizationMode="Recycling" 
        VirtualizingStackPanel.IsVirtualizing="true"
        ScrollViewer.IsDeferredScrollingEnabled="False"
        Grid.Column ="4"
        MouseDown="TestLV_MouseDown"
        >
      <ListView.ItemContainerStyle>
        <Style TargetType="ListViewItem">
          <Setter Property="IsSelected" Value="{Binding Path=IsSelected, Mode=OneWay}" />
          <Setter Property="Template">
            <Setter.Value>
              <ControlTemplate TargetType="{x:Type ListViewItem}">
                <Grid 
                    x:Name="SignalGrid"
                    Background="Transparent"
                    >
                  <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="*"/>
                  </Grid.ColumnDefinitions>
                  <Grid.RowDefinitions>
                    <RowDefinition Height="Auto"/>
                    <RowDefinition Height="*"/>
                  </Grid.RowDefinitions>
                  <Border 
                      Name="Bd"
                      BorderBrush="{TemplateBinding BorderBrush}"
                      BorderThickness="{TemplateBinding BorderThickness}"
                      Padding="{TemplateBinding Padding}"
                      SnapsToDevicePixels="true">
                    <ContentPresenter 
                        x:Name="PART_Header"
                        SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
                        />
                  </Border>
                  <ItemsPresenter
                      x:Name="ItemsHost"
                      Grid.Row="1"
                      Grid.Column="0"
                      />
                </Grid>
                <ControlTemplate.Triggers>
                  <Trigger Property="IsSelected"
                               Value="false">
                    <Setter 
                        TargetName="SignalGrid"
                        Property="Background"
                        Value="Transparent"
                        />
                  </Trigger>
                  <Trigger Property="IsSelected"
                             Value="true">

                    <Setter 
                        TargetName="SignalGrid"
                        Property="Background"
                        Value="Navy" 
                        />
                  </Trigger>
                </ControlTemplate.Triggers>
              </ControlTemplate>
            </Setter.Value>
          </Setter>
        </Style>
      </ListView.ItemContainerStyle>
      <ListView.ItemsPanel>
        <ItemsPanelTemplate>
          <VirtualizingStackPanel />
          <!--<Components:VirtualizingTilePanel 
              ChildSize="{Binding Path=GraphHeight}"
              />-->
        </ItemsPanelTemplate>
      </ListView.ItemsPanel>
      <ListView.Template>
        <ControlTemplate>
          <Grid >
           
            <ScrollViewer
                
                >
              <ItemsPresenter />
            </ScrollViewer>
          </Grid>
        </ControlTemplate>
      </ListView.Template>
      <!--Template Defining the layout of items in this treeview-->
      <ListView.Resources>
        <HierarchicalDataTemplate 
            ItemsSource ="{Binding Path = bits}"
            DataType="{x:Type ViewModels:BusViewModel}"
            >
          <Grid>
            <Components:CenteredTextBlock
                x:Name="CommentTextBlock"
                Foreground="Black"
                BorderThickness="{Binding RelativeSource ={RelativeSource AncestorType={x:Type ListView}}, Path=BorderThickness}"
                BorderBrush="{Binding RelativeSource ={RelativeSource AncestorType={x:Type ListView}}, Path=BorderBrush}"
                HorizontalAlignment="Stretch"
                Height="{Binding ElementName=graph_viewer, Path=GraphHeight, Mode=OneWay}"
                >
              <Components:CenteredTextBlock.MainText>
                <MultiBinding Converter="{StaticResource StringConcatConverter}">
                  <Binding Path="Alias" />
                  <Binding Path="SignalValueAtPrimaryMarker" />
                </MultiBinding>
              </Components:CenteredTextBlock.MainText>
            </Components:CenteredTextBlock>

          </Grid>
        </HierarchicalDataTemplate>
        <DataTemplate
            DataType="{x:Type ViewModels:BitViewModel}"
            >
          <Grid>
            <Components:CenteredTextBlock
                Foreground="Black"
                BorderThickness="{Binding RelativeSource ={RelativeSource AncestorType={x:Type ListView}}, Path=BorderThickness}"
                BorderBrush="{Binding RelativeSource ={RelativeSource AncestorType={x:Type ListView}}, Path=BorderBrush}"
                HorizontalAlignment="Stretch"
                Height="{Binding ElementName=graph_viewer, Path=GraphHeight, Mode=OneWay}">
              <Components:CenteredTextBlock.MainText>
                <MultiBinding Converter="{StaticResource StringConcatConverter}">
                  <Binding Path="Alias" />
                  <Binding Path="SignalValueAtPrimaryMarker" />
                </MultiBinding>
              </Components:CenteredTextBlock.MainText>
            </Components:CenteredTextBlock>
          </Grid>
        </DataTemplate>
        <DataTemplate
            DataType="{x:Type ViewModels:SelectableItemViewModel}"
            >
          <Grid>
            <Components:CenteredTextBlock
                Foreground="Red"
                BorderThickness="{Binding RelativeSource ={RelativeSource AncestorType={x:Type ListView}}, Path=BorderThickness}"
                BorderBrush="{Binding RelativeSource ={RelativeSource AncestorType={x:Type ListView}}, Path=BorderBrush}"
                HorizontalAlignment="Stretch"
                Height="{Binding ElementName=graph_viewer, Path=GraphHeight, Mode=OneWay}"
                MainText="{Binding Path = FullName}"
                
                />
          </Grid>
        </DataTemplate>
      </ListView.Resources>
    </ListView>

5
为什么您不使用VirtualizingStackPanel的measureoverride方法呢?使用VirtualizingStackPanel可以解决您的问题。顺便说一句,我检查了您的MeasureOverride方法,发现您缺少VirtualizingStackPanel具有的一些功能。您没有包含偏移量。您没有跟踪聚焦元素。当您处于回收模式时,您需要在测量子项之前和之后进行清理,否则元素将被插入错误的顺序... - dev hedgehog
所以我使用了一个关于创建虚拟化平铺面板的教程,这个MeasureOverride就是那里使用的。抱歉我忘记链接它了,我会编辑我的帖子。 - James Joshua Street
1
请使用标准的VirtualizingStackPanel而不是您自己的测量逻辑。在您的逻辑中没有任何特殊的东西,VirtualizingStackPanel都可以做到。RecyclingMode不应该是Recycle,而是将其留空或更改为Standard。如果没有演示,很难理解您的意思。请上传一个演示。您知道,我们喜欢看代码示例。 - dev hedgehog
无论如何,您的答案解决了我的主要问题。不过我很好奇,使用其iscrollinfo实现中的项来滚动虚拟堆栈面板。是否可以以像素为单位存储horizontalextent和viewportwidth?我认为我没有使用虚拟堆栈面板的原因是我担心VSP实现在某个时候会假定我重写的iscrollinfo方法将返回项而不是像素。对于虚拟化目的在一个方向上测量项目,在另一个方向上以像素为单位测量,这相当奇怪。 - James Joshua Street
6
答案是否定的,VSP按单位滚动,这意味着它会跳过某些项目。但是它具有按像素滚动的功能。如果您使用.NET 4.5,您将能够激活该功能。但您使用的是3.5版本。在.NET 3.5中,只有TreeView允许按像素滚动。这意味着,如果您想要平滑滚动,请将列表放入TreeView中。带有列表的TreeView与ListBox相同。某种程度上。两者都执行相同的操作。 - dev hedgehog
显示剩余8条评论
1个回答

1

这个问题似乎很奇怪,因为它实际上已经被回答了,但被列为没有答案。所以我会在这里发布dev hedgehog的评论/答案。

请使用标准的VirtualizingStackPanel而不是您自定义的测量逻辑。您的逻辑中没有任何特殊的东西,VirtualizingStackPanel无法处理。RecyclingMode不应该是Recycle,而是将其删除或更改为Standard。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接