简体   繁体   中英

How do I paste in a wpf datagrid to an observablecollection

I have a WPF Datagrid that I am capturing the paste command via

<CommandBinding Command="{x:Static ApplicationCommands.Paste}"
                            Executed="CommandBinding_Paste_Executed"/>

In 'CommandBinding_Paste_Executed' I can cycle through all the selected cells and can see the field name, where I need to paste the clipboard data to my observable collection.

Unfortunately I cannot figure out how to reference the member of the collection. I realise the below is wrong, but it should give you an idea as to what I am attempting...

foreach (DataGridCellInfo cell in MyDataGrid.SelectedCells)
{
   string columnName = cell.Column.SortMemberPath;
   int rowIndex = ????;
   MyCollection[rowIndex].columnName ??? = Clipboard.GetText();
}

Am I missing something obvious? Or am I attempting this from the wrong angle.

OK, so it appear after searching Google for wpf datagrid paste, what I should have been looking for is column mapping. Still find it hard to believe that these is not a simpler answer for this, but here is what I have got. MainWindow.xaml

<Grid>
    <DataGrid x:Name="DGrid" ItemsSource="{Binding Path=Stuff}"
              SelectedItem="{Binding DGSelection}"
              CellEditEnding="DGrid_CellEditEnding"
              SelectionUnit="Cell">
        <DataGrid.CommandBindings>
            <CommandBinding Command="{x:Static ApplicationCommands.Paste}" CanExecute="CanPaste" Executed="Paste"/>
        </DataGrid.CommandBindings>
        
        <DataGrid.Columns>
            <DataGridTextColumn Header="First name" Binding="{Binding FirstName}"/>
            <DataGridTextColumn Header="Surname" Binding="{Binding Surname}"/>
            <DataGridTextColumn Header="Country" Binding="{Binding Country}"/>
        </DataGrid.Columns>
    </DataGrid>
</Grid>

Person.cs

public class Person : INotifyPropertyChanged
{
    public string FirstName { get; set; }
    public string Surname { get; set; }
    public string Country { get; set; }

    public Person()
    { }

    public Person(string firstName, string surname, string country)
    {
        FirstName = firstName;
        Surname = surname;
        Country = country;
    }

    public event PropertyChangedEventHandler PropertyChanged;

    public virtual void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

PeopleViewModel.cs

public class PeopleViewModel : INotifyPropertyChanged
{
    private ObservableCollection<Person> people;
    public event PropertyChangedEventHandler PropertyChanged;

    /// <summary>
    /// property map to store the column indexes and names
    /// eg: 0, FirstName
    /// </summary>
    private Dictionary<int, string> propertyMap;

    public PeopleViewModel()
    {
        people = new ObservableCollection<Person>();
        people.Add(new Person("Bruce", "Willis", "USA"));
        people.Add(new Person("Sarah", "Connor", "USA"));
        people.Add(new Person("Adolph", "Hitler", "Germany"));
        people.Add(new Person("Rowan", "Atkinson", "United Kingdom"));
        people.Add(new Person("Ryan", "Reynolds", "Canada"));

        propertyMap = new Dictionary<int, string>();
    }

    public ObservableCollection<Person> PeopleList
    {
        get => people;
        set
        {
            people = value;
            OnPropertyChanged("PeopleList");
        }
    }

    public void AddColumnMapping(int displayIndex, string propertyName)
    {
        propertyMap[displayIndex] = propertyName;
    }

    private void SetProperty(Person person, string propertyName, string cellItem)
    {
        PropertyInfo propertyInfo = person.GetType().GetProperty(propertyName);
        if (propertyInfo == null)
            throw new Exception($"Could not find property '{propertyName}'");

        if (propertyInfo.PropertyType != typeof(string))
            throw new Exception("Only coded for string values at this time");

        propertyInfo.SetValue(person, cellItem, null);
        person.OnPropertyChanged(propertyName);
    }

    public void Paste(int row, string column, string value)
    {
        Person person = PeopleList[row];
        SetProperty(person, column, value);
    }

    protected virtual void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

MainWindow.xaml.cs

public partial class MainWindow : Window
{
    public PeopleViewModel people = new PeopleViewModel();
    public MainWindow()
    {
        InitializeComponent();
        DGrid.ItemsSource = people.PeopleList;
    }

    private void CanPaste(object sender, CanExecuteRoutedEventArgs e)
    {
        e.CanExecute = Clipboard.GetDataObject() != null;
    }

    private void Paste(object sender, ExecutedRoutedEventArgs e)
    {
        Person person;
        int row;
        string column;

        string clipboardValue = Clipboard.GetText();
        if (clipboardValue.Substring(clipboardValue.Length - 2) == "\r\n")
            clipboardValue = clipboardValue.Substring(0, clipboardValue.Length - 2);

        IList<DataGridCellInfo> cells = DGrid.SelectedCells;
        foreach (DataGridCellInfo cell in cells)
        {
            person = cell.Item as Person;
            row = people.PeopleList.IndexOf(person);
            column = cell.Column.SortMemberPath;
            people.Paste(row, column, clipboardValue);
        }
    }
}

My thanks for Peter_Smithson at https://www.codeproject.com/Articles/246306/Implementing-Copy-Paste-for-WPF-DataGrid-net-4

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM