WPF में एक विधि से बांधें?


90

आप इस परिदृश्य में WPF में किसी ऑब्जेक्ट विधि से कैसे बंधते हैं?

public class RootObject
{
    public string Name { get; }

    public ObservableCollection<ChildObject> GetChildren() {...}
}

public class ChildObject
{
    public string Name { get; }
}

XAML:

<TreeView ItemsSource="some list of RootObjects">
    <TreeView.Resources>
        <HierarchicalDataTemplate DataType="{x:Type data:RootObject}" 
                                  ItemsSource="???">
            <TextBlock Text="{Binding Path=Name}" />
        </HierarchicalDataTemplate>
        <HierarchicalDataTemplate DataType="{x:Type data:ChildObject}">
            <TextBlock Text="{Binding Path=Name}" />
        </HierarchicalDataTemplate>
    </TreeView.Resources>
</TreeView>

यहां मैं GetChildrenप्रत्येक RootObjectपेड़ पर विधि से बांधना चाहता हूं ।

EDIT बाइंडिंग ObjectDataProviderकाम नहीं करता है क्योंकि मैं वस्तुओं की एक सूची के लिए बाध्य हूं, और ObjectDataProviderआवश्यकताओं को या तो एक स्थिर विधि है, या यह स्वयं का उदाहरण बनाता है और इसका उपयोग करता है।

उदाहरण के लिए, मैट के उत्तर का उपयोग कर मुझे मिलता है:

System.Windows.Data त्रुटि: 33: ObjectDataProvider ऑब्जेक्ट नहीं बना सकता है; Type = 'RootObject'; त्रुटि = 'निर्माता के लिए गलत मानदंड।'

System.Windows.Data त्रुटि: 34: ObjectDataProvider: प्रकार पर पद्धति को लागू करने की कोशिश में विफलता; विधि = 'GetChildren'; Type = 'RootObject'; त्रुटि = 'निर्दिष्ट सदस्य को लक्ष्य पर नहीं लगाया जा सकता है।' TargetException: 'System.Reflection.TargetException: गैर-स्थिर पद्धति के लिए लक्ष्य की आवश्यकता होती है।


हां आप ठीक हैं। ObjectDataProvider के पास एक ObjectInstance गुण (किसी विशिष्ट उदाहरण पर इसकी विधि को कॉल करने के लिए) है, लेकिन मुझे नहीं लगता कि यह एक निर्भरता गुण है, इसलिए आप इसे (AFAIK) बाँध नहीं सकते।
मैट हैमिल्टन

1
हाँ, मैंने ObjectInstance को बांधने की कोशिश की और पाया कि यह एक निर्भरता संपत्ति नहीं है।
कैमरून मैकफारलैंड

मैं अपने उत्तर को वैसे भी छोड़ दूंगा, दोनों आपके अपडेट को कुछ संदर्भ देंगे और किसी और की मदद करने के लिए जो इस प्रश्न को एक समान पर्याप्त समस्या के साथ पाता है।
मैट हैमिल्टन

क्या आपको वास्तव में ObjectInstance को बांधने की आवश्यकता है? (क्या यह बदल जाएगा) यह मानते हुए कि आप बदले में अपना स्वयं का इवेंट-ईवेंट हैंडलिंग बना सकते हैं और ObjectDataProvider को कोड में अपडेट कर सकते हैं ...
टिम लोवेल-स्मिथ

1
इस तथ्य के एक साल बाद, मैंने कुछ स्रोत कोड के साथ अपना उत्तर अपडेट किया।
ड्रू नोज

जवाबों:


71

एक और दृष्टिकोण जो आपके लिए काम कर सकता है वह है एक कस्टम बनाने के लिए जो IValueConverterएक पैरामीटर के रूप में एक विधि का नाम लेता है, ताकि इसका उपयोग इस तरह किया जा सके:

ItemsSource="{Binding 
    Converter={StaticResource MethodToValueConverter},
    ConverterParameter='GetChildren'}"

यह कन्वर्टर परावर्तन का उपयोग करते हुए विधि खोजता और आह्वान करता है। इसके लिए किसी तर्क की जरूरत नहीं है।

यहां इस तरह के एक कनवर्टर के स्रोत का एक उदाहरण दिया गया है:

public sealed class MethodToValueConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        var methodName = parameter as string;
        if (value==null || methodName==null)
            return value;
        var methodInfo = value.GetType().GetMethod(methodName, new Type[0]);
        if (methodInfo==null)
            return value;
        return methodInfo.Invoke(value, new object[0]);
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotSupportedException("MethodToValueConverter can only be used for one way conversion.");
    }
}

और इसी इकाई परीक्षण:

[Test]
public void Convert()
{
    var converter = new MethodToValueConverter();
    Assert.AreEqual("1234", converter.Convert(1234, typeof(string), "ToString", null));
    Assert.AreEqual("ABCD", converter.Convert(" ABCD ", typeof(string), "Trim", null));

    Assert.IsNull(converter.Convert(null, typeof(string), "ToString", null));

    Assert.AreEqual("Pineapple", converter.Convert("Pineapple", typeof(string), "InvalidMethodName", null));
}

ध्यान दें कि यह कनवर्टर targetTypeपैरामीटर लागू नहीं करता है ।


6
हम्म्, ... एक हैक की तरह लगता है, लेकिन मुझे लगता है कि यह एकमात्र तरीका हो सकता है। यह निश्चित है कि सबसे आसान होने वाला है!
अस्सीऑन यूनाइट

25

यह सुनिश्चित नहीं है कि यह आपके परिदृश्य में कितनी अच्छी तरह काम करेगा, लेकिन आप MethodNameसंपत्ति का उपयोग ObjectDataProviderकरने के लिए इसे एक विशिष्ट विधि कह सकते हैं (आपके विशिष्ट मापदंडों के साथ)MethodParameters इसके डेटा को पुनः प्राप्त करने के लिए संपत्ति के ) को ।

यहाँ MSDN पृष्ठ से सीधे लिया गया एक स्निपेट है:

<Window.Resources>
    <ObjectDataProvider ObjectType="{x:Type local:TemperatureScale}"
        MethodName="ConvertTemp" x:Key="convertTemp">
        <ObjectDataProvider.MethodParameters>
            <system:Double>0</system:Double>
            <local:TempType>Celsius</local:TempType>
        </ObjectDataProvider.MethodParameters>
    </ObjectDataProvider>
</Window.Resources>

इसलिए यह एक ObjectDataProviderऐसा ConvertTempतरीका है जो एक TemperatureScaleवर्ग के उदाहरण पर एक कॉल कर रहा है, दो मापदंडों ( 0और TempType.Celsius) को पार कर रहा है ।


10

क्या आपको विधि से बंधना होगा?

क्या आप एक संपत्ति के लिए बाध्य कर सकते हैं जो पाने वाला विधि है?

public ObservableCollection<ChildObject> Children
{
   get
   {
      return GetChildren();
   }
}

2
मैं कैमरन की टिप्पणी का मतलब यह निकालता हूं कि वह एक प्रकार से बाध्य है, जिसमें वह एक संपत्ति नहीं जोड़ सकता है।
ड्रू नोक

2
यदि आप संभावित रूप से लंबे समय तक चलने वाले हो सकते हैं, तो आपको उन गुणों के लिए बाध्य करने से बचना चाहिए, जो विधियों को कॉल करते हैं। इस तरह के तरीके होने से यह अच्छा डिज़ाइन नहीं है क्योंकि कोड का एक उपभोक्ता केवल एक स्थानीय चर का उपयोग करने के लिए एक संपत्ति की उम्मीद करता है।
16

@markml तो सीधे कार्य करने के लिए बंधन का क्या मतलब है? तो ओपी के सवाल का आपके मामले पर कोई मतलब नहीं है?
तेमन शिपाही

4

जब तक आप विधि को कॉल करने के लिए एक संपत्ति जोड़ सकते हैं (या एक रैपर वर्ग बना सकते हैं जो उस संपत्ति को जोड़ता है) जिस तरह से मैं जानता हूं कि वह एक ValueConverter का उपयोग कर रहा है।



3

आप उपयोग कर सकते हैं System.ComponentModel एक प्रकार के लिए गुणों को गतिशील रूप से परिभाषित लिए (वे संकलित मेटाडेटा का हिस्सा नहीं हैं)। मैंने WPF में इस दृष्टिकोण का उपयोग करने के लिए बाध्यकारी को एक प्रकार से सक्षम किया है जो अपने मूल्यों को खेतों में संग्रहीत करता है, क्योंकि खेतों के लिए बाध्यकारी संभव नहीं है।

ICustomTypeDescriptorऔर TypeDescriptionProviderप्रकार आप प्राप्त करने के लिए आप क्या चाहते हैं अनुमति दे सकते हैं। इस लेख के अनुसार :

TypeDescriptionProviderआपको एक अलग वर्ग लिखने की अनुमति देता है जो लागू करता है ICustomTypeDescriptorऔर फिर इस वर्ग को अन्य प्रकार के विवरणों के प्रदाता के रूप में पंजीकृत करने के लिए।

मैंने स्वयं इस दृष्टिकोण की कोशिश नहीं की है, लेकिन मुझे आशा है कि यह आपके मामले में मददगार है।


0

अपने WPF परिदृश्य में किसी ऑब्जेक्ट की विधि से बाँधने के लिए, आप एक संपत्ति पर बाँध सकते हैं जो एक प्रतिनिधि को लौटाता है।

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