C# 将内容从一个网格子级拖放到另一个网格子级

C# 将内容从一个网格子级拖放到另一个网格子级,c#,wpf,button,drag-and-drop,grid,C#,Wpf,Button,Drag And Drop,Grid,我正在寻找一种方法,让我的程序的用户通过拖放将一个按钮(作为图像作为背景,是网格子项的内容)移动到另一个网格子项 “我的按钮”是由程序本身根据for迭代中的数据库创建的: foreach (PC_Infos item in allPcsOnThisFloor) { if (item != null) { roomToCoordinates(allPcsOnThisFloor[i].Room,out column, out row); Button

我正在寻找一种方法,让我的程序的用户通过拖放将一个按钮(作为图像作为背景,是网格子项的内容)移动到另一个网格子项

“我的按钮”是由程序本身根据for迭代中的数据库创建的:

foreach (PC_Infos item in allPcsOnThisFloor)
{
    if (item != null)
    {
        roomToCoordinates(allPcsOnThisFloor[i].Room,out column, out row);
        Button btn = new Button();
        btn.Name = Name+ "_Button";
        btn.Background = new ImageBrush(my icon here);
        btn.Click += btn_Click;
        btn.SetValue(Grid.ColumnProperty, column);
        btn.SetValue(Grid.RowProperty, row);
        My_Grid.Children.Add (btn);
        i++;
    }
    else 
        break;
}
PC\u Infos
只是一个包含属性的类:PC\u名称、房间和MAC\u地址,没有其他属性

我的网格:

<Grid x:Name="Grid_10" AllowDrop="True">
    <Grid.Background>
        <ImageBrush ImageSource="C:\Users\XXX\XXX\buildingPlan.png"/>
    </Grid.Background>
    <Grid.ColumnDefinitions>
        <ColumnDefinition />
        [...]
        <ColumnDefinition />
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition />
        [...]
        <RowDefinition />
    </Grid.RowDefinitions>
</Grid>

[...]
[...]
现在有没有一种方法可以使用一个
btn.*
在拖动时获取当前位置(行和列),以及另一个
btn.*
在鼠标放下按钮时在鼠标当前所在的子网格中创建此按钮的新副本? 或者甚至有没有办法将按钮从一个孩子“移动”到另一个孩子

顺便说一句:我的程序应该显示一个建筑平面图,上面的图标(按钮)是电脑实际所在的位置。通过阅读MyDB中的“Room”列,源代码可以粗略猜测。但房间不仅仅是一个地方。有人在窗口工作,另一人在门上工作,这应该由用户标记(使用拖放) 我在VS'13中使用了一个WPF应用程序和C#和.NET4.5.1

PS:如果有人说:为什么是网格,为什么是地狱按钮D:当用户点击图标时,会出现一个带有系统值的新窗口,如OS、RAM、CPU。。。会出现的。但我对任何实施都持开放态度。我已经很久没有做编程了,所以我可能不知道最好的方法


我可能误解了您的问题,但据我所知,这里没有拖放:您想在
面板周围移动
ui元素

首先,我建议使用
画布
来显示项目,而不是
网格
,因为它将提供更大的灵活性

假设您将该类作为主要对象:

public class PC_Infos
{
    public string PC_Name;
    public string Room;
    public string MAC_Adress;
}
与其在代码隐藏中构建控件,我更喜欢一个简单的包装器,如:

public class DragablePC : INotifyPropertyChanged
{
    public DragablePC(PC_Infos pc, double x = 0d, double y = 0d)
    {
        _pcItem = pc;
        PcRow = y;
        PcColumn = x;
    }

    private double _x;
    public double PcColumn
    {
        get { return _x; }
        set
        {
            if (value == _x) return;
            _x = value;
            RaisePropertyChanged("PcColumn");
        }
    }

    private double _y;
    public double PcRow
    {
        get { return _y; }
        set
        {
            if (value == _y) return;
            _y = value;
            RaisePropertyChanged("PcRow");
        }
    }

    PC_Infos _pcItem;

    public DragablePC(PC_Infos pc, double x = 0d, double y = 0d)
    {
        _pcItem = pc;
        PcRow = y;
        PcColumn = x;
    }

    public override string ToString() { return _pcItem.PC_Name; }

    public event PropertyChangedEventHandler PropertyChanged;
    void RaisePropertyChanged(string propName)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propName));
    }
}
这个包装器只存储X/Y坐标和项目。它允许定义绑定源,如下所示:

AllPCS = allPcsOnThisFloor.Select(p => new DragablePC(p));
现在,您可以使用
ItemsControl
来显示项目。如上所述,我将为
ItemsPanel
使用
Canvas
,并定义一个简单的
ItemContainerStyle
将它们放置在画布上

    <ItemsControl Name="DDPanel" ItemsSource="{Binding Path=AllPCS}"
                  MouseMove="DDPanel_MouseMove">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <Canvas IsItemsHost="True" Background="LightGray"/>                    
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <ItemsControl.ItemContainerStyle>
            <Style>
                <Setter Property="Canvas.Top" Value="{Binding Path=PcRow}"/>
                <Setter Property="Canvas.Left" Value="{Binding Path=PcColumn}"/>
            </Style>
        </ItemsControl.ItemContainerStyle>
        <ItemsControl.ItemTemplate>
            <DataTemplate DataType="{x:Type dnd:DragablePC}">
                <Border BorderBrush="Red" BorderThickness="2" CornerRadius="6" Padding="6, 12"
                        Background="White" MinWidth="70" 
                        MouseLeftButtonDown="Border_MouseLeftButtonDown"
                        MouseLeftButtonUp="Border_MouseLeftButtonUp">
                    <TextBlock Text="{Binding}" HorizontalAlignment="Center"/>
                </Border>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
这现在需要很多调整,例如处理
MouseLeave
事件,为定位添加一些逻辑。。。但是你现在可以到处移动你的电脑了


希望这能有所帮助。

谢谢第二段:D现在我使用的画布(正如你已经提到的)更灵活、更容易,而不是现在使用的按钮矩形。使用
MyCanvas\u MouseDown
MyCanvas\u MouseMove
MyCanvas\u MouseMove
操作处理程序和全局变量DragInProgress,我可以处理移动。调用
MouseDown
时,代码会获取参考底图矩形并重新绘制它,而
MouseMove
自按下任何鼠标按钮后,使用鼠标的deltaX和deltaY进行重新绘制。很抱歉,没有使用您的代码或您本来可以使用的方式,但是看看我的questinon的PS。我对编程相对来说是新手,老实说,我甚至不理解你的每一段代码。但是你给了我一个新的方向很高兴它能帮上忙。如果您使用的是WPF,那么您肯定应该关注绑定和模板。
    DragablePC _selected = null;
    Point cursorPos = new Point();

    private void DDPanel_MouseMove(object sender, MouseEventArgs e)
    {
        if (null == _selected) return;

        Point newPosition = e.GetPosition(DDPanel);
        _selected.PcColumn += newPosition.X - cursorPos.X;
        _selected.PcRow += newPosition.Y - cursorPos.Y;
        cursorPos = newPosition;
    }

    private void Border_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        var uiItem = sender as FrameworkElement;
        var dpc = uiItem.DataContext as DragablePC;

        if (dpc == null) return;

        cursorPos = e.GetPosition(DDPanel);
        _selected = dpc;
    }

    private void Border_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
    {
        var uiItem = sender as FrameworkElement;
        var dpc = uiItem.DataContext as DragablePC;

        if (dpc == null) return;

        _selected = null;
    }