Ich habe zwei einfache Modellklassen und ein ViewModel ...
public class GridItem
{
public string Name { get; set; }
public int CompanyID { get; set; }
}
public class CompanyItem
{
public int ID { get; set; }
public string Name { get; set; }
}
public class ViewModel
{
public ViewModel()
{
GridItems = new ObservableCollection<GridItem>() {
new GridItem() { Name = "Jim", CompanyID = 1 } };
CompanyItems = new ObservableCollection<CompanyItem>() {
new CompanyItem() { ID = 1, Name = "Company 1" },
new CompanyItem() { ID = 2, Name = "Company 2" } };
}
public ObservableCollection<GridItem> GridItems { get; set; }
public ObservableCollection<CompanyItem> CompanyItems { get; set; }
}
... und ein einfaches Fenster:
<Window x:Class="DataGridComboBoxColumnApp.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">
<Grid>
<DataGrid AutoGenerateColumns="False" ItemsSource="{Binding GridItems}" >
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Name}" />
<DataGridComboBoxColumn ItemsSource="{Binding CompanyItems}"
DisplayMemberPath="Name"
SelectedValuePath="ID"
SelectedValueBinding="{Binding CompanyID}" />
</DataGrid.Columns>
</DataGrid>
</Grid>
</Window>
Das ViewModel ist DataContext
in App.xaml.cs auf das MainWindow eingestellt:
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
MainWindow window = new MainWindow();
ViewModel viewModel = new ViewModel();
window.DataContext = viewModel;
window.Show();
}
}
Wie Sie sehen, setze ich ItemsSource
das DataGrid auf die GridItems
Sammlung des ViewModel. Dieser Teil funktioniert, die einzelne Gitterlinie mit dem Namen "Jim" wird angezeigt.
Ich möchte auch ItemsSource
die ComboBox in jeder Zeile auf die CompanyItems
Sammlung des ViewModel setzen. Dieser Teil funktioniert nicht: Die ComboBox bleibt leer und im Debugger-Ausgabefenster wird eine Fehlermeldung angezeigt:
System.Windows.Data-Fehler: 2: FrameworkElement oder FrameworkContentElement für das Zielelement können nicht gefunden werden. BindingExpression: Path = CompanyItems; DataItem = null; Zielelement ist 'DataGridComboBoxColumn' (HashCode = 28633162); Die Zieleigenschaft ist 'ItemsSource' (Typ 'IEnumerable').
Ich glaube, dass WPF erwartet CompanyItems
, eine Eigenschaft zu sein, GridItem
die nicht der Fall ist, und das ist der Grund, warum die Bindung fehlschlägt.
Ich habe bereits versucht mit einem zu arbeiten RelativeSource
und AncestorType
mag so:
<DataGridComboBoxColumn ItemsSource="{Binding CompanyItems,
RelativeSource={RelativeSource Mode=FindAncestor,
AncestorType={x:Type Window}}}"
DisplayMemberPath="Name"
SelectedValuePath="ID"
SelectedValueBinding="{Binding CompanyID}" />
Aber das gibt mir einen weiteren Fehler in der Debugger-Ausgabe:
System.Windows.Data-Fehler: 4: Quelle für Bindung mit Referenz 'RelativeSource FindAncestor, AncestorType =' System.Windows.Window ', AncestorLevel =' 1 '' kann nicht gefunden werden. BindingExpression: Path = CompanyItems; DataItem = null; Zielelement ist 'DataGridComboBoxColumn' (HashCode = 1150788); Die Zieleigenschaft ist 'ItemsSource' (Typ 'IEnumerable').
Frage: Wie kann ich die ItemsSource der DataGridComboBoxColumn an die CompanyItems-Auflistung des ViewModel binden? Ist das überhaupt möglich?
Vielen Dank für Ihre Hilfe im Voraus!
Die Dokumentation auf MSDN über die
ItemsSource
von derDataGridComboBoxColumn
sagt , dass nur statische Ressourcen, statische Code oder Inline - Sammlungen von Combobox Elemente können an die gebunden werdenItemsSource
:Das Binden an die Eigenschaft eines DataContext ist nicht möglich, wenn ich das richtig verstehe.
Und tatsächlich: Wenn ich
CompanyItems
eine statische Eigenschaft in ViewModel erstelle ...... fügen Sie dem Fenster den Namespace hinzu, in dem sich das ViewModel befindet ...
... und ändern Sie die Bindung in ...
... dann funktioniert es. Aber die ItemsSource als statische Eigenschaft zu haben, mag manchmal in Ordnung sein, aber es ist nicht immer das, was ich will.
quelle
Die richtige Lösung scheint zu sein:
Das obige Layout funktioniert für mich einwandfrei und sollte für andere funktionieren. Diese Designauswahl ist ebenfalls sinnvoll, obwohl sie nirgendwo sehr gut erklärt wird. Wenn Sie jedoch eine Datenspalte mit vordefinierten Werten haben, ändern sich diese Werte normalerweise zur Laufzeit nicht. Das
CollectionViewSource
einmalige Erstellen und Initialisieren der Daten ist also sinnvoll. Es werden auch die längeren Bindungen beseitigt, um einen Vorfahren zu finden und seinen Datenkontext zu binden (was sich für mich immer falsch anfühlte).Ich überlasse dies hier allen anderen, die mit dieser Bindung zu kämpfen haben und sich gefragt haben, ob es einen besseren Weg gibt (da diese Seite offensichtlich immer noch in den Suchergebnissen auftaucht, bin ich hierher gekommen).
quelle
MyItems
würden zu einem Kompilierungsfehler führen, wenn Sie ihn mit dem OP-Code verwendenMir ist klar, dass diese Frage über ein Jahr alt ist, aber ich bin bei der Behandlung eines ähnlichen Problems nur darauf gestoßen und dachte, ich würde eine andere mögliche Lösung teilen, falls sie einem zukünftigen Reisenden (oder mir selbst, wenn ich dies später vergesse und mich selbst finde) helfen könnte auf StackOverflow herumflippen zwischen Schreien und Werfen des nächsten Objekts auf meinem Schreibtisch).
In meinem Fall konnte ich den gewünschten Effekt erzielen, indem ich eine DataGridTemplateColumn anstelle einer DataGridComboBoxColumn verwendete, wie im folgenden Snippet beschrieben. [Vorbehalt: Ich verwende .NET 4.0, und was ich gelesen habe, lässt mich glauben, dass sich das DataGrid stark weiterentwickelt hat, also YMMV, wenn frühere Versionen verwendet werden]
quelle
RookieRick hat recht,
DataGridTemplateColumn
stattDataGridComboBoxColumn
eine viel einfachere XAML zu verwenden.Wenn Sie die
CompanyItem
Liste direkt von derGridItem
Website aus aufrufen, können Sie sie außerdem entfernenRelativeSource
.IMHO, das gibt Ihnen eine sehr saubere Lösung.
XAML:
Modell anzeigen:
quelle
Ihre ComboBox versucht zu binden, um zu binden
GridItem[x].CompanyItems
, was nicht existiert.Ihre RelativeBinding ist geschlossen, muss jedoch
DataContext.CompanyItems
gebunden werden , da Window.CompanyItems nicht vorhanden istquelle
CompanyItems
durchDataContext.CompanyItems
das letzte XAML-Snippet in meiner Frage), aber es gibt mir den gleichen Fehler in der Debugger-Ausgabe.{Binding ElementName=RootWindow, Path=DataContext.CompanyItems}
Die Bast-Art, die ich benutze, binde ich den Textblock und die Combobox an dieselbe Eigenschaft und diese Eigenschaft sollte notifyPropertyChanged unterstützen.
Ich habe relativeresource verwendet, um an den Datenkontext der übergeordneten Ansicht zu binden. Dies ist eine Benutzersteuerung, um die Datagrid-Ebene beim Binden zu erhöhen, da in diesem Fall das Datagrid in einem Objekt sucht, das Sie in datagrid.itemsource verwendet haben
quelle