none
MVVM - Copy & Paste von Excel in ein DataGrid. RRS feed

  • Frage

  • Hallo erstmal!

    Ich habe folgendes Problem: ich kopiere aus Excel Werte-Bereiche in ein DataGrid.

    Im Excel stehen die Werte als "x" oder string.Empty. Im DataGrid habe ich dafür CheckBoxes vorgegeben (true/false).

    Ich verwende MVVM und die Properties im Hintergrund werden richtig angesprochen. Ich verwende einen IValueConverter um die x -> true und string.empty -> false zu konvertieren.

    In den Settern der Properties (es sind 20 CheckBoxen -> 20 Properties) werden die gewollten Aktionen (create object) auch richtig ausgeführt.

    Leider wird mir im UI jede CheckBox mit "angehakt" dargestellt. Was übersehe ich?

    Binding:

    <DataGridCheckBoxColumnHeader="Basic"Binding="{BindingIsBasic,Converter={StaticResourceCheckBoxConverter},UpdateSourceTrigger=PropertyChanged}"/> 

    Property:

    IValueConverter:

    Nun die Frage: wo liegt der Hund begraben? Wie bekomme ich die GUI dazu, die CheckBoxes richtig anzuhaken?

    Vielen Dank schonmal und hoffentlich reichen die Infos!!

    Cheers,

    Dominic


    Edit: Mit einem gepasteten "x" in eine Zelle funktioniert es. Sobald ich mehrere Werte pasten will, markiert er alle CheckBoxes als "checked", obwohl nur für die eigentlich ausgewählten, die objekte erzeugt werden...
    • Bearbeitet Dominic R Donnerstag, 6. März 2014 13:11 additional info:
    Donnerstag, 6. März 2014 12:36

Antworten

  • Also wenn du nach MVVM arbeitest brauchst/solltest du nicht direkt auf die Cellen Zugreifen, sonder die Cellen sollen sich automatisch Updaten durch das Property Change. Das erklärt auch dass ConvertBack, da du den Wert der Celle geändert hast will da Grid jetzt denn Wert in die gebundene Klasse schreiben.

    Wenn du dieOnExecutedPast Methode von dem Grid benutzen willst, kannst du im im VM eine Methode implementieren, die die Daten verarbeitet, die Rufst du in dem Event auf und Übergibst ihr dann die Daten.

    Die Methode kann dann eine Observabel Collection mit Geeignete Objekte (mit boolean Propertys) bestücken diese Collection Bindest du dann an das DataGrid View.

    Damit hast du dan die Logic für das Verarbeiten der Daten im VM wo sie auch hingehört.

    MFG

    Björn 

    • Als Antwort markiert Dominic R Freitag, 7. März 2014 09:16
    Donnerstag, 6. März 2014 17:43

Alle Antworten

  • Natürlich habe ich auch noch eine OnExecutedPaste Methode:

    protected virtual void OnExecutedPaste(ExecutedRoutedEventArgs args)
            {
                // parse the clipboard data            
                List<string[]> rowData = ClipboardHelper.ParseClipboardData();
    
                if (rowData == null)
                {
                    return;
                }
    
                bool hasAddedNewRow = false;
    
                // call OnPastingCellClipboardContent for each cell
                //int minRowIndex = Items.IndexOf(CurrentItem);
                //int maxRowIndex = Items.Count - 1;
                //int minColumnDisplayIndex = (SelectionUnit != DataGridSelectionUnit.FullRow) ? Columns.IndexOf(CurrentColumn) : 0;
                //int maxColumnDisplayIndex = Columns.Count - 1;
    
                if (this.SelectedCells.Count != 1)
                {
                    int minRowIndex = Items.Count - 1;
                    int maxRowIndex = -1;
                    int minColumnDisplayIndex = Columns.Count;
                    int maxColumnDisplayIndex = -1;
    
                    foreach (DataGridCellInfo info in this.SelectedCells)
                    {
                        minRowIndex = Math.Min(this.Items.IndexOf(info.Item), minRowIndex);
                        maxRowIndex = Math.Max(this.Items.IndexOf(info.Item), minRowIndex);
                        minColumnDisplayIndex = Math.Min(this.Columns.IndexOf(info.Column), minColumnDisplayIndex);
                        maxColumnDisplayIndex = Math.Max(this.Columns.IndexOf(info.Column), maxColumnDisplayIndex);
                    }
    
                    for (int i = minRowIndex; i <= maxRowIndex; i++)
                    {
                        CurrentItem = Items[i];
    
                        BeginEditCommand.Execute(null, this);
    
                        for (int j = minColumnDisplayIndex; j <= maxColumnDisplayIndex; j++)
                        {
                            string[] row = rowData[i % rowData.Count];
                            object dataContent = row[j % row.Length];
                            DataGridColumn column = ColumnFromDisplayIndex(j);
                            if (column.GetType().Equals(typeof(DataGridCheckBoxColumn)))
                            {
                                if (Convert.ToString(dataContent).ToLower().Equals("x") || Convert.ToString(dataContent).ToLower().Equals("true"))
                                {
                                    dataContent = true;
                                }
                                else if (Convert.ToString(dataContent).ToLower().Equals(string.Empty) || Convert.ToString(dataContent).ToLower().Equals("false"))
                                {
                                    dataContent = false;
                                }
                            }
                            column.OnPastingCellClipboardContent(Items[i], dataContent);
    
                        }
    
                        CommitEditCommand.Execute(this, this);
                    }
                }
                else
                {
                    int minRowIndex = Items.IndexOf(CurrentItem);
                    int maxRowIndex = Items.Count - 1;
                    int minColumnDisplayIndex = (SelectionUnit != DataGridSelectionUnit.FullRow) ? Columns.IndexOf(CurrentColumn) : 0;
                    int maxColumnDisplayIndex = Columns.Count - 1;
                    int rowDataIndex = 0;
                    for (int i = minRowIndex; i <= maxRowIndex && rowDataIndex < rowData.Count; i++, rowDataIndex++)
                    {
                        CurrentItem = Items[i];
    
                        BeginEditCommand.Execute(null, this);
    
                        int columnDataIndex = 0;
                        for (int j = minColumnDisplayIndex; j <= maxColumnDisplayIndex && columnDataIndex < rowData[rowDataIndex].Length; j++, columnDataIndex++)
                        {
                            DataGridColumn column = ColumnFromDisplayIndex(j);
                            column.OnPastingCellClipboardContent(Items[i], rowData[rowDataIndex][columnDataIndex]);
                        }
    
                        CommitEditCommand.Execute(this, this);
                        if (i == maxRowIndex)
                        {
                            maxRowIndex++;
                            hasAddedNewRow = true;
                        }
                    }
    
                    // update selection
                    if (hasAddedNewRow)
                    {
                        UnselectAll();
                        UnselectAllCells();
    
                        CurrentItem = Items[minRowIndex];
    
                        if (SelectionUnit == DataGridSelectionUnit.FullRow)
                        {
                            SelectedItem = Items[minRowIndex];
                        }
                        else if (SelectionUnit == DataGridSelectionUnit.CellOrRowHeader ||
                                 SelectionUnit == DataGridSelectionUnit.Cell)
                        {
                            SelectedCells.Add(new DataGridCellInfo(Items[minRowIndex], Columns[minColumnDisplayIndex]));
    
                        }
                    }
                }
            }

    Donnerstag, 6. März 2014 12:42
  • Hi Dominic,

    auf den ersten Blick würde ich sagen dein Value Converter.

    Schreib in die Convert Methode wie die Daten zur Anzeige konvertiert werden soll und in die Back Metode die Konvertierung von Anzeige zu Daten.

    MFG

    Björn

    Donnerstag, 6. März 2014 13:00
  • Hi Björn,

    durch die Convert Methode laufen nur true/false Werte.

    in der ConvertBack kommen die "x" und "" an.

    Dort konvertiere ich die Werte wieder in true/false.  

    Die Property Setter springen auch nur an, wenn ein "x" durch den Converter kam.

    Die GUI ist mein Problem. Die zeigt nur Haken, obwohl im Hintergrund nur die "gewollten" Setter angesprochen werden.

    Ich kann einen Wert x in eine ComboBox pasten, bei ner ganzen Excel Zeile bestehend aus Zellen mit x oder "" geht das ganze nicht mehr.

    Donnerstag, 6. März 2014 13:26
  • Hi Dominic,

    du den Converter doch nur gebunden. Um zu schauen um zu schauen welcher Wert angezeigt wird wird die Convert methode aufgerufen.  Die sollte für die Checkbox true oder false zurück lifern.

    Die ConvertBack sollte dann genau das gegenteil mache also X oder "" zurück lifern.

    Schau dir mal das Beispiel an. Bitte beachten es geht genau in die Umgekerte richtung.

    MFG

    BJörn

    Donnerstag, 6. März 2014 13:39
  • Ablauf ist wie folgt:

    ìn der OnExecutedPaste Methode kriegt die column(DataGridCell) aus dem ClipboardContent:

     IDataObject dataObj = System.Windows.Clipboard.GetDataObject();

    den Wert "x" zugewiesen: siehe oben der ganze Code

      column.OnPastingCellClipboardContent(Items[i], dataContent);
    

    Nach diesem OnPastingCellClipboardContent call wird sofort der ConvertBack aufgerufen.

    Dort mach ich aus dem x -> true und aus "" -> false.

    Wie krieg ich es hin, dass ich die Convert Methode aufrufe?

    Cheers und dankeschön!

    Donnerstag, 6. März 2014 15:05
  • Hi Dominic,

    du brauchst die Methode garnicht Aufrufen, das passiert beim Binding alleine.

    Deinen Code hab ich mir jetzt nicht im Detail angesehen.

    Mal eine Frage du verwedest das MVVM Pattern?

    Du hast 3 Klassen, das Model, die View und das ViewModel ?

    MFG
    Björn

    Donnerstag, 6. März 2014 15:55
  • Ja ich benutze MVVM. Mein DataGrid ist ein CustomDataGrid, das das copy and paste schon "modifiziert" hat.

    Irgendwie scheint es mir so, als würde ich im Grid Code die Column(Cell) falsch mit Werten füttern.

    Daher der falsche Aufruf vom "ConvertBack" ???

    MFG

    Dominic

    Donnerstag, 6. März 2014 16:59
  • Also wenn du nach MVVM arbeitest brauchst/solltest du nicht direkt auf die Cellen Zugreifen, sonder die Cellen sollen sich automatisch Updaten durch das Property Change. Das erklärt auch dass ConvertBack, da du den Wert der Celle geändert hast will da Grid jetzt denn Wert in die gebundene Klasse schreiben.

    Wenn du dieOnExecutedPast Methode von dem Grid benutzen willst, kannst du im im VM eine Methode implementieren, die die Daten verarbeitet, die Rufst du in dem Event auf und Übergibst ihr dann die Daten.

    Die Methode kann dann eine Observabel Collection mit Geeignete Objekte (mit boolean Propertys) bestücken diese Collection Bindest du dann an das DataGrid View.

    Damit hast du dan die Logic für das Verarbeiten der Daten im VM wo sie auch hingehört.

    MFG

    Björn 

    • Als Antwort markiert Dominic R Freitag, 7. März 2014 09:16
    Donnerstag, 6. März 2014 17:43
  • Hi Björn!

    Ich habs mir schon gedacht, dass die Stelle (CustomGrid Code) nicht ganz okay ist, um die Values einfach in die Cell zu schreiben. Weil ich ja somit das MVVM Pattern "breche". 

    Ich werd das schnell mal umbauen und dir noch Bescheid geben!

    Vielen Dank schonmal!

    Jetz machts wieder Sinn!!

    Cheers,

    Dominic

    Freitag, 7. März 2014 09:19