My workplace is developing an internal program for building common company spreadsheets. Our program doesn't need an inordinate amount of functionality, but one thing that we'd like to include is the ability to click a cell, drag it up/down/left/right, and copy the contents of the original cell to the cells the user has selected like Excel can do.
My search for a solid, unambiguous, and contextual answer has not been fruitful. The closest I've come to finding something about this is this SO question and articles about moving the physical position of a row on the datagrid. The author of the question had no success, reporting that they skipped the "drag and copy" implementation entirely.
Is there a reasonable way to implement this feature in an application that is built following MVVM?
Simple XAML - note the SelectionUnit, SelectedCellsChanges and Keyup events added to the data grid
<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>
Some simple C# code:
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);
}
}
}
}
}
The user can drag cells in any direction and the 'GridSelectedCells' will fill with only the selected cells. Use the KeyUp (or other preferred) event to allow the user to copy (or implement right click events with context menu), then loop through the data (forwards or backwards) as needed to copy.
While it's not a complete solution it should get you started.