c#/ WPF产品配置器/可拖动项目

时间:2017-12-20 22:08:58

标签: c# .net wpf xaml user-controls

我目前正在C#/ WPF中构建产品配置程序。该产品类似于定制插座条。它由可变长度的铝型材制成。您可以选择出口并将它们放在铝型材上。

我们已经有了数据模型。我们有班级"简介"具有"长度"等属性和班级"项目"使用" position"," type"等

我做了一个可视化数据的功能。我有一个MainCanvas,其中我将配置文件绘制为矩形,并且我使用属性" width"。属于该产品的项目位于列表中。我使用for循环绘制项目,为列表中的每个插件插入一个wpf" items"。

当我更改数据时,我必须清除画布并重绘。我认为下一步是将类的变量绑定到WPF属性,例如插件的位置或配置文件的长度。

稍后,应选择/拖动插头以更改其位置(例如,在5毫米的网格中)。那是我陷入困境的品脱。我知道我可以选择和拖动插头,例如" OnLeftMouseButton"。现在的问题是:我应该在什么类型的容器中插入插头?

我以为我可以将一个插件的WPF-Code包装在UserControl中。这是正确的方法吗?据我所知,我可以使用Hittest选择UserControl。 Hittestresult将被列入选中的列表。为了显示选择,我可以使用UserControl的Borderthickness / Brush。对于拖动,我可以使用ManupilationDelta更改位置(并更改绑定的位置变量)。因为插件的数量是可变的,所以我必须从C#-Code生成UserControls。 我知道Hittest使用UserControls并不容易实现,因为它们并非真正可见"。

我是C#的新手,我很难在互联网上找到有类似问题或项目的人,也许是因为我在搜索错误的单词。我的假设是否正确?您将使用什么WPF控制?

1 个答案:

答案 0 :(得分:1)

我使用了this answer并添加了一些修改。

我使用ItemControl创建包含不同对象的视图。这样,您只需将对象添加到列表中即可添加图像。容器是Canvas,但它可以是任何内容,因为该位置由RenderTransform控制:

<ItemsControl Name="MainView" ItemsSource="{Binding ListObjects}">
    <ItemsControl.ItemsPanel >
        <ItemsPanelTemplate>
            <Canvas/>
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <ItemsControl.ItemTemplate>
        <DataTemplate DataType="{x:Type local:MVDragableObject}">
            <local:DragableObject/>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

这是背后的代码。一些基本的ModelView:

public class MVObjectManager
{
    public ObservableCollection<MVDragableObject> ListObjects { get; set; }
    public MVObjectManager()
    {
        ListObjects = new ObservableCollection<MVDragableObject>();
    }
}
public class MVDragableObject
{
}

填充和绑定容器的代码。您可以注意到我在集合中添加了3个项目:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        MVObjectManager Manager=new MVObjectManager();
        Manager.ListObjects.Add(new MVDragableObject());
        Manager.ListObjects.Add(new MVDragableObject());
        Manager.ListObjects.Add(new MVDragableObject());
        MainView.DataContext  = Manager;
    }
}

我定义了一个非常简单的UserControl。您可以自定义它:

<UserControl x:Class="StackFill.DragableObject"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         mc:Ignorable="d">
<Grid>
    <Rectangle Fill="Red" Height="30" Width="30"/>
</Grid>

</UserControl>

以下是管理拖放行为的代码:

public partial class DragableObject : UserControl
{
    public DragableObject()
    {
        InitializeComponent();
        this.MouseLeftButtonDown += new MouseButtonEventHandler(DragableObject_MouseLeftButtonDown);
        this.MouseLeftButtonUp += new MouseButtonEventHandler(DragableObject_MouseLeftButtonUp);
        this.MouseMove += new MouseEventHandler(DragableObject_MouseMove);
    }

    protected bool isDragging;
    private Point clickPosition;

    private void DragableObject_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        isDragging = true;
        var draggableControl = sender as UserControl;
        clickPosition = e.GetPosition(this.Parent as UIElement);
        draggableControl.CaptureMouse();
    }

    private void DragableObject_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
    {
        isDragging = false;
        var draggable = sender as UserControl;
        draggable.ReleaseMouseCapture();
    }

    private void DragableObject_MouseMove(object sender, MouseEventArgs e)
    {
        var draggableControl = sender as UserControl;

        if (isDragging && draggableControl != null)
        {
            Point currentPosition = e.GetPosition(this.Parent as UIElement);

            var transform = draggableControl.RenderTransform as TranslateTransform;
            if (transform == null)
            {
                transform = new TranslateTransform();
                draggableControl.RenderTransform = transform;
            }

            transform.X = snapPosition(currentPosition.X - clickPosition.X, 10);
            transform.Y = snapPosition(currentPosition.Y - clickPosition.Y, 10);
        }
    }

    private double snapPosition(double position, double gridSize)
    {
        return (Math.Truncate(position / gridSize) * gridSize);
    }
}

您可以通过更改gridSize参数来控制捕捉精度。