98

DataGrid画像のある行があります。この画像は、トリガーで特定の状態にバインドされています。状態が変わったら画像を変えたいです。

テンプレート自体はのに設定されHeaderStyleますDataGridTemplateColumn。このテンプレートにはいくつかのバインディングがあります。最初の拘束日はそれが何日であるかを示し、州はトリガーで画像を変更します。

これらのプロパティはViewModelで設定されます。

プロパティ:

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 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>

プロジェクトを起動すると、画像が表示されず、次のエラーが発生します。

System.Windows.Dataエラー:2:ターゲット要素の支配的なFrameworkElementまたはFrameworkContentElementが見つかりません。BindingExpression:Path = HeaderItems [0]; DataItem = null; ターゲット要素は'DataGridTemplateColumn'(HashCode = 26950454); ターゲットプロパティは「ヘッダー」(タイプ「オブジェクト」)です

このエラーが表示されるのはなぜですか?

4

3 に答える 3

173

残念ながら、DataGridColumn下でホストされているものはツリーDataGrid.Columnsの一部ではないVisualため、データグリッドのデータコンテキストに接続されていません。Visibilityしたがって、バインディングは、などのプロパティでは機能しませんHeader(ただし、これらのプロパティは有効な依存関係プロパティです!)。

今、あなたはそれがどのように可能であるか疑問に思うかもしれませんか?それらのBindingプロパティはデータコンテキストにバインドされることになっているのではありませんか?まあそれは単にハックです。バインディングは実際には機能しません。このバインディングオブジェクトをコピー/複製し、独自のコンテンツを表示するために使用するのは、実際にはデータグリッドセルです。

さて、問題の解決に戻りましょう。これは、親ビューのHeaderItemsとして設定されているオブジェクトのプロパティであると思います。DataContextビューのを、と呼ぶものを介して任意のビューに接続できます。DataContextDataGridColumnProxyElement

次の例は、ContextMenuまたはDataGridColumnのような論理的な子を親ビューに接続する方法を示しています。DataContext

 <Window x:Class="WpfApplicationMultiThreading.Window5"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"        
         xmlns:vb="http://schemas.microsoft.com/wpf/2008/toolkit"
         Title="Window5" Height="300" Width="300" >
  <Grid x:Name="MyGrid">
    <Grid.Resources>
        <FrameworkElement x:Key="ProxyElement" DataContext="{Binding}"/>
    </Grid.Resources>
    <Grid.DataContext>
         <TextBlock Text="Text Column Header" Tag="Tag Columne Header"/>
    </Grid.DataContext>
    <ContentControl Visibility="Collapsed"
             Content="{StaticResource ProxyElement}"/>
    <vb:DataGrid AutoGenerateColumns="False" x:Name="MyDataGrid">
        <vb:DataGrid.ItemsSource>
            <x:Array Type="{x:Type TextBlock}">
                <TextBlock Text="1" Tag="1.1"/>
                <TextBlock Text="2" Tag="1.2"/>
                <TextBlock Text="3" Tag="2.1"/>
                <TextBlock Text="4" Tag="2.2"/>
            </x:Array>
        </vb:DataGrid.ItemsSource>
        <vb:DataGrid.Columns>
            <vb:DataGridTextColumn
                       Header="{Binding DataContext.Text,
                                     Source={StaticResource ProxyElement}}"
                       Binding="{Binding Text}"/>
            <vb:DataGridTextColumn
                       Header="{Binding DataContext.Tag,
                                     Source={StaticResource ProxyElement}}"
                       Binding="{Binding Tag}"/>
        </vb:DataGrid.Columns>
    </vb:DataGrid>
  </Grid>
</Window>

上記のビューでは、ProxyElementハックを実装しなかった場合に見つかったのと同じバインディングエラーが発生しました。ProxyElementは、メインビューからを盗み、またはDataContextなどの論理的な子に提供する任意のFrameworkElementです。そのためには、同じビューの下にある非表示にとしてホストする必要があります。ContextMenuDataGridColumnContentContentControl

これがあなたを正しい方向に導くことを願っています。

于 2011-10-05T13:00:56.617 に答える
16

StaticResource受け入れられた答えのようにを使用するためのわずかに短い代替案は次のx:Referenceとおりです。

<StackPanel>

    <!--Set the DataContext here if you do not want to inherit the parent one-->
    <FrameworkElement x:Name="ProxyElement" Visibility="Collapsed"/>

    <DataGrid>
        <DataGrid.Columns>
            <DataGridTextColumn
                Header="{Binding DataContext.Whatever, Source={x:Reference ProxyElement}}"
                Binding="{Binding ...}" />
        </DataGrid.Columns>
    </DataGrid>

</StackPanel>

これの主な利点は次のとおりです。DataGridの祖先ではない要素(つまり、上記の例ではないStackPanel要素)がすでにある場合は、名前を付けてx:Reference代わりに使用できるため、ダミーを定義する必要はありません。FrameworkElementまったく。

祖先を参照しようとするとXamlParseException、周期的な依存関係があるため、実行時に取得します。

于 2020-04-10T09:44:09.633 に答える
0

プロキシを使用しない方法は、コンストラクターでバインディングを設定することです。

var i = 0;
var converter = new BooleanToVisibilityConverter();
foreach(var column in DataGrid.Columns)
{
    BindingOperations.SetBinding(column, DataGridColumn.VisibilityProperty, new Binding($"Columns[{i++}].IsSelected")
    { 
        Source = ViewModel,
        Converter = converter,
    });
}
于 2021-04-06T21:36:24.203 に答える