【问题标题】:Send message from WPF behavior to the ViewModel从 WPF 行为向 ViewModel 发送消息
【发布时间】:2015-01-15 17:39:47
【问题描述】:

按照my previous question,我现在可以通过行为在画布中拖动项目。

问题是项目新坐标计算是在行为内部完成的,我不确定如何在视图中不写任何内容的情况下将它们发送到项目的 ViewModel。

我的 MainViewModel 有一个 Items 集合:

public BindableCollection<ItemViewModel> Items { get; set; }

ItemViewModel 看起来像这样:

[ImplementPropertyChanged]
public class ItemViewModel
{
    private readonly IEventAggregator events;
    private Random r = new Random();

    public ItemViewModel(IEventAggregator events)
    {
        this.events = events;
        this.events.Subscribe(this);

        // default values
        this.BackgroundColor = this.RandomColor();
        this.Width = 100;
        this.Height = 100;
        this.X = 10;
        this.Y = 10;
    }

    public Brush BackgroundColor { get; set; }
    public string Content { get; set; }
    public int Height { get; set; }
    public int Width { get; set; }
    public double X { get; set; }
    public double Y { get; set; }

    /// <summary>
    /// https://stackoverflow.com/a/11282427/6776
    /// </summary>
    private SolidColorBrush RandomColor()
    {
        var properties = typeof(Brushes).GetProperties();
        var count = properties.Count();
        var color = properties.Select(x => new { Property = x, Index = this.r.Next(count) })
                              .OrderBy(x => x.Index)
                              .First();

        return (SolidColorBrush)color.Property.GetValue(color, null);
    }
}

目前,我的 DragBehavior 只是 this code snippet 的复制/粘贴。

最后,我的 MainView 显示这样的项目(我正在使用 Caliburn.Micro 通过 x:Name 绑定项目):

<ItemsControl x:Name="Items">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <Canvas />
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <ItemsControl.ItemContainerStyle>
        <Style TargetType="ContentPresenter">
            <Setter Property="Canvas.Left" Value="{Binding Path=X}" />
            <Setter Property="Canvas.Top" Value="{Binding Path=Y}" />
            <Setter Property="Width" Value="{Binding Path=Width}" />
            <Setter Property="Height" Value="{Binding Path=Height}" />
        </Style>
    </ItemsControl.ItemContainerStyle>
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <Border Background="{Binding Path=BackgroundColor}"
                behaviors:DragBehavior.Drag="True">
                <!-- contents -->
            </Border>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

我正在考虑添加一些类似的内容:

<Border ...
    behaviors:DragBehavior.OnDropped="{Binding Dropped}">

在 ItemViewModel 中:

public void Dropped(Point newCoordinates) {
  // change the X and Y of the viewmodel
}

但我不知道从哪里开始,甚至不知道该怎么称呼它。行动 ?扳机 ?它似乎与我要查找的内容无关。

Gong DragDropBehavior 库有一个系统,其中项目实现接口并且行为运行正确的方法,但我不太了解它是如何工作的(这是我第一次处理行为)。

【问题讨论】:

    标签: c# wpf mvvm triggers action


    【解决方案1】:

    到目前为止,这是我使用的方法(灵感来自龚的工作原理)。

    基本上,视图绑定在视图模型本身上,它应该实现一个接口。行为检索此绑定,并通过绑定元素调用接口方法。

    我有一个使用此代码的 GitHub 帐户:https://github.com/cosmo0/DragSnap(在撰写本文时尚未更新)。

    该行为有一个新的 DropHandler 属性:

        public static readonly DependencyProperty DropHandlerProperty =
            DependencyProperty.RegisterAttached(
                "DropHandler",
                typeof(IDropHandler),
                typeof(DragOnCanvasBehavior),
                new PropertyMetadata(OnDropHandlerChanged));
    
        private IDropHandler DropHandler { get; set; }
    
        public static IDropHandler GetDropHandler(UIElement target)
        {
            return (IDropHandler)target.GetValue(DropHandlerProperty);
        }
    
        public static void SetDropHandler(UIElement target, IDropHandler value)
        {
            target.SetValue(DropHandlerProperty, value);
        }
    
        private static void OnDropHandlerChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            // Initialize variables and assign handlers
            // see original code in Github linked in original question
    
            // Additionnaly, initialize the DropHandler :
            var handler = (IDropHandler)(e.NewValue);
            Instance.DropHandler = handler;
        }
    
        private void ElementOnMouseLeftButtonUp(object sender, MouseButtonEventArgs mouseButtonEventArgs)
        {
            var element = (UIElement)sender;
            element.ReleaseMouseCapture();
    
            // this is the main change
            if (this.DropHandler != null)
            {
                this.DropHandler.Dropped();
            }
        }
    
        private void ElementOnMouseMove(object sender, MouseEventArgs mouseEventArgs)
        {
            // TODO : do some calculations
    
            this.DropHandler.Moved(x, y);
        }
    

    我的 ItemViewModel 实现了IDropHandler,以及DroppedMoved 方法:

        public void Dropped()
        {
            this.events.PublishOnUIThread(new ItemDroppedEvent(this.X, this.Y, this.Width, this.Height, this.ID));
        }
    
        public void Moved(double x, double y)
        {
            this.X = x;
            this.Y = y;
        }
    

    视图绑定在视图模型本身上:

    <Border
        behaviors:DragOnCanvasBehavior.DropHandler="{Binding}">
    

    我在处理拖动的元素位置时仍有问题,但实际问题(从行为向视图模型发送消息)已得到解答。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-09-08
      • 2012-04-20
      • 2020-01-13
      • 2018-01-29
      相关资源
      最近更新 更多