Laden...

Wie kann ich Daten aus der selektierten Zelle eines DataGrids anzeigen?

Erstellt von CombatKarl vor 3 Jahren Letzter Beitrag vor 3 Jahren 838 Views
CombatKarl Themenstarter:in
36 Beiträge seit 2020
vor 3 Jahren
Wie kann ich Daten aus der selektierten Zelle eines DataGrids anzeigen?

Hallo zusammen,

ich habe in meinem MainWindow ein DataGrid verankert, dass als ItemSource eine Observable Collection besitzt und meine Daten werden wunderbar angezeigt.

Zu Testzwecken haben ich einen Button hinzugefügt, der ein RelayCommand startet, dass auch tadellos funktioniert.

Das Datagrid ist auf SelectionUnit "Cell" eingestellt und ich suche nun einen Weg, den Inhalt einer selektierten Zelle als Console.WriteLine wieder zu geben.

Bislang habe ich in meinem ViewModel eine DataGridCellInfo Property, die an die "CurrentCell" Property des DataGrids gebunden ist.

Bin ich mit dieser Vorgehensweise grundsätzlich richtig oder sollte ich anders einsteigen ??

Vielen Dank für die Hilfe.

<--- Wer übt, ist feige ! --->

16.842 Beiträge seit 2008
vor 3 Jahren

Bei sowas kannste Dich selbst fragen: bin ich der Erste, der das Problem hat? 😉
Google-Suche nach wpf datagrid selecteditem

Da siehst zig Treffer, wie man es machen kann.

CombatKarl Themenstarter:in
36 Beiträge seit 2020
vor 3 Jahren

Vielen Dank für die Hilfe,

allerdings bin ich natürlich auf die Suche gegangen, bevor ich hier im Forum gepostet habe. Jedoch sind die gefundenen möglichen Lösungen nie wirklich MVVM konform gewesen, da permanent Code-Behind benutzt wird, um auf das DataGrid direkt zuzugreifen. Dabei wird häufig das "SelectedCellsChanged" Event abgegriffen und der Inhalt der selektierten Zelle abgefragt.

Ich bin mir sicher, dass dies auch ohne Code-Behind lösbar ist, nur fehlt mir da der Ansatz.

Vielen Dank für die weitere Hilfe !!

<--- Wer übt, ist feige ! --->

5.658 Beiträge seit 2006
vor 3 Jahren

Wir wissen aus deiner Beschreibung weder, was du schon probiert hast, noch, was dabei nicht geklappt hat, oder nicht MVVM-konform war. Du sagst auch nicht, was du eigentlich damit erreichen willst (außer, den Wert auf der Konsole auszugeben).

Es gibt das DataGrid.SelectedCellsChanged-Event, das du abbonieren kannst, und es gibt die DataGrid.SelectedCells-Eigenschaft, an die du binden kannst. Wo hast du damit ein Problem?

Bitte beachte [Hinweis] Wie poste ich richtig?, besonders Punkt 5.

Weeks of programming can save you hours of planning

CombatKarl Themenstarter:in
36 Beiträge seit 2020
vor 3 Jahren

Hallo zurück,

sorry für meine mangelhaften Ausführungen. Dann versuche ich mal etwas konkreter zu werden. Mein Plan ist, mit Hilfe eines DataGrids einen Monatskalender zu erstellen. Dabei repräsentiert jede einzelne Reihe eine Person und jede Spalte einen Tag. Somit kann ich dann darüber pro Person & Tag Eintragungen vornehmen (Anwesend, Abwesend, Urlaub etc.)

Grundsätzlich habe ich dafür eine eigene Klasse (EintragModel), welche die Properties Name, Vorname & die Tage des Monats bereithält.

EintragModel


    public class EintragModel
    {
        public string Vorname { get; set; }
        public string Nachname { get; set; }
        public string Tag1 { get; set; } = null;
        public string Tag2 { get; set; } = null;
        public string Tag3 { get; set; } = null;
        public string Tag4 { get; set; } = null;
        public string Tag5 { get; set; } = null;

    }

Weiterhin gibt es mein CollectionViewModel, welches durch eine Schleife meine ObservableCollection befüllt (dies ist hier alles nur exemplarisch, da die Daten später aus einer Datenbank gelesen werden sollen).

CollectionViewModel


    public class CollectionViewModel : ViewModelBase
    {
        private ObservableCollection<EintragModel> _myEintragCollection;
        public ObservableCollection<EintragModel> MyEintragCollection
        {
            get
            {
                _myEintragCollection = new ObservableCollection<EintragModel>();
                for (int i = 1; i <= 10; i++)
                {
                    _myEintragCollection.Add
                        (
                            new EintragModel()
                            {
                                Vorname = $"{i}. Vorname",
                                Nachname = $"{i}. Nachname",
                                Tag1=$"Tag 1",
                                Tag2=$"Tag 2",
                                Tag3=$"Tag 3",
                                Tag4=$"Tag 4",
                                Tag5=$"Tag 5"
                            }
                        );
                }

                return _myEintragCollection;
            }
        }
    }

Danach kommt das DateTimeViewModel, das mir das Datum eines ausgewählten Monats an eine Property des MainWindowViewModels übergibt.

DateTimeViewModel


    public class DateTimeViewModel : ViewModelBase
    {
        private MainWindowViewModel _mainWindowViewModel;
        public DateTimeViewModel(MainWindowViewModel viewModel)
        {
            _mainWindowViewModel = viewModel;
        }
        public int TotalDays (int Monat, int Jahr)
        {
            var totalDays = DateTime.DaysInMonth(Jahr, Monat);
            return totalDays;
        }
        public void GetTage(int Monat, int Jahr)
        {
            for (int i = 1; i <= TotalDays(Monat, Jahr); i++)
            {
                switch (i)
                {
                    case 1:
                        _mainWindowViewModel.Header1 = string.Format("{0:dd.MM.}", new DateTime(Jahr, Monat, i));
                        break;
                    case 2:
                        _mainWindowViewModel.Header2 = string.Format("{0:dd.MM.}", new DateTime(Jahr, Monat, i));
                        break;
                    case 3:
                        _mainWindowViewModel.Header3 = string.Format("{0:dd.MM.}", new DateTime(Jahr, Monat, i));
                        break;
                    case 4:
                        _mainWindowViewModel.Header4 = string.Format("{0:dd.MM.}", new DateTime(Jahr, Monat, i));
                        break;
                    case 5:
                        _mainWindowViewModel.Header5 = string.Format("{0:dd.MM.}", new DateTime(Jahr, Monat, i));
                        break;
                }
            }
        }
    }

MainWindowViewModel


    public class MainWindowViewModel : ViewModelBase
    {
        
        private CollectionViewModel _collection = new CollectionViewModel();
        private string _header1;
        private string _header2;
        private string _header3;
        private string _header4;
        private string _header5;

        public string Header1
        {
            get => this._header1;
            set
            {
                SetProperty(ref this._header1, value);
            }
        }
        public string Header2
        {
            get => this._header2;
            set
            {
                SetProperty(ref this._header2, value);
            }
        }
        public string Header3
        {
            get => this._header3;
            set
            {
                SetProperty(ref this._header3, value);
            }
        }
        public string Header4
        {
            get => this._header4;
            set
            {
                SetProperty(ref this._header4, value);
            }
        }
        public string Header5
        {
            get => this._header5;
            set
            {
                SetProperty(ref this._header5, value);
            }
        }
        public ICommand MyGetCommand { get; private set; }

        public MainWindowViewModel()
        {
            DateTimeViewModel.GetTage(08,2020);
            MyGetCommand = new RelayCommand<object>(MyCommand);

        }

        public DateTimeViewModel DateTimeViewModel
        {
            get => new DateTimeViewModel(this);
        }
        public ObservableCollection<EintragModel> Collection
        {
            get => this._collection.MyEintragCollection;
        }

        private void MyCommand(object obj)
        {
            Console.WriteLine("Zellenvalue, der ausgewählten Zelle");
        }

    }

Die Daten werden alle korrekt im DataGrid angezeigt und mit der SelectionUnit="Cell" kann ich auch bequem einzelne oder mehrere Zellen auswählen.

Nun möchte ich mit dem Button und dem gebundenen Command (auch hier nur exemplarisch) den Inhalt der gewählten Zelle als Console.WriteLine ausgeben.

MainWindow


<Window x:Class="DataGridTest.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:DataGridTest"
        xmlns:converter="clr-namespace:DataGridTest.Converter"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="auto" WindowState="Maximized">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="auto"/>
            <RowDefinition Height="auto"/>
            <RowDefinition Height="auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <DataGrid Margin="10" Grid.Row="2" BorderBrush="{x:Null}" 
                  ItemsSource="{Binding Collection}" 
                  CanUserSortColumns="False" 
                  AutoGenerateColumns="False" 
                  VerticalScrollBarVisibility="Disabled"
                  HeadersVisibility="Column" 
                  AlternatingRowBackground="LightBlue" 
                  CanUserResizeColumns="False" 
                  CanUserReorderColumns="False" 
                  CanUserAddRows="False"
                  FrozenColumnCount="2" 
                  HorizontalScrollBarVisibility="Auto" 
                  ColumnWidth="60" 
                  MinRowHeight="50"
                  HorizontalContentAlignment="Center" 
                  VerticalContentAlignment="Center"
                  SelectionUnit="Cell"
                  SelectedItem="{Binding MyCellInfo, Mode=OneWayToSource}">
            <DataGrid.Columns>
                <DataGridTextColumn Binding="{Binding Vorname}" Width="100"/>
                <DataGridTextColumn Binding="{Binding Nachname}" Width="100"/>
                <!--#region Tag 1 -->
                <DataGridTextColumn Binding="{Binding Tag1}">
                    <DataGridTextColumn.Header>
                        <TextBlock Text="{Binding DataContext.Header1,RelativeSource={RelativeSource AncestorType={x:Type local:MainWindow}}}"/>
                    </DataGridTextColumn.Header>
                </DataGridTextColumn>
                <!--#endregion-->                
                <!--#region Tag 2 -->
                <DataGridTextColumn Binding="{Binding Tag2}">
                    <DataGridTextColumn.Header>
                        <TextBlock Text="{Binding DataContext.Header2,RelativeSource={RelativeSource AncestorType={x:Type local:MainWindow}}}"/>
                    </DataGridTextColumn.Header>
                </DataGridTextColumn>
                <!--#endregion-->
                <!--#region Tag 3 -->
                <DataGridTextColumn Binding="{Binding Tag3}">
                    <DataGridTextColumn.Header>
                        <TextBlock Text="{Binding DataContext.Header3,RelativeSource={RelativeSource AncestorType={x:Type local:MainWindow}}}"/>
                    </DataGridTextColumn.Header>
                </DataGridTextColumn>
                <!--#endregion-->
                <!--#region Tag 4 -->
                <DataGridTextColumn Binding="{Binding Tag4}">
                    <DataGridTextColumn.Header>
                        <TextBlock Text="{Binding DataContext.Header4,RelativeSource={RelativeSource AncestorType={x:Type local:MainWindow}}}"/>
                    </DataGridTextColumn.Header>
                </DataGridTextColumn>
                <!--#endregion-->
                <!--#region Tag 5 -->
                <DataGridTextColumn Binding="{Binding Tag5}">
                    <DataGridTextColumn.Header>
                        <TextBlock Text="{Binding DataContext.Header5,RelativeSource={RelativeSource AncestorType={x:Type local:MainWindow}}}"/>
                    </DataGridTextColumn.Header>
                </DataGridTextColumn>
                <!--#endregion-->
            </DataGrid.Columns>
        </DataGrid>
        <Button Content="Anzeige" Grid.Row="3" HorizontalAlignment="Center" VerticalAlignment="Center" Command="{Binding MyGetCommand}"/>
    </Grid>
</Window>

Ich bin nun um jede Idee dankbar, mein Command richtig umzusetzen und endlich mal ein Ergebnis angezeigt zu bekommen.

Vielen Dank für Eure Hilfe !

<--- Wer übt, ist feige ! --->

4.942 Beiträge seit 2008
vor 3 Jahren

Wie hast du denn MyCellInfo definiert?
Mittels SelectedItem erhältst du den Zellenwert (vom Typ object).

Nun kannst du entweder aus deinem Button-Command auf diese (gebundene) Eigenschaft (MyCellInfo) zugreifen oder aber als CommandParameter übergeben lassen, s. Top-Antwort in Bind to SelectedItems from DataGrid or ListBox in MVVM (nur daß du dann SelectedItem anstatt SelectedItems benutzt).

CombatKarl Themenstarter:in
36 Beiträge seit 2020
vor 3 Jahren

Guten Morgen,

vielen Dank für die weitere Hilfe.

Wie hast du denn MyCellInfo definiert?

Meine Property MyCellInfo sieht folgender Maßen aus.


public object MyCellInfo { get; set; }

Weiterhin habe ich laut dem Link und der Anleitung dies als CommandParameter übergeben lassen. ```xml
    <Button Content="Anzeige" 
            Grid.Row="3" 
            HorizontalAlignment="Center" 
            VerticalAlignment="Center" 
            CommandParameter="{Binding ElementName=myDataGrid, Path=SelectedItems}"
            Command="{Binding MyGetCommand}"/>

```csharp

        private void MyCommand(object obj)
        {
            Console.WriteLine(MyCellInfo.ToString());
        }

Als Ausgabe in der Console erhalte ich nun Folgendes: "System.Windows.Controls.DataGridCellInfo"

Wie komme ich denn nun weiter, dass ich daraus die benötigten Daten auslese ?

Vielen herzlichen Dank.

<--- Wer übt, ist feige ! --->

4.942 Beiträge seit 2008
vor 3 Jahren

Meintest du


CommandParameter="{Binding ElementName=myDataGrid, Path=SelectedItem}" <!-- also ohne 's' -->

?

Wenn du wirklich statt dem Datenwert ein DataGridCellInfo-Objekt erhältst, dann brauchst du doch nur den übergebenen Parameter obj zu casten:


var cellIinfo = obj as DataGridCellInfo;
if (cellInfo != null)
  Console.WriteLine(cellInfo.Item.ToString());

Vllt. liegt es daran, daß du object anstatt einen konkreten Typ bei deiner VM-Eigenschaft angegeben hast, denn laut WPF Binding SelectedItem in DataGrid sollte es direkt funktionieren (aber vllt. ist auch SelectionUnit="Cell" eine Ausnahme und diese gibt immer ein DataGridCellInfo-Objekt zurück?).

Edit: Vllt. solltest du auch direkt auf SelectedValue (anstatt SelectedItem) binden und dann string (anstatt object) benutzen...