"拖动并复制"对于WPF DataGrid

时间:2017-08-28 13:29:01

标签: c# wpf mvvm datagrid

我的工作场所正在开发用于构建通用公司电子表格的内部程序。我们的程序不需要过多的功能,但我们想要包括的一件事是能够点击单元格,向上/向下/向左/向右拖动,以及复制内容原始单元格到用户选择的单元格,如Excel可以做到。

我寻求一个可靠,明确和有条理的答案并没有取得多大成果。最接近我发现的事情是this SO question和关于在数据网格上移动行的物理位置的文章。该问题的作者没有成功,报告他们跳过了'#34;拖动和复制"完全实施。

是否有合理的方法在MVVM之后构建的应用程序中实现此功能?

2 个答案:

答案 0 :(得分:1)

简单XAML - 请注意添加到数据网格的SelectionUnit,SelectedCellsChanges和Keyup事件

    <Window x:Class="WpfApp4.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:WpfApp4"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <DataGrid x:Name="MyGrid" HorizontalAlignment="Left" Height="276" Margin="18,21,0,0" VerticalAlignment="Top" Width="466" SelectionUnit="Cell" SelectedCellsChanged="SelectionChanged" KeyUp="MyGrid_PreviewKeyUp"/>
    </Grid>
</Window>

一些简单的C#代码:

    using System;
    using System.Collections.Generic;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Input;

    namespace WpfApp4
    {
        public class MyItems
        {
            public int Col1 { get; set; }
            public int Col2 { get; set; }
            public int Col3 { get; set; }
            public int Col4 { get; set; }
        }

        public partial class MainWindow : Window
        {
            // create a source for the datagrid
            public List<MyItems> DataList { get; set; }

            // somewhere to hold the selected cells
            IList<DataGridCellInfo> DataGridSelectedCells { get; set; }

            public MainWindow()
            {
                InitializeComponent();
                DataContext = this;

                DataList = new List<MyItems>()
                {
                    new MyItems() { Col1=1, Col2=2, Col3=3, Col4=4},
                    new MyItems() { Col1=5, Col2=6, Col3=7, Col4=8},
                    new MyItems() { Col1=9, Col2=10, Col3=11, Col4=12},
                    new MyItems() { Col1=13, Col2=14, Col3=15, Col4=16},
                };

                MyGrid.ItemsSource = DataList;

            }

            private void SelectionChanged(object sender, SelectedCellsChangedEventArgs e)
            {
                DataGridSelectedCells = MyGrid.SelectedCells;
            }

            private void MyGrid_PreviewKeyUp(object sender, KeyEventArgs e)
            {
                // Check your key here (Ctrl D, Ctrl R etc)                  
                // then loop around your data looking at what is selected
                // chosing the direction based on what key was pressed       
                foreach (DataGridCellInfo d in DataGridSelectedCells)
                {   // get the content of the cell           
                    var cellContent = d.Column.GetCellContent(d.Item);
                    if (cellContent != null)
                    {  // if it's not null try to get the content
                        DataGridCell dc = (DataGridCell)cellContent.Parent;
                        TextBlock tb = (TextBlock)dc.Content;

                        // Change the contents of tb.Content here
                        // or dump for debugging
                        Console.WriteLine(tb.Text);
                    }
                }
            }
        }
}

用户可以向任何方向拖动单元格和“GridSelectedCells”。将只填充选定的单元格。使用KeyUp(或其他首选)事件允许用户复制(或使用上下文菜单实现右键单击事件),然后根据需要循环访问数据(向前或向后)以进行复制。

虽然它不是一个完整的解决方案,但它应该让你开始。

答案 1 :(得分:0)

最终解决方案。

using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;

namespace Fatele.Imp.Exp.Application.Applications.Components {
    public class DataGridBehaviour {
      public static readonly DependencyProperty NavLikeProperty = DependencyProperty.RegisterAttached("NavLike",
            typeof(bool), typeof(DataGridBehaviour), new UIPropertyMetadata(NavLikeChanged));

        public static bool GetNavLike(DependencyObject obj) {
            return (bool) obj.GetValue(NavLikeProperty);
        }

        public static void SetNavLike(DependencyObject obj, bool value) {
            obj.SetValue(NavLikeProperty, value);
        }

        private static void NavLikeChanged(object oo, DependencyPropertyChangedEventArgs ee) {
            var odg = (DataGrid) oo;
            odg.KeyUp += KeyUp;
        }

        private static void KeyUp(object sender, KeyEventArgs e) {
            var dataGrid = sender as DataGrid;
            if (dataGrid == null) {
                return;
            }

            if (e.Key != Key.LeftCtrl) {
                return;
            }

            if (dataGrid.SelectedCells.Count < 2) {
                return;
            }

            var firstCell = dataGrid.SelectedCells.First();
            var propertyInfo = firstCell.Item.GetType().GetProperty(firstCell.Column.SortMemberPath);
            if (propertyInfo == null) {
                return;
            }

            var value1 = propertyInfo.GetValue(firstCell.Item);
            foreach (var cellInfo in dataGrid.SelectedCells.Skip(1)) {
                var value2 = propertyInfo.GetValue(cellInfo.Item);
                if (value2 == null) {
                    propertyInfo.SetValue(cellInfo.Item, value1);
                }
            }
        }
    }
}