मैं एक WPF ऐप में कस्टम नियंत्रण का उपयोग करने की कोशिश कर रहा हूं, और मुझे स्ट्रिंगफ़ॉर्मेट बाध्यकारी का उपयोग करके कुछ समस्या है।कस्टम नियंत्रण पर स्ट्रिंगफॉर्मेट के साथ बाध्यकारी
समस्या पुन: पेश करना आसान है। सबसे पहले, एक WPF एप्लिकेशन बनाएं और इसे "टेम्पलेट बाइंडिंगटेस्ट" कहें। वहां, केवल एक प्रॉपर्टी (टेक्स्ट) के साथ एक कस्टम व्यूमोडेल जोड़ें, और इसे विंडो के डेटाकॉन्टेक्स्ट को असाइन करें। टेक्स्ट प्रॉपर्टी को "हैलो वर्ल्ड!" पर सेट करें।
अब, समाधान पर एक कस्टम नियंत्रण जोड़ें।
using System.Windows;
using System.Windows.Controls;
namespace TemplateBindingTest
{
public class CustomControl : Control
{
static CustomControl()
{
TextProperty = DependencyProperty.Register(
"Text",
typeof(object),
typeof(CustomControl),
new FrameworkPropertyMetadata(null));
DefaultStyleKeyProperty.OverrideMetadata(typeof(CustomControl), new FrameworkPropertyMetadata(typeof(CustomControl)));
}
public static DependencyProperty TextProperty;
public object Text
{
get
{
return this.GetValue(TextProperty);
}
set
{
SetValue(TextProperty, value);
}
}
}
}
समाधान करने के लिए कस्टम नियंत्रण जोड़ने के दौरान, विजुअल स्टूडियो स्वचालित रूप से एक विषय फ़ोल्डर बनाया, एक generic.xaml फ़ाइल के साथ: कस्टम नियंत्रण के रूप में प्राप्त कर सकते हैं के रूप में सरल है। के वहाँ में नियंत्रण के लिए डिफ़ॉल्ट शैली रखते हैं:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:TemplateBindingTest">
<Style TargetType="{x:Type local:CustomControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:CustomControl}">
<TextBlock Text="{TemplateBinding Text}" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
अब, बस खिड़की के नियंत्रण जोड़ सकते हैं और एक StringFormat का उपयोग करके पाठ संपत्ति पर एक बाध्यकारी निर्धारित करते हैं,। इसके अलावा एक सरल TextBlock जोड़ने लगता है कि बाध्यकारी वाक्य रचना सही है होना करने के लिए:
<Window x:Class="TemplateBindingTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:TemplateBindingTest="clr-namespace:TemplateBindingTest" Title="MainWindow" Height="350" Width="525">
<StackPanel>
<TemplateBindingTest:CustomControl Text="{Binding Path=Text, StringFormat=Test1: {0}}"/>
<TextBlock Text="{Binding Path=Text, StringFormat=Test2: {0}}" />
</StackPanel>
संकलित, चलाने के लिए, aaaaand ... पाठ विंडो में प्रदर्शित है:
नमस्ते विश्व !
टेस्ट 2: हैलो वर्ल्ड!
कस्टम नियंत्रण पर, स्ट्रिंगफॉर्मेट पूरी तरह अनदेखा कर दिया जाता है। वीएस आउटपुट विंडो पर कोई त्रुटि दिखाई नहीं दे रही है। क्या चल रहा है?
संपादित करें: कामकाज।
ठीक है, टेम्पलेट बाइंडिंग भ्रामक था। मुझे कारण और एक गंदे कामकाज मिला।
सबसे पहले, आप देखते हैं कि समस्या बटन की सामग्री संपत्ति के साथ एक ही है:
<Button Content="{Binding Path=Text, StringFormat=Test3: {0}}" />
तो, क्या हो रहा है? चलो बाध्यकारीबेस वर्ग की स्ट्रिंगफॉर्मैट संपत्ति में परावर्तक और गोता का उपयोग करें। 'विश्लेषण' सुविधा से पता चलता है कि इस संपत्ति का उपयोग आंतरिक DetermineEffectiveStringFormat
विधि द्वारा किया जाता है। आइए इस विधि को देखें:
internal void DetermineEffectiveStringFormat()
{
Type propertyType = this.TargetProperty.PropertyType;
if (propertyType == typeof(string))
{
// Do some checks then assign the _effectiveStringFormat field
}
}
समस्या ठीक है। प्रभावी स्ट्रिंगफॉर्मैट फ़ील्ड बाध्यकारी को हल करते समय उपयोग किया जाता है। और यह फ़ील्ड केवल तभी सौंपा गया है जब निर्भरता प्रॉपर्टी String
(मेरा है, बटन की सामग्री संपत्ति, Object
) के रूप में है।
ऑब्जेक्ट क्यों? चूंकि मेरा कस्टम नियंत्रण चिपकाए गए एक से थोड़ा जटिल है, और बटन की तरह मैं चाहता हूं कि नियंत्रण का उपयोगकर्ता केवल टेक्स्ट के बजाय बाल नियंत्रण प्रदान करने में सक्षम हो।
तो, अब क्या? हम WPF कोर नियंत्रणों में भी मौजूद व्यवहार में चल रहे हैं, इसलिए मैं इसे "जैसा है" छोड़ सकता हूं।
using System.Windows;
using System.Windows.Controls;
namespace TemplateBindingTest
{
public class CustomControl : Control
{
static CustomControl()
{
TextProperty = DependencyProperty.Register(
"Text",
typeof(string),
typeof(CustomControl),
new FrameworkPropertyMetadata(null, Callback));
HeaderProperty = DependencyProperty.Register(
"Header",
typeof(object),
typeof(CustomControl),
new FrameworkPropertyMetadata(null));
DefaultStyleKeyProperty.OverrideMetadata(typeof(CustomControl), new FrameworkPropertyMetadata(typeof(CustomControl)));
}
static void Callback(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
obj.SetValue(HeaderProperty, e.NewValue);
}
public static DependencyProperty TextProperty;
public static DependencyProperty HeaderProperty;
public object Header
{
get
{
return this.GetValue(HeaderProperty);
}
set
{
SetValue(HeaderProperty, value);
}
}
public string Text
{
set
{
SetValue(TextProperty, value);
}
}
}
}
Header
मेरी TemplateBinding में इस्तेमाल किया संपत्ति है: फिर भी, अपने कस्टम नियंत्रण के रूप में केवल एक आंतरिक परियोजना पर प्रयोग किया जाता है, और मैं इसे XAML से उपयोग करना आसान होना चाहता हूँ, मैं इस हैक का उपयोग करने का फैसला किया। जब Text
पर कोई मान प्रदान किया जाता है, तो स्ट्रिंगफ़ॉर्मैट लागू होता है क्योंकि संपत्ति String
प्रकार है, तो मान को कॉलबैक का उपयोग करके Header
प्रॉपर्टी पर भेजा जाता है। यह काम करता है, लेकिन यह वास्तव में गंदा है:
Header
औरText
संपत्ति सिंक में नहीं हैं, के रूप मेंText
अपडेट नहीं किया गया है जब मैंHeader
अद्यतन करें। मैं कुछ गलतियों से बचने के लिएText
प्रॉपर्टी पर कोई गेटटर प्रदान नहीं करना चुनता हूं, लेकिन अगर कोई सीधे निर्भरता प्रॉपर्टी (GetValue(TextProperty)
) से मूल्य पढ़ता है तो यह तब भी हो सकता है।- अगर कोई
Header
औरText
संपत्ति दोनों के लिए मूल्य प्रदान करता है तो अप्रत्याशित व्यवहार हो सकता है क्योंकि मानों में से एक खो जाएगा।
तो कुल मिलाकर, मैं इस हैक का उपयोग करने की सिफारिश नहीं करता। ऐसा केवल तभी करें जब आप वास्तव में अपनी परियोजना के नियंत्रण में हैं। अगर नियंत्रण में किसी अन्य प्रोजेक्ट पर इस्तेमाल होने का मामूली मौका भी है, तो बस स्ट्रिंगफॉर्मेट को छोड़ दें।
गलत। रनटाइम स्ट्रिंग को स्वरूपित करने से पहले सभी ऑब्जेक्ट्स के लिए 'object.ToString()' को आमंत्रित करता है। –
हां, लेकिन यह स्ट्रिंगफॉर्मेट लागू करने से पहले निर्भरता संपत्ति के अंतर्निहित प्रकार की जांच करता है। यह काम करता है अगर मैं ऑब्जेक्ट की बजाय स्ट्रिंग में अपने डीपी के प्रकार को बदलता हूं। –