1

I'm trying to display shapes in two separate Listboxes occupying the same space. I've set the Background to both Transparent and {x:Null} but the mouseclick is still getting captured by the topmost Listbox so I can't select any shapes from the underlying ListBox.

Here is some sample code reproducing the problem.

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

This is how I solved this problem for now but I'm more than open for other suggestions :) I enabled hittesting on the Grid and disabled it for both ListBoxes. Then I did the hittesting in the event handler instead

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

Event handler and hittesting

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;
}
George
  • 13
  • 3
  • Why don't you have all the shapes in a single listbox? It seems really unlikely that the two-listbox approach will ever get you what you want. – antlersoft Jul 01 '11 at 14:03
  • That's my last out.. I'm dispalying items on top of a map and they don't share the same data at all so that's why I'm using two ListBoxes. The ItemsSource is DataTables – George Jul 01 '11 at 14:08

2 Answers2

2

You can bind multiple sets of data to a single ListBox by using a CompositeCollection as the items source:

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

You can then use data templates to control the appearance of different data types. You can either use implicit data templates or you can use an ItemTemplateSelector.

For more information about using and binding to a CompositeCollection, see this resource: How do you bind a CollectionContainer to a collection in a view model?

Community
  • 1
  • 1
sellmeadog
  • 7,437
  • 1
  • 31
  • 45
0

You could bind your ListBoxes to a Visibility variable. This way you can make the bottom box visible when you are in a situation where the bottom one would be selected and the top on collapsed and visa verse when you need the top one to be selected.

J Lundberg
  • 2,313
  • 2
  • 20
  • 23