开发者

Rx DragBehavior -> Why is my Element not moving

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>
        </ItemsC开发者_C百科ontrol.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>


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>


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.

0

上一篇:

下一篇:

精彩评论

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

最新问答

问答排行榜