You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WPF自定义TrackPanel(ListBox)点击选中及拖动选中小切换问题

视频剪辑时间线轨道模块开发问题

背景

我正在开发视频剪辑软件的时间线(轨道)模块,为方便管理ItemsSource和SelectedItem(s),自定义了TrackPanel : ListBox控件并定义样式。

第一阶段:Thumb拦截点击事件问题

最初实现时无法点击选中剪辑片段,原因是点击事件被Thumb拦截,相关代码如下:

C#逻辑代码

public TrackPanel()
{
    AddHandler(Thumb.DragDeltaEvent, new DragDeltaEventHandler(OnThumbDragDelta), true);
}

private void OnThumbDragDelta(object sender, DragDeltaEventArgs e)
{
    if (e.OriginalSource is Thumb thumb && ContainerFromElement(thumb) is ListBoxItem item)
    {
        if (thumb.Name is "thumbTrimHandleLeft" or "thumbTrimHandleRight")
        {
            return;
        }

        if (item.RenderTransform is not TranslateTransform transform)
        {
            transform = new TranslateTransform();
            item.RenderTransform = transform;
        }

        transform.X += e.HorizontalChange;
        transform.Y += e.VerticalChange;
    }
}

XAML样式代码

<Style TargetType="{x:Type c:TrackPanel}">
        <Setter Property="ItemTemplate">
        <Setter.Value>
            <DataTemplate>
                <Thumb>
                    <Thumb.Template>
                        <ControlTemplate TargetType="{x:Type Thumb}">
                            <c:ClipControl />
                        </ControlTemplate>
                    </Thumb.Template>
                </Thumb>
            </DataTemplate>
        </Setter.Value>
    </Setter>

    <Setter Property="ItemsPanel">
        <Setter.Value>
            <ItemsPanelTemplate>
                <Canvas HorizontalAlignment="Stretch"
                        IsItemsHost="True" />
            </ItemsPanelTemplate>
        </Setter.Value>
    </Setter>

    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type ListBox}">
                <ItemsPresenter />
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

此前我曾用TrackPanel : Canvas实现,逻辑更简单,但需手动实现ItemsSource和SelectedItem(s),因此未采用该方案。


第二阶段:原生鼠标事件拖动导致选中项异常

改用原生鼠标事件实现拖动后,点击选中问题解决,但出现选中项自动切换的异常:

拖动时选中项切换异常

修改后的XAML样式代码

<Style TargetType="{x:Type c:TrackPanel}">
    <Setter Property="ItemContainerStyle">
        <Setter.Value>
            <Style TargetType="ListBoxItem">
                <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
                <Setter Property="Panel.ZIndex" Value="0" />

                <Style.Triggers>
                    <Trigger Property="IsSelected" Value="True">
                        <Setter Property="Panel.ZIndex" Value="999" />
                    </Trigger>
                </Style.Triggers>

            </Style>
        </Setter.Value>
    </Setter>

    <Setter Property="ItemTemplate">
        <Setter.Value>
            <DataTemplate DataType="{x:Type m:Clip}">
                <c:ClipControl IsSelected="{Binding IsSelected}" />
            </DataTemplate>
        </Setter.Value>
    </Setter>

    <Setter Property="ItemsPanel">
        <Setter.Value>
            <ItemsPanelTemplate>
                <Canvas HorizontalAlignment="Stretch"
                        IsItemsHost="True" />
            </ItemsPanelTemplate>
        </Setter.Value>
    </Setter>

    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type ListBox}">
                <ItemsPresenter />
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

修改后的C#逻辑代码

public TrackPanel()
{
    AddHandler(MouseLeftButtonDownEvent, new MouseButtonEventHandler(OnClipMouseLeftButtonDown), true);
    AddHandler(MouseMoveEvent, new MouseEventHandler(OnClipMouseMove), true);
    AddHandler(MouseLeftButtonUpEvent, new MouseButtonEventHandler(OnClipMouseLeftButtonUp), true);
}

#region Drag Handling

private UIElement? _draggedElement;

private Point _dragStartPoint;

private bool _isDragging = false;

private void OnClipMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
    if (e.OriginalSource is DependencyObject source)
    {
        if (ContainerFromElement(source) is UIElement item)
        {
            _dragStartPoint = e.GetPosition(this);
            _isDragging = true;
            _draggedElement = item;
            CaptureMouse();
        }
    }
}

private void OnClipMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
    if (_isDragging)
    {
        _isDragging = false;
        _draggedElement = null;
        ReleaseMouseCapture();
    }
}

private void OnClipMouseMove(object sender, MouseEventArgs e)
{
    if (_isDragging && _draggedElement != null && e.LeftButton == MouseButtonState.Pressed)
    {
        var current = e.GetPosition(this);
        var delta = current - _dragStartPoint;

        double left = Canvas.GetLeft(_draggedElement);
        if (System.Double.IsNaN(left))
        {
            left = 0;
        }

        double top = Canvas.GetTop(_draggedElement);
        if (System.Double.IsNaN(top))
        {
            top = 0;
        }

        Canvas.SetLeft(_draggedElement, left + delta.X);
        Canvas.SetTop(_draggedElement, top + delta.Y);

        _dragStartPoint = current;
    }
}

#endregion Drag Handling

内容的提问来源于stack exchange,提问作者CodingNinja

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 21:05:12