Lỗi WPF: Không thể tìm thấy FrameworkElement quản lý cho phần tử mục tiêu


87

Tôi có một DataGridvới một hàng có một hình ảnh. Hình ảnh này được liên kết với một trình kích hoạt đến một trạng thái nhất định. Khi trạng thái thay đổi tôi muốn thay đổi hình ảnh.

Bản thân mẫu được đặt trên HeaderStylecủa a DataGridTemplateColumn. Mẫu này có một số ràng buộc. Ngày ràng buộc đầu tiên hiển thị ngày đó là ngày gì và Bang thay đổi hình ảnh bằng một bộ kích hoạt.

Các thuộc tính này được đặt trong một ViewModel.

Tính chất:

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,
    });
}

Lưới dữ liệu:

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

Bây giờ khi tôi khởi động dự án, hình ảnh không hiển thị và tôi gặp lỗi này:

Lỗi System.Windows.Data: 2: Không thể tìm thấy FrameworkElement quản lý hoặc FrameworkContentElement cho phần tử đích. BindingExpression: Path = HeaderItems [0]; DataItem = null; phần tử đích là 'DataGridTemplateColumn' (HashCode = 26950454); thuộc tính đích là 'Header' (loại 'Đối tượng')

Tại sao lỗi này hiển thị?


4
Tôi đã kiểm tra giải pháp đã trả lời ở trên, nhưng nó không hoạt động trong trường hợp của tôi. Khi tôi chuyển sang giải pháp khác như trong liên kết thomaslevesque.com/2011/03/21/… . Ý tưởng cũng giống như giải pháp, thay vì sử dụng FrameworkElement, họ tạo ra một lớp khác. Sau đó, nó hoạt động cho tôi.
leo5th

Đối với những người khác kết thúc ở đây bằng cách tìm kiếm các thông báo lỗi: Câu trả lời của câu hỏi tương tự này giúp tôi giải quyết vấn đề khá dễ dàng stackoverflow.com/a/18657986/4961688
Tim Pohlmann

Câu trả lời:


165

Đáng buồn thay, bất kỳ dữ liệu nào DataGridColumnđược lưu trữ dưới DataGrid.Columnsđều không phải là một phần của Visualcây và do đó không được kết nối với ngữ cảnh dữ liệu của datagrid. Vì vậy, các ràng buộc không hoạt động với các thuộc tính của chúng như Visibilityhoặc Headerv.v. (mặc dù các thuộc tính này là các thuộc tính phụ thuộc hợp lệ!).

Bây giờ bạn có thể tự hỏi làm thế nào điều đó là có thể? Không phải thuộc tính của họ Bindingphải được ràng buộc với ngữ cảnh dữ liệu? Nó chỉ đơn giản là một hack. Sự ràng buộc không thực sự hoạt động. Nó thực sự là các ô datagrid sao chép / sao chép đối tượng ràng buộc này và sử dụng nó để hiển thị nội dung của chính chúng!

Vì vậy, bây giờ trở lại giải quyết vấn đề của bạn, tôi giả sử rằng đó HeaderItemslà một thuộc tính của đối tượng được đặt làm DataContextChế độ xem cha mẹ của bạn. Chúng tôi có thể kết nối DataContextkhung nhìn với bất kỳ DataGridColumnthông qua một cái gì đó mà chúng tôi gọi là a ProxyElement.

Ví dụ bên dưới minh họa cách kết nối một phần tử con hợp lý, chẳng hạn như ContextMenuhoặc DataGridColumnvới Chế độ xem cha mẹ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>

Chế độ xem ở trên gặp phải lỗi ràng buộc tương tự mà bạn đã tìm thấy nếu tôi không thực hiện hack ProxyElement. Các ProxyElement là bất kỳ FrameworkElement rằng đánh cắp các DataContexttừ giao diện chính và cung cấp nó cho đứa trẻ logic như ContextMenuhay DataGridColumn. Cho rằng nó phải được lưu trữ như một Contentthành vô hình ContentControlmà là dưới cùng View.

Tôi hy vọng điều này hướng dẫn bạn đi đúng hướng.


25
Tôi thấy việc phải sử dụng công cụ proxy hacky này thực sự thất vọng nhưng tôi không thể tìm ra cách khác để đạt được chức năng tương tự nếu không ... Cảm ơn bạn.
Alex Hope O'Connor,

2
Điều này không hiệu quả với tôi nhưng sau khi đọc bài viết của Josh Smith về Chi nhánh ảo, tôi đã thử thêm liên kết OneWayToSource vào điều khiển gốc của mình để đặt DataContext "ProxyElement" và điều đó đã hoạt động.
jpierson

1
Không. Giải pháp trên phù hợp với .NET 3.5 rất tốt.
WPF-it

1
Câu trả lời này đã cũ, nhưng vẫn hữu ích với .NET 4.0. Rất nhiều câu trả lời xung quanh việc sao chép DataContext vào cột dường như không hoạt động. Tôi cần hiển thị / ẩn một cột tùy thuộc vào thuộc tính mô hình chế độ xem và giải pháp này hoạt động tốt. Và không có mã phía sau sẽ không gây ra sự cố ngoại giao trong quá trình xem xét mã.
James_UK_DEV

3
Menu ngữ cảnh của FYI không giống nhau và có một công việc không phải proxy. Trình đơn ngữ cảnh có thuộc tính hiển thị Parenttrong khi trình đơn DataGridTextColumnkhông hiển thị thuộc tính của nó DataGridOwner. Xem cách một mục bối cảnh ràng buộc được thực hiện thông qua RelativeSource ràng buộc trong câu trả lời của tôi Context Menu Binding cho Phụ Huynh Window của DataContext
ΩmegaMan

8

Một cách thay thế ngắn hơn một chút để sử dụng StaticResourcenhư trong câu trả lời được chấp nhận là 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>

Ưu điểm chính của việc này là: nếu bạn đã có một yếu tố đó là không tổ tiên của một DataGrid (tức là không những StackPaneltrong ví dụ trên), bạn chỉ có thể cung cấp cho nó một cái tên và sử dụng nó như là x:Referencethay vào đó, do đó không cần phải xác định bất kỳ giả FrameworkElementở tất cả.

Nếu bạn thử tham chiếu đến một tổ tiên, bạn sẽ nhận được XamlParseExceptionthời gian chạy do sự phụ thuộc theo chu kỳ.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.