当前位置 : 主页 > 手机开发 > 无线 >

wpf – 使用MVVM在画布中移动项目

来源:互联网 收集:自由互联 发布时间:2021-06-10
我希望用户能够在画布中自由移动项目. 我的应用程序正在使用Caliburn.Micro. 如果Items,我的MainViewModel有一个集合: public BindableCollectionItemViewModel Items { get; set; } 我通过ItemsControl在画布中显
我希望用户能够在画布中自由移动项目.
我的应用程序正在使用Caliburn.Micro.

如果Items,我的MainViewModel有一个集合:

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

我通过ItemsControl在画布中显示:

<ItemsControl x:Name="Items">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <Canvas Background="#FFCADEEF" />
        </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}">
                <Rectangle>
                    <Rectangle.Fill>
                        <VisualBrush Visual="{StaticResource appbar_cursor_move}" />
                    </Rectangle.Fill>
                </Rectangle>
            </Border>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

我已经成功地将事件(现在什么都不做)绑定到MouseLeftButtonDown,MouseLeftButtonUp和MouseMove,但我不知道如何从viewmodel获取光标的位置.

我已经使用了你的行为,并改变了一些东西,使其更加MVVM’y:

<Window x:Class="WpfApp1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApp1"
        xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525" DataContext="{Binding RelativeSource={RelativeSource Self}, Path=ViewModel}">
    <ItemsControl ItemsSource="{Binding Path=Shapes}">
        <ItemsControl.Resources>
            <DataTemplate DataType="{x:Type local:Rectangle}">
                <Rectangle Canvas.Top="{Binding Top, Mode=TwoWay}" Canvas.Left="{Binding Left, Mode=TwoWay}" Width="{Binding Width}" Height="{Binding Height}" Fill="Red">
                    <i:Interaction.Behaviors>
                        <local:DragBehavior/>
                    </i:Interaction.Behaviors>
                </Rectangle>
            </DataTemplate>
            <DataTemplate DataType="{x:Type local:Circle}">
                <Ellipse Width="{Binding Radius}" Height="{Binding Radius}" Fill="Blue" Canvas.Top="{Binding Top, Mode=TwoWay}" Canvas.Left="{Binding Left, Mode=TwoWay}">
                    <i:Interaction.Behaviors>
                        <local:DragBehavior/>
                    </i:Interaction.Behaviors>
                </Ellipse>
            </DataTemplate>
        </ItemsControl.Resources>
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <Canvas />
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <ItemsControl.ItemContainerStyle>
            <Style TargetType="ContentPresenter">
                <Setter Property="Canvas.Top" Value="{Binding Path=Top, Mode=TwoWay}" />
                <Setter Property="Canvas.Left" Value="{Binding Path=Left, Mode=TwoWay}" />
            </Style>
        </ItemsControl.ItemContainerStyle>
    </ItemsControl>
</Window>

this是我使用样式绑定到Canvas.Top和Left的原因.

这是我的ViewModel.我使用ReactiveUI for IPropertyChanged,但这并不重要.

public class MainViewModel : ReactiveObject
    {
        private ReactiveList<IShape> _shapes;

        public MainViewModel()
        {
            Shapes = new ReactiveList<IShape>();

            Shapes.Add(new Rectangle { Top = 50, Left = 50, Height = 50, Width = 50 });
            Shapes.Add(new Circle{Top = 100, Left = 100, Radius = 50});
        }

        public ReactiveList<IShape> Shapes
        {
            get { return _shapes; }
            set { this.RaiseAndSetIfChanged(ref _shapes, value); }
        }
    }

    public interface IShape
    {
        int Top { get; set; }
        int Left { get; set; }
    }

    public abstract class Shape : ReactiveObject, IShape
    {
        private int _top;
        private int _left;

        public int Top
        {
            get { return _top; }
            set { this.RaiseAndSetIfChanged(ref _top, value); }
        }

        public int Left
        {
            get { return _left; }
            set { this.RaiseAndSetIfChanged(ref _left, value); }
        }
    }

    public class Circle : Shape
    {
        private int _radius;

        public int Radius
        {
            get { return _radius; }
            set { this.RaiseAndSetIfChanged(ref _radius, value); }
        }
    }

    public class Rectangle : Shape
    {
        private int _width;
        private int _height;

        public int Width
        {
            get { return _width; }
            set { this.RaiseAndSetIfChanged(ref _width, value); }
        }

        public int Height
        {
            get { return _height; }
            set { this.RaiseAndSetIfChanged(ref _height, value); }
        }
    }

我为反应角和圆创建了类,因为MVVM的重点在于区分层.在ViewModel中持有UI控件是违背这个想法的.

最后,我不得不改变你的MouseLeftButtonUp:

AssociatedObject.MouseLeftButtonUp += (sender, e) =>
            {
                AssociatedObject.ReleaseMouseCapture();

                var diff = e.GetPosition(parent) - mouseStartPosition;


                Canvas.SetTop(AssociatedObject, ElementStartPosition.Y + diff.Y);
                Canvas.SetLeft(AssociatedObject, ElementStartPosition.X + diff.X);

                transform.Y = 0;
                transform.X = 0;
            };

这将从RenderTransform进行更改并将其写入对象.然后,双向绑定将其转移到我们的Rectangle类中.

如果您想知道对象的位置,则只需要这样做,例如检查它们是否在VM中相交.

它工作得很好,就像你可以得到的MVVM一样.也许除了行var parent = Application.Current.MainWindow; – 这应该取代我认为绑定到您的行为的公共依赖属性.

网友评论