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 ! --->
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.
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
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 ! --->
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
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 ! --->
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).
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 ! --->
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...