ข้อผิดพลาด WPF: ไม่พบการควบคุม FrameworkElement สำหรับองค์ประกอบเป้าหมาย


88

ฉันมี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 Error: 2: ไม่พบการปกครอง FrameworkElement หรือ FrameworkContentElement สำหรับองค์ประกอบเป้าหมาย BindingExpression: Path = HeaderItems [0]; DataItem = null; องค์ประกอบเป้าหมายคือ 'DataGridTemplateColumn' (HashCode = 26950454); คุณสมบัติเป้าหมายคือ 'Header' (ประเภท 'Object')

เหตุใดจึงแสดงข้อผิดพลาดนี้


4
ฉันตรวจสอบวิธีแก้ปัญหาที่ตอบข้างต้นแล้ว แต่มันไม่ได้ผลในกรณีของฉัน เมื่อฉันเปลี่ยนไปใช้โซลูชันอื่นตามลิงค์thomaslevesque.com/2011/03/21/… . แนวคิดนี้เหมือนกับโซลูชันแทนที่จะใช้ FrameworkElement พวกเขาสร้างคลาสอื่น แล้วมันก็ใช้ได้สำหรับฉัน
leo5th

สำหรับคนอื่น ๆ ที่ลงเอยที่นี่ด้วยการค้นหาข้อความแสดงข้อผิดพลาด: คำตอบของคำถามที่คล้ายกันนี้ช่วยให้ฉันแก้ปัญหาได้ค่อนข้างง่ายstackoverflow.com/a/18657986/4961688
Tim Pohlmann

คำตอบ:


166

น่าเสียดายที่DataGridColumnโฮสต์ใด ๆ ที่อยู่ภายใต้DataGrid.Columnsไม่ได้เป็นส่วนหนึ่งของVisualทรีดังนั้นจึงไม่เชื่อมต่อกับบริบทข้อมูลของดาต้ากริด ดังนั้นการผูกจึงใช้ไม่ได้กับคุณสมบัติเช่นVisibilityหรือHeaderอื่น ๆ (แม้ว่าคุณสมบัติเหล่านี้จะเป็นคุณสมบัติการอ้างอิงที่ถูกต้อง!)

ตอนนี้คุณอาจสงสัยว่าเป็นไปได้อย่างไร? Bindingทรัพย์สินของพวกเขาไม่ควรถูกผูกไว้กับบริบทข้อมูลหรือไม่? มันเป็นเพียงการแฮ็ก การผูกใช้ไม่ได้จริงๆ จริงๆแล้วมันคือเซลล์ดาต้ากริดที่คัดลอก / โคลนวัตถุที่มีผลผูกพันนี้และใช้เพื่อแสดงเนื้อหาของตัวเอง!

ตอนนี้กลับไปแก้ปัญหาของคุณฉันถือว่าHeaderItemsเป็นคุณสมบัติของวัตถุที่ตั้งค่าเป็นDataContextมุมมองหลักของคุณ เราสามารถเชื่อมต่อDataContextมุมมองใด ๆDataGridColumnผ่านสิ่งที่เราเรียกว่าProxyElementว่า

ตัวอย่างด้านล่างแสดงให้เห็นถึงวิธีการเชื่อมต่อลูกเชิงตรรกะเช่น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 เป็น FrameworkElement ใด ๆ ที่ขโมยDataContextจากมุมมองหลักและข้อเสนอไปยังเด็กตรรกะเช่นหรือContextMenu DataGridColumnสำหรับสิ่งนั้นจะต้องโฮสต์เป็นสิ่งContentที่มองไม่เห็นContentControlซึ่งอยู่ภายใต้มุมมองเดียวกัน

ฉันหวังว่านี่จะแนะนำคุณไปในทิศทางที่ถูกต้อง


26
ฉันพบว่าการต้องใช้พร็อกซีที่แฮ็กกี้นี้ทำให้ผิดหวังจริงๆ แต่ฉันไม่สามารถหาวิธีอื่นในการใช้งานฟังก์ชันเดียวกันได้ ... ขอบคุณ
Alex Hope O'Connor

2
สิ่งนี้ไม่ได้ผลสำหรับฉัน แต่หลังจากอ่านบทความของ Josh Smith เกี่ยวกับ Virtual Branches ฉันพยายามเพิ่มการเชื่อมโยง OneWayToSource บนการควบคุมรูทของฉันเพื่อตั้งค่า DataContext "ProxyElement" และใช้งานได้
jpierson

1
ไม่ โซลูชันข้างต้นเหมาะกับ. NET 3.5 เป็นอย่างดี
WPF-it

1
คำตอบนี้เก่า แต่ยังมีประโยชน์เมื่อเทียบกับ. NET 4.0 คำตอบมากมายเกี่ยวกับการคัดลอก DataContext ไปยังคอลัมน์ดูเหมือนจะไม่ได้ผล ฉันต้องการแสดง / ซ่อนคอลัมน์โดยขึ้นอยู่กับคุณสมบัติของโมเดลมุมมองและโซลูชันนี้ทำงานได้ดี และการไม่มีรหัสหลังจะไม่ทำให้เกิดเหตุการณ์ทางการทูตในการตรวจสอบรหัส
James_UK_DEV

3
เมนูบริบท FYI ไม่เหมือนกันและมีวิธีแก้ไขที่ไม่ใช่พร็อกซี เมนูบริบทมีคุณสมบัติที่เปิดเผยParentในขณะที่DataGridTextColumnไม่เปิดเผยDataGridOwnerคุณสมบัติ ดูว่าการเชื่อมรายการบริบททำได้อย่างไรผ่านการเชื่อม RelativeSource ในคำตอบของฉันเมนูบริบทที่ผูกกับ Datacontext ของหน้าต่างหลัก
ΩmegaMan

8

ทางเลือกที่สั้นกว่าเล็กน้อยในการใช้ a 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ณ รันไทม์เนื่องจากการพึ่งพาวัฏจักร

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.