【问题标题】:Two overlapping ListBoxes. Selection problem两个重叠的列表框。选择问题
【发布时间】:2011-07-01 13:59:40
【问题描述】:

我试图在占据相同空间的两个单独的列表框中显示形状。我已将背景设置为透明和 {x:Null},但鼠标点击仍被最顶部的列表框捕获,因此我无法从底层列表框中选择任何形状。

这里是一些重现问题的示例代码。

<Grid>
    <!-- ListBox 1 -->
    <ListBox Background="{x:Null}">
        <ListBox.ItemsPanel>
            <ItemsPanelTemplate>
                <Canvas Background="{x:Null}"/>
            </ItemsPanelTemplate>
        </ListBox.ItemsPanel>
        <ListBox.ItemTemplate>
            <DataTemplate>
                <Grid Background="Transparent">
                    <Ellipse Width="100" Height="100" Stroke="Blue" StrokeThickness="10"/>
                </Grid>
            </DataTemplate>
        </ListBox.ItemTemplate>
        1
    </ListBox>

    <!-- ListBox 2 -->
    <ListBox Background="{x:Null}">
        <ListBox.ItemsPanel>
            <ItemsPanelTemplate>
                <Canvas Background="{x:Null}"/>
            </ItemsPanelTemplate>
        </ListBox.ItemsPanel>
        <ListBox.ItemContainerStyle>
            <Style TargetType="ListBoxItem">
                <Setter Property="Canvas.Left" Value="100"/>
                <Setter Property="Canvas.Top" Value="100"/>
            </Style>
        </ListBox.ItemContainerStyle>
        <ListBox.ItemTemplate>
            <DataTemplate>
                <Ellipse Width="100" Height="100" Stroke="Blue" StrokeThickness="10"/>
            </DataTemplate>
        </ListBox.ItemTemplate>
        1
    </ListBox>
</Grid>

这就是我现在解决这个问题的方法,但我对其他建议持开放态度:) 我在 Grid 上启用了命中测试,并为两个 ListBox 禁用了它。然后我改为在事件处理程序中进行命中测试

<Grid MouseDown="Grid_MouseDown"
      IsHitTestVisible="True"
      Background="Transparent">

    <!-- ListBox 1 -->
    <ListBox Background="Transparent"
             IsHitTestVisible="True"
             ..>
    </ListBox>

    <!-- ListBox 2 -->
    <ListBox Background="Transparent"
             IsHitTestVisible="True"
             ..>
    </ListBox>
</Grid>

事件处理程序和命中测试

private void Grid_MouseDown(object sender, MouseButtonEventArgs e)
{
    Grid grid = sender as Grid;
    Point ptCurrent = e.GetPosition(grid);
    VisualTreeHelper.HitTest(grid, null, new HitTestResultCallback(HitTestCallback), new PointHitTestParameters(ptCurrent));
}
public HitTestResultBehavior HitTestCallback(HitTestResult htrResult)
{
    ListBoxItem listBoxItem = GetVisualParent<ListBoxItem>(htrResult.VisualHit);
    if (listBoxItem != null)
    {
        listBoxItem.IsSelected = true;
        return HitTestResultBehavior.Stop;
    }
    return HitTestResultBehavior.Continue;
}
public T GetVisualParent<T>(object child) where T : Visual
{
    DependencyObject c = child as DependencyObject;
    while ((c != null) && !(c is T))
    {
        c = VisualTreeHelper.GetParent(c);
    }
    return c as T;
}

【问题讨论】:

  • 为什么不在一个列表框中包含所有形状?两个列表框的方法似乎真的不太可能得到你想要的。
  • 这是我的最后一次。我在地图上显示项目,它们根本不共享相同的数据,所以这就是我使用两个 ListBox 的原因。 ItemsSource 是 DataTables

标签: c# wpf xaml listbox itemspaneltemplate


【解决方案1】:

您可以使用 CompositeCollection 作为项目源将多组数据绑定到单个 ListBox:

<ListBox ...>
  <ListBox.ItemsSource>
    <CompositeCollection>
      <CollectionContainer Collection={Binding ...}" />
      <CollectionContainer Collection={Binding ...}" />
    </CompositeCollection>
  </ListBox.ItemsSource>
</ListBox>

然后您可以使用数据模板来控制不同数据类型的外观。您可以使用隐式数据模板,也可以使用ItemTemplateSelector

有关使用和绑定到 CompositeCollection 的更多信息,请参阅此资源:How do you bind a CollectionContainer to a collection in a view model?

【讨论】:

  • 谢谢,这正是我想要的!
【解决方案2】:

您可以将您的列表框绑定到一个可见性变量。这样,当您处于将选择底部框而顶部折叠时,您可以使底部框可见,当您需要选择顶部框时,反之亦然。

【讨论】:

  • 问题是我的两个 ListBox 始终可见,谢谢
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-12-09
  • 1970-01-01
  • 1970-01-01
  • 2014-01-06
  • 2012-12-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多