开发者

How do I get ListBox, Canvas and Thumb to work together?

How do I get ListBox, Canvas and Thumb to work together?

I am attempting to reuse the selection logic of ListBox together开发者_如何学Go with a Canvas that contains draggable Thumbs.

Unfortunately the Thumb appears to handle the mouse events so that clicking on the Thumb doesn't make the item selected.

I was hoping these elements could be made to work together without resorting to workarounds in procedural code. If anyone knows if this is possible or how to do it please advise me.

Code examples follow.

In the XAML I define the ListBox and specify a Canvas as the ItemsPanel:

<Window x:Class="ListBoxCanvasThumb.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300"
    Loaded="Window_Loaded"
    >
    <Grid>
        <ListBox
            x:Name="listBox"
            >
            <ListBox.ItemsPanel>
                <ItemsPanelTemplate>                
                    <Canvas />
                </ItemsPanelTemplate>
            </ListBox.ItemsPanel>
        </ListBox>
    </Grid>
</Window>

In the Loaded event handler I create a draggable Thumb, wrap it in a ListBoxItem, set the positon in the Canvas and then add it to the ListBox:

private void Window_Loaded(object sender, RoutedEventArgs e)
{
    Thumb t = new Thumb();
    t.Width = 10;
    t.Height = 10;
    t.DragDelta += new DragDeltaEventHandler(thumb_DragDelta);

    ListBoxItem i = new ListBoxItem();
    Canvas.SetLeft(i, 10);
    Canvas.SetTop(i, 10);
    i.Content = t;

    listBox.Items.Add(i);
}

In the DragDelta event handler I update the position of the item in the Canvas:

void thumb_DragDelta(object sender, DragDeltaEventArgs e)
{
    ListBoxItem i = (ListBoxItem)((Thumb)sender).Parent;
    Canvas.SetLeft(i, Canvas.GetLeft(i) + e.HorizontalChange);
    Canvas.SetTop(i, Canvas.GetTop(i) + e.VerticalChange);
}


For this purpose, your use of the Thumb control isn't really buying you all that much, and it conflicts in several ways with what you are trying to do. I would get rid of it.

It is very simple to make your items draggable without a Thumb by just intercepting mouse down, mouse move, and mouse up events:

  • In mouse down, set a "dragging" flag, note the current position, and capture the mouse
  • In mouse move, if "dragging" is true update Canvas.Left and Canvas.Top by the difference between the mouse position on the control and the original position
  • In mouse up, clear the "dragging" flag and clear the mouse capture

By doing this Thumb won't be intercepting keyboard and mouse clicks and messing with your ListBox.


I don't know if that will satisfy your requirement not to use procedural code, since apparently you already are (or was this only a reproduction example?)

Anyway, add a handler to the ListBoxItem for PreviewMouseDown and select the item there:

i.PreviewMouseDown += new MouseButtonEventHandler(LBI_PreviewMouseDown);

void LBI_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
    var lbi = (ListBoxItem)sender;
    lbi.IsSelected = true;
    lbi.Focus();
}


You can try moving the Thumb into the ListBoxItem template and using the Thumb's focus state to trigger selection. Thumb is not focusable by default but you can turn it on.

         <ListBox.ItemContainerStyle>
            <Style TargetType="{x:Type ListBoxItem}">
                <Setter Property="Canvas.Left" Value="10" />
                <Setter Property="Canvas.Top" Value="10" />
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="{x:Type ListBoxItem}">
                            <Border x:Name="Bd" ...>
                                <DockPanel>
                                    <Thumb x:Name="dragger" DockPanel.Dock="Top" 
                                           Width="50" Height="20" Focusable="True"/>
                                    <ContentPresenter/>
                                </DockPanel>
                            </Border>
                            <ControlTemplate.Triggers>
                                <Trigger SourceName="dragger" Property="IsFocused" Value="True">
                                    <Setter Property="IsSelected" Value="True" />
                                </Trigger>

...

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜