Rx DragBehavior ->为什么我的元素不动

发布于 2024-10-28 21:21:09 字数 4339 浏览 4 评论 0原文

我根据一般的拖放示例编写了一个 DragBehavior。虽然这在不处于行为中的情况下也可以工作,但当我将代码放入行为中时它不会移动。

行为:

public class DragBehavior : Behavior<UIElement>
    {

        protected override void OnAttached()
        {
            Window mainCanvas = Application.Current.MainWindow;

            var mouseDown = from evt in AssociatedObject.GetMouseLeftButtonDown()
                                select evt.EventArgs.GetPosition(mainCanvas);
            var mouseUp = from evt in AssociatedObject.GetMouseLeftButtonUp()
                            select evt.EventArgs.GetPosition(mainCanvas);
            var mouseMove = from evt in AssociatedObject.GetMouseMove()
                            select evt.EventArgs.GetPosition(mainCanvas);

            var q = from start in mouseDown
                    from delta in mouseMove.StartWith(start).TakeUntil(mouseUp)
                    .Let(mm => mm.Zip(mm.Skip(1),(pre,cur) =>
                        new{ X= cur.X - pre.X, Y= cur.Y - pre.Y}))
                        select delta;

            q.Subscribe(value =>
            {
                Canvas.SetLeft(AssociatedObject, Canvas.GetLeft(AssociatedObject) + value.X);
                Canvas.SetTop(AssociatedObject, Canvas.GetTop(AssociatedObject) + value.Y);
            });

        }
    }

帮助方法:

  public static IObservable<IEvent<MouseEventArgs>>  GetMouseMove(
             this UIElement inputElement)
        {

            return Observable.FromEvent(
                (EventHandler<MouseEventArgs> h) => new MouseEventHandler(h),
                h => inputElement.MouseMove += h,
                h => inputElement.MouseMove -= h);
        }

        public static IObservable<IEvent<MouseButtonEventArgs>>
          GetMouseLeftButtonDown(this UIElement inputElement)
        {
            return Observable.FromEvent(
                (EventHandler<MouseButtonEventArgs> genericHandler) =>
                    new MouseButtonEventHandler(genericHandler),
                            h => inputElement.MouseLeftButtonDown += (h),
                            h => inputElement.MouseLeftButtonDown -= (h));
        }

        public static IObservable<IEvent<MouseButtonEventArgs>>
            GetMouseLeftButtonUp(this UIElement inputElement)
        {
            return Observable.FromEvent(
                (EventHandler<MouseButtonEventArgs> genericHandler) =>
                    new MouseButtonEventHandler(genericHandler),
                            h => inputElement.MouseLeftButtonUp += h,
                            h => inputElement.MouseLeftButtonUp -= h);
        }}


   <Window x:Class="DesignerTest.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:vm="clr-namespace:DesignerTest.ViewModels"
    xmlns:h="clr-namespace:DesignerTest.Helpers"
    xmlns:e="http://schemas.microsoft.com/expression/2010/interactivity"
    Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
    <vm:WindowViewModel />
</Window.DataContext>
<Grid>
    <ItemsControl ItemsSource="{Binding Path=Shapes}">
     <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <Canvas />
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <StackPanel>
                    <e:Interaction.Behaviors>
                        <h:DragBehavior />
                    </e:Interaction.Behaviors>
                    <TextBlock Text="{Binding X}" />
                </StackPanel>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    <ItemsControl.ItemContainerStyle>
            <Style TargetType="ContentPresenter">
            <Setter Property="Canvas.Left" Value="{Binding Path=X,Mode=TwoWay}" />
            <Setter Property="Canvas.Top" Value="{Binding Path=Y,Mode=TwoWay}" />
        </Style>
    </ItemsControl.ItemContainerStyle>
    </ItemsControl>  
</Grid>

I wrote a DragBehavior based on the general Drag and Drop examples. While this is working without being in a Behavior, it is not moving when I place the code in a behavior.

Behavior:

public class DragBehavior : Behavior<UIElement>
    {

        protected override void OnAttached()
        {
            Window mainCanvas = Application.Current.MainWindow;

            var mouseDown = from evt in AssociatedObject.GetMouseLeftButtonDown()
                                select evt.EventArgs.GetPosition(mainCanvas);
            var mouseUp = from evt in AssociatedObject.GetMouseLeftButtonUp()
                            select evt.EventArgs.GetPosition(mainCanvas);
            var mouseMove = from evt in AssociatedObject.GetMouseMove()
                            select evt.EventArgs.GetPosition(mainCanvas);

            var q = from start in mouseDown
                    from delta in mouseMove.StartWith(start).TakeUntil(mouseUp)
                    .Let(mm => mm.Zip(mm.Skip(1),(pre,cur) =>
                        new{ X= cur.X - pre.X, Y= cur.Y - pre.Y}))
                        select delta;

            q.Subscribe(value =>
            {
                Canvas.SetLeft(AssociatedObject, Canvas.GetLeft(AssociatedObject) + value.X);
                Canvas.SetTop(AssociatedObject, Canvas.GetTop(AssociatedObject) + value.Y);
            });

        }
    }

Helper Methods:

  public static IObservable<IEvent<MouseEventArgs>>  GetMouseMove(
             this UIElement inputElement)
        {

            return Observable.FromEvent(
                (EventHandler<MouseEventArgs> h) => new MouseEventHandler(h),
                h => inputElement.MouseMove += h,
                h => inputElement.MouseMove -= h);
        }

        public static IObservable<IEvent<MouseButtonEventArgs>>
          GetMouseLeftButtonDown(this UIElement inputElement)
        {
            return Observable.FromEvent(
                (EventHandler<MouseButtonEventArgs> genericHandler) =>
                    new MouseButtonEventHandler(genericHandler),
                            h => inputElement.MouseLeftButtonDown += (h),
                            h => inputElement.MouseLeftButtonDown -= (h));
        }

        public static IObservable<IEvent<MouseButtonEventArgs>>
            GetMouseLeftButtonUp(this UIElement inputElement)
        {
            return Observable.FromEvent(
                (EventHandler<MouseButtonEventArgs> genericHandler) =>
                    new MouseButtonEventHandler(genericHandler),
                            h => inputElement.MouseLeftButtonUp += h,
                            h => inputElement.MouseLeftButtonUp -= h);
        }}


   <Window x:Class="DesignerTest.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:vm="clr-namespace:DesignerTest.ViewModels"
    xmlns:h="clr-namespace:DesignerTest.Helpers"
    xmlns:e="http://schemas.microsoft.com/expression/2010/interactivity"
    Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
    <vm:WindowViewModel />
</Window.DataContext>
<Grid>
    <ItemsControl ItemsSource="{Binding Path=Shapes}">
     <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <Canvas />
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <StackPanel>
                    <e:Interaction.Behaviors>
                        <h:DragBehavior />
                    </e:Interaction.Behaviors>
                    <TextBlock Text="{Binding X}" />
                </StackPanel>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    <ItemsControl.ItemContainerStyle>
            <Style TargetType="ContentPresenter">
            <Setter Property="Canvas.Left" Value="{Binding Path=X,Mode=TwoWay}" />
            <Setter Property="Canvas.Top" Value="{Binding Path=Y,Mode=TwoWay}" />
        </Style>
    </ItemsControl.ItemContainerStyle>
    </ItemsControl>  
</Grid>

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

陌路终见情 2024-11-04 21:21:09

稍微改变一下你的模板...mb这会对你有帮助..

<DataTemplate>
    <!-- change background to transparent -->        
    <StackPanel Background="Transparent">            
        <e:Interaction.Behaviors>                        
            <h:DragBehavior />                    
        </e:Interaction.Behaviors> 
        <!-- Prevent yout textBlock from capturing mouse events -->    
        <!-- by setting is HitTestVisible to false -->  
        <TextBlock Text="{Binding X}" IsHitTestVisible="False" />                
    </StackPanel>            
</DataTemplate>

Change your template a little... mb this will help you..

<DataTemplate>
    <!-- change background to transparent -->        
    <StackPanel Background="Transparent">            
        <e:Interaction.Behaviors>                        
            <h:DragBehavior />                    
        </e:Interaction.Behaviors> 
        <!-- Prevent yout textBlock from capturing mouse events -->    
        <!-- by setting is HitTestVisible to false -->  
        <TextBlock Text="{Binding X}" IsHitTestVisible="False" />                
    </StackPanel>            
</DataTemplate>
凉月流沐 2024-11-04 21:21:09

代码真的在运行吗?向 OnAttached 和您的 Subscribe 闭包添加一个“When Hit”断点,以跟踪实际发生的情况

另外,关于您的实现的一些注意事项:

  • 我建议创建一个 MutableDisposable 私有成员并分配返回值订阅它的Disposable属性。这将允许您取消订阅 OnDetached 中的所有内容。
  • 无需选择 MouseUp 事件的位置,因为 TakeUntil 不要求序列具有相同类型。

编辑:我认为问题是您要添加 Canvas 属性的 StackPanel 实际上是 ItemContainerTemplate (ContentPresenter) 元素,而不是 Canvas 本身。您应该在行为的 OnAttached 方法中遍历树,或者定义自己的 ItemContainerTemplate 并将行为附加到 ContentPresenter

Is the code actually running? Add a "When Hit" breakpoint to OnAttached and your Subscribe closure to trace out what's atually happening

Also, a few notes on your implementation:

  • I'd recommend creating a MutableDisposable private member and assigning the return value of Subscribe to it's Disposable property. This will allow you to unsubscribe from everything in OnDetached
  • There's no need to select the MouseUp event's position as TakeUntil doesn't require that the sequences be of the same type.

Edit: I think the problem is that the StackPanel you are adding the Canvas properties to is actually the child of the ItemContainerTemplate (ContentPresenter) element, not of the Canvas itself. You should either walk the tree in the behavior's OnAttached method, or define your own ItemContainerTemplate and attach the behavior to the ContentPresenter instead.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文