Ich habe eine DataGrid
mit einer Zeile, die ein Bild hat. Dieses Bild ist mit einem Auslöser an einen bestimmten Zustand gebunden. Wenn sich der Status ändert, möchte ich das Bild ändern.
Die Vorlage selbst wird auf die HeaderStyle
von a gesetzt DataGridTemplateColumn
. Diese Vorlage hat einige Bindungen. Der erste Bindungstag zeigt an, welcher Tag heute ist, und der Status ändert das Bild mit einem Auslöser.
Diese Eigenschaften werden in einem ViewModel festgelegt.
Eigenschaften:
public class HeaderItem
{
public string Day { get; set; }
public ValidationStatus State { get; set; }
}
this.HeaderItems = new ObservableCollection<HeaderItem>();
for (int i = 1; i < 15; i++)
{
this.HeaderItems.Add(new HeaderItem()
{
Day = i.ToString(),
State = ValidationStatus.Nieuw,
});
}
Datagrid:
<DataGrid x:Name="PersoneelsPrestatiesDataGrid" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
AutoGenerateColumns="False" SelectionMode="Single" ItemsSource="{Binding CaregiverPerformances}" FrozenColumnCount="1" >
<DataGridTemplateColumn HeaderStyle="{StaticResource headerCenterAlignment}" Header="{Binding HeaderItems[1]}" Width="50">
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<TextBox Text="{ Binding Performances[1].Duration,Converter={StaticResource timeSpanConverter},Mode=TwoWay}"/>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock TextAlignment="Center" Text="{ Binding Performances[1].Duration,Converter={StaticResource timeSpanConverter}}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid>
Datagrid HeaderStyleTemplate:
<Style x:Key="headerCenterAlignment" TargetType="{x:Type DataGridColumnHeader}">
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridColumnHeader}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Text="{Binding Day}" />
<Image x:Name="imageValidation" Grid.Row="1" Width="16" Height="16" Source="{StaticResource imgBevestigd}" />
</Grid>
<ControlTemplate.Triggers>
<MultiDataTrigger >
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding State}" Value="Nieuw"/>
</MultiDataTrigger.Conditions>
<Setter TargetName="imageValidation" Property="Source" Value="{StaticResource imgGeenStatus}"/>
</MultiDataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Wenn ich jetzt das Projekt starte, werden die Bilder nicht angezeigt und ich erhalte folgende Fehlermeldung:
System.Windows.Data-Fehler: 2: FrameworkElement oder FrameworkContentElement für das Zielelement können nicht gefunden werden. BindingExpression: Path = HeaderItems [0]; DataItem = null; Zielelement ist 'DataGridTemplateColumn' (HashCode = 26950454); Die Zieleigenschaft ist 'Header' (Typ 'Objekt').
Warum wird dieser Fehler angezeigt?
Antworten:
Leider ist jedes
DataGridColumn
gehostete unterDataGrid.Columns
nicht Teil desVisual
Baums und daher nicht mit dem Datenkontext des Datagrids verbunden. Bindungen funktionieren also nicht mit ihren Eigenschaften wieVisibility
oderHeader
usw. (obwohl diese Eigenschaften gültige Abhängigkeitseigenschaften sind!).Jetzt fragen Sie sich vielleicht, wie das möglich ist? Soll ihr
Binding
Eigentum nicht an den Datenkontext gebunden sein? Nun, es ist einfach ein Hack. Die Bindung funktioniert nicht wirklich. Es sind tatsächlich die Datagrid-Zellen, die dieses Bindungsobjekt kopieren / klonen und es zur Anzeige ihres eigenen Inhalts verwenden!Zurück zur Lösung Ihres Problems gehe ich davon aus, dass dies
HeaderItems
eine Eigenschaft des Objekts ist, die als dieDataContext
Ihrer übergeordneten Ansicht festgelegt ist. Wir können die VerbindungDataContext
der Ansicht zu jederDataGridColumn
über etwas , das wir einen AnrufProxyElement
.Das folgende Beispiel zeigt, wie ein logisches untergeordnetes Element wie
ContextMenu
oderDataGridColumn
mit den übergeordneten Ansichten verbunden wirdDataContext
In der obigen Ansicht ist derselbe Bindungsfehler aufgetreten, den Sie gefunden haben, wenn ich den ProxyElement-Hack nicht implementiert habe. Das ProxyElement ist ein FrameworkElement, das das aus der Hauptansicht stiehlt
DataContext
und es dem logischen untergeordneten Element wieContextMenu
oder anbietetDataGridColumn
. Dafür muss es alsContent
Unsichtbares gehostet werden,ContentControl
das sich unter derselben Ansicht befindet.Ich hoffe, das führt Sie in die richtige Richtung.
quelle
Parent
während dasDataGridTextColumn
seineDataGridOwner
Eigenschaft nicht verfügbar macht . Sehen Sie in meiner Antwort, wie eine Kontextelementbindung über die RelativeSource-Bindung durchgeführt wird. Kontextmenü-Bindung an den Datenkontext des übergeordneten FenstersEine etwas kürzere Alternative zur Verwendung von a
StaticResource
wie in der akzeptierten Antwort istx:Reference
:Der Hauptvorteil davon ist: Wenn Sie bereits ein Element haben, das nicht der Vorfahr eines DataGrid ist (dh nicht das
StackPanel
im obigen Beispiel), können Sie ihm einfach einen Namen geben und ihnx:Reference
stattdessen verwenden, sodass Sie keinen Dummy definieren müssenFrameworkElement
überhaupt.Wenn Sie versuchen, einen Vorfahren zu referenzieren, erhalten Sie
XamlParseException
zur Laufzeit aufgrund einer zyklischen Abhängigkeit eine.quelle