2015-04-14 18 views
6

Ich muss eine benutzerdefinierte Kopie implementieren + Ausschneiden + Einfügen für Daten (nicht Text oder CSV) zwischen Raster in einer WPF-Anwendung kopiert werden. Die Verwendung von Standard-ApplicationCommands und die Definition von CommandBinding funktionieren sehr gut, aber nur, wenn das DataGrid mindestens eine Datenzeile enthält und wenn es ausgewählt ist. Wenn keine Zeilen vorhanden sind oder der Fokus nicht auf einem davon liegt, sind alle Befehle deaktiviert.Implementieren Sie benutzerdefinierte Kopieren und Einfügen in WPF DataGrid, die funktioniert, wenn keine Zeilen darin sind

Um das Problem zu beheben, versuchte ich CommandManager.InvalidateRequerySuggested() und Focusable = True und/oder FocusManager.IsFocusScope = True auf dem DataGrid aufrufen, aber es scheint intern DataGrid als Ganzes ist nicht daran interessiert, mit Kopieren/Einfügen Operationen, nur die Zeilen sind erneut Abfragen Befehle CanExecute Zustand und Aufruf Execute entsprechend. Es ignoriert auch KeyBindings.

Wie DataGrid behandelt wird, Requerying ApplicationCommands behandeln?

finden Sie das Beispiel, an dem ich das Problem unten getestet:

<Window x:Class="WpfApplication1.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     Title="MainWindow" Height="350" Width="525"> 
    <DataGrid x:Name="TheGrid"> 
     <DataGrid.Columns> 
      <DataGridTextColumn Header="Number" Binding="{Binding}"/> 
     </DataGrid.Columns> 
     <DataGrid.InputBindings> 
      <KeyBinding Key="A" Command="{x:Static ApplicationCommands.New}"/> 
     </DataGrid.InputBindings> 
     <DataGrid.CommandBindings> 
      <CommandBinding Command="{x:Static ApplicationCommands.Paste}" CanExecute="CanPaste" Executed="Paste"/> 
      <CommandBinding Command="{x:Static ApplicationCommands.Copy}" CanExecute="CanCopy" Executed="Copy"/> 
      <CommandBinding Command="{x:Static ApplicationCommands.New}" CanExecute="CanAddNew" Executed="AddNew"/> 
     </DataGrid.CommandBindings> 
     <DataGrid.ContextMenu> 
      <ContextMenu> 
       <MenuItem Command="{x:Static ApplicationCommands.Copy}" Header="Copy"/> 
       <MenuItem Command="{x:Static ApplicationCommands.Paste}" Header="Paste"/> 
       <MenuItem Command="{x:Static ApplicationCommands.New}" Header="New row"/> 
      </ContextMenu> 
     </DataGrid.ContextMenu> 
    </DataGrid> 
</Window> 

Und den Code hinter:

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

namespace WpfApplication1 
{ 
    public partial class MainWindow 
    { 
     public MainWindow() 
     { 
      InitializeComponent(); 
      TheGrid.ItemsSource = numbers; 
      // Following line enables commands when row is selected 
      numbers.Add(0); 
     } 

     private void Copy(object sender, ExecutedRoutedEventArgs e) 
     { 
      Clipboard.SetData(DataFormats.Text, string.Join(",", numbers)); 
     } 

     private void CanCopy(object sender, CanExecuteRoutedEventArgs e) 
     { 
      e.CanExecute = numbers.Count > 0; 
     } 

     private void CanPaste(object sender, CanExecuteRoutedEventArgs e) 
     { 
      e.CanExecute = numbers.Count > 0; 
      e.Handled = true; 
     } 

     private void Paste(object sender, ExecutedRoutedEventArgs e) 
     { 
      Close(); 
     } 

     private void CanAddNew(object sender, CanExecuteRoutedEventArgs e) 
     { 
      e.CanExecute = true; 
      e.Handled = true; 
     } 

     private void AddNew(object sender, ExecutedRoutedEventArgs e) 
     { 
      numbers.Add(numbers.Count); 
     } 

     private readonly ICollection<int> numbers = new ObservableCollection<int>(); 
    } 
} 

bearbeiten

Der Code nur von Ayyappan Subramanian Lösung die beste Übereinstimmung mit der Anwendung, in der es verwendet wird. Schließlich, da ich bereits das Gitter erwerbe, weil es kundenspezifischen Polizisten hat y + Paste-Format zu arbeiten, habe ich einige Code, der sicherstellt, dass der Fokus innerhalb eines Gitters ist in 3 Fällen:

  1. Kontextmenü wird
  2. Benutzer klickt im Raster (leer) Bereich angezeigt, wenn es Kind Visuals ist kein Fokus
  3. (Unser App-spezifischer Fall) Der Benutzer klickt auf eine Grid-Navigation TreeView, die dann den Fokus auf das Grid bringt, damit Shortcuts sofort funktionieren.

Relevante Code:

public class MyDataGrid: DataGrid 
{ 
     protected override void OnContextMenuOpening(ContextMenuEventArgs e) 
     { 
      base.OnContextMenuOpening(e); 
      Focus(); 
     } 

     protected override void OnMouseUp(MouseButtonEventArgs e) 
     { 
      base.OnMouseUp(e); 
      if(e.ChangedButton == MouseButton.Left && !IsKeyboardFocusWithin) 
      { 
       Focus(); 
      } 
     } 
} 
+0

ich denke, es wegen der Linie sein könnte -> ** e.CanExecute = numbers.Count> 0; ** versuchen, die Linie in CanPaste Funktion Wechsel zu ** e.CanExecute = true; ** –

+0

Es tut uns leid, aber keine Aktion ist aktiviert, ohne sich auf eine Zeile zu konzentrieren, einschließlich ApplicationCommands.New und es hat e.CanExecute immer auf True gesetzt. – too

Antwort

5

Wenn die ContextMenu wird openning dann können Sie den Fokus auf das Gitter gesetzt, die alle Menüpunkte ermöglichen. Gute Erklärung wird hier gegeben http://www.wpftutorial.net/RoutedCommandsInContextMenu.html

auch für die Umsetzung der Paste beziehen sich die SO Post WPF datagrid pasting

WPF:

<DataGrid x:Name="TheGrid" CanUserAddRows="True" 
      ContextMenuOpening="TheGrid_ContextMenuOpening"> 
    <DataGrid.Columns> 
     <DataGridTextColumn Header="Number" Binding="{Binding}"/> 
    </DataGrid.Columns> 
    <DataGrid.InputBindings> 
     <KeyBinding Key="A" Command="{x:Static ApplicationCommands.New}"/> 
    </DataGrid.InputBindings> 
    <DataGrid.CommandBindings>     
     <CommandBinding Command="{x:Static ApplicationCommands.Paste}" 
         CanExecute="CanPaste" Executed="Paste"/> 
     <CommandBinding Command="{x:Static ApplicationCommands.Copy}" 
         CanExecute="CanCopy" Executed="Copy"/> 
     <CommandBinding Command="{x:Static ApplicationCommands.New}" 
         CanExecute="CanAddNew" Executed="AddNew"/> 
    </DataGrid.CommandBindings> 
    <DataGrid.ContextMenu> 
     <ContextMenu>     
      <MenuItem Command="{x:Static ApplicationCommands.Copy}" Header="Copy"/> 
      <MenuItem Command="{x:Static ApplicationCommands.Paste}" Header="Paste"/> 
      <MenuItem Command="{x:Static ApplicationCommands.New}" Header="New row"/> 
     </ContextMenu> 
    </DataGrid.ContextMenu> 
</DataGrid> 

C# -Code:

public partial class Window1 : Window 
{ 
    public Window1() 
    { 
     InitializeComponent(); 
     TheGrid.ItemsSource = numbers; 
    } 

    private void Copy(object sender, ExecutedRoutedEventArgs e) 
    { 
     Clipboard.SetData(DataFormats.Text, string.Join(",", numbers)); 
    } 

    private void CanCopy(object sender, CanExecuteRoutedEventArgs e) 
    { 
     e.CanExecute = true; 
    } 

    private void CanPaste(object sender, CanExecuteRoutedEventArgs e) 
    { 
     e.CanExecute = true; 
     e.Handled = true; 
    } 

    private void Paste(object sender, ExecutedRoutedEventArgs e) 
    { 
     Close(); 
    } 

    private void CanAddNew(object sender, CanExecuteRoutedEventArgs e) 
    { 
     e.CanExecute = true; 
     e.Handled = true; 
    } 

    private void AddNew(object sender, ExecutedRoutedEventArgs e) 
    { 
     numbers.Add(numbers.Count); 
    } 

    private readonly ICollection<int> numbers = new ObservableCollection<int>(); 

    private void TheGrid_ContextMenuOpening(object sender, ContextMenuEventArgs e) 
    { 
     TheGrid.Focus(); 
    } 

} 
+0

Überprüfen Sie diesen Link für Einfügen http://StackOverflow.com/Questions/4118617/WPF-Datagrid-Pasting –

+1

Ihre Lösung macht am meisten Sinn, wenn man bedenkt, dass das Kontextmenü den Fokus aus dem Raster stiehlt und es jedes Mal wiedererlangt, wenn das Kontextmenü geöffnet wird werde das Problem wohl in jedem Fall lösen und habe es für mich getan. Vielen Dank. – too

0

Hier meine VB.NET Version. Es nimmt einen Wert und füllt ihn dann in alle ausgewählten Zellen im Datagrid.

Private Sub gridpaste(ByVal pasteValue As String) 

    Dim rowInd As Integer = Nothing 
    Dim colind As Integer = Nothing 
    Dim add As Integer = 1 

    For Each c As DataGridCellInfo In LineListDataGrid.SelectedCells 

     colind = c.Column.DisplayIndex 

     rowInd = GetRowIndex(LineListDataGrid, c) 

     Try 
      LLDB.LineList.Rows(rowInd)(colind) = pasteValue 
     Catch err As Exception 
      MessageBox.Show(err.Message) 
     End Try 
    Next 

End Sub 

    Public Shared Function GetRowIndex(dataGrid As DataGrid, dataGridCellInfo As DataGridCellInfo) As Integer 
    Dim dgrow As DataGridRow = DirectCast(dataGrid.ItemContainerGenerator.ContainerFromItem(dataGridCellInfo.Item), DataGridRow) 
    If dgrow IsNot Nothing Then 
     Return dgrow.GetIndex() 
    Else 
     Return -1 
    End If 

End Function