डब्ल्यूपीएफ त्रुटि: लक्ष्य तत्व के लिए गवर्निंग फ्रेमवर्क को नहीं पा सकता है


87

मुझे DataGridएक पंक्ति मिली है जिसमें एक छवि है। यह छवि एक निश्चित राज्य के लिए एक ट्रिगर के साथ बाध्य है। जब राज्य बदलता है तो मैं छवि बदलना चाहता हूं।

टेम्प्लेट स्वयं HeaderStylea पर सेट है 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>

डाटाग्रिड हैडरसाइलटेम्पलेट:

<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: टारगेट एलिमेंट के लिए गवर्निंग फ्रेमवर्क या फ्रेमवर्ककंटेनमेंट नहीं पा सकते हैं। BindingExpression: पथ = HeaderItems [0]; DataItem = बातिल; लक्ष्य तत्व 'डेटाग्रिडमप्लेटकॉल्यूम' (हैशकोड = 26950454) है; टारगेट प्रॉपर्टी 'हैडर' (टाइप 'ऑब्जेक्ट')

यह त्रुटि क्यों दिखाई जा रही है?


4
मैंने ऊपर दिए गए समाधान की जाँच की, लेकिन यह मेरे मामले में काम नहीं करता है। जब मैं लिंक के रूप में दूसरे समाधान पर स्विच करता हूं thomaslevesque.com/2011/03/21/… । विचार समाधान के समान है, फ्रेमवर्क के उपयोग के बजाय, उन्होंने एक और वर्ग बनाया। फिर यह मेरे लिए काम करता है।
leo5th

दूसरों के लिए त्रुटि संदेश की खोज करके यहां समाप्त होने के लिए: इस तरह के प्रश्न के उत्तर ने मुझे समस्या को आसानी से हल करने में मदद की, बड़ी आसानी से stackoverflow.com/a/18657986/4961688
टिम पोल्हमन

जवाबों:


165

अफसोस की बात है कि कोई भी 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 किसी भी FrameworkElement कि है चुराDataContext मुख्य दृश्य और तार्किक बच्चे को यह जैसे प्रस्तावों से ContextMenuया DataGridColumn। इसके लिए इसे Contentएक अदृश्य के रूप में होस्ट किया जाना चाहिए, ContentControlजो उसी दृश्य के अंतर्गत है।

मुझे आशा है कि यह आपको सही दिशा में मार्गदर्शन करेगा।


25
मुझे लगता है कि इस हैक किए गए प्रॉक्सी सामान का वास्तव में निराशाजनक उपयोग हो रहा है, लेकिन मैं अन्यथा कार्यक्षमता को प्राप्त करने का दूसरा तरीका नहीं खोज सकता ... धन्यवाद।
एलेक्स होप ओ'कॉनर

2
यह मेरे लिए काम नहीं करता था, लेकिन वर्चुअल शाखाओं के बारे में जोश स्मिथ के लेख को पढ़ने के बाद मैंने "ProxyElement" DataContext को सेट करने के लिए अपने रूट कंट्रोल पर OneWayToSource बाइंडिंग को जोड़ने का प्रयास किया और यह काम किया।
जिपरसन

1
नहीं। उपरोक्त समाधान .NET 3.5 के लिए बहुत अच्छी तरह से फिट बैठता है।
WPF-it

1
यह उत्तर पुराना है, लेकिन अभी भी .NET 4.0 के विरुद्ध उपयोगी है। कॉलम में DataContext की प्रतिलिपि बनाने के लिए उत्तर के बहुत सारे काम नहीं करते हैं। मुझे एक मॉडल मॉडल की संपत्ति के आधार पर एक कॉलम दिखाने / छिपाने की आवश्यकता थी और इस समाधान ने अच्छी तरह से काम किया। और कोई कोड नहीं होने के कारण कोड की समीक्षा में एक राजनयिक घटना नहीं होगी।
जेम्स_यूके_डीईवी

3
FYI संदर्भ मेनू समान नहीं है और इसमें गैर-प्रॉक्सी कार्य है। प्रसंग मेनू में एक उजागर संपत्ति है, Parentजबकि DataGridTextColumnइसकी DataGridOwnerसंपत्ति को उजागर नहीं करता है। देखें कि कैसे एक संदर्भ आइटम बाइंडिंग मेरे उत्तर में RelativeSource बाइंडिंग के माध्यम से पूरा होता है प्रसंग मेनू पेरेंट विंडो के
डाटाकॉन्सेट पर

8

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>

इस का मुख्य लाभ यह है: अगर आप पहले से ही एक तत्व जो है नहीं एक डेटा ग्रिड के पूर्वज (यानी नहींStackPanel ऊपर के उदाहरण में), तुम बस इसे एक नाम देने के लिए और के रूप में उपयोग कर सकते हैं x:Referenceबजाय, इसलिए किसी भी डमी को परिभाषित करने की जरूरत नहीं FrameworkElementबिलकुल।

यदि आप पूर्वज को संदर्भित करने का प्रयास करते हैं, तो XamlParseExceptionचक्रीय निर्भरता के कारण आपको रन-टाइम मिलेगा ।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.