2008-09-28 14 views
8

मैं अपने यूनिट परीक्षणों में एक असामान्य समस्या में भाग रहा हूं। जिस वर्ग का मैं परीक्षण कर रहा हूं वह रनटाइम पर गतिशील रूप से एक निर्भरता संपत्ति बनाता है और उस निर्भरता संपत्ति का प्रकार परिस्थितियों के आधार पर भिन्न हो सकता है। मेरे यूनिट परीक्षण लिखते समय, मुझे निर्भरता संपत्ति को विभिन्न प्रकारों के साथ बनाने की आवश्यकता होती है और इससे त्रुटियों की ओर इशारा होता है क्योंकि आप मौजूदा निर्भरता संपत्ति को फिर से परिभाषित नहीं कर सकते हैं।एक WPF निर्भरता संपत्ति को पंजीकृत करने का कोई तरीका?

तो वहाँ किसी भी तरह से या तो एक निर्भरता संपत्ति अन-रजिस्टर करने के लिए या एक मौजूदा निर्भरता संपत्ति का प्रकार बदलने के लिए है?

धन्यवाद!


OverrideMetadata() केवल आप डिफ़ॉल्ट मान की तरह एक बहुत कुछ चीजें बदल तो यह उपयोगी नहीं है की सुविधा देता है। AppDomain दृष्टिकोण एक अच्छा विचार है और काम कर सकता है लेकिन यूनिट परीक्षण के लिए वास्तव में जानना चाहता था उससे अधिक जटिल लगता है।

मैं कभी नहीं तो मैं punted और ध्यान से मेरी इकाई परीक्षण पुनर्गठित समस्या से बचने के लिए एक निर्भरता संपत्ति का पंजीकरण रद्द करने के लिए एक रास्ता खोजने किया था। मुझे थोड़ा कम परीक्षण कवरेज मिल रहा है, लेकिन चूंकि यह समस्या वास्तविक एप्लिकेशन में कभी नहीं होगी और केवल यूनिट परीक्षण के दौरान मैं इसके साथ रह सकता हूं।

सहायता के लिए धन्यवाद!

उत्तर

8

मैं सिर्फ कल समान मुद्दा था जब मेरे अपने DependencyProperty परीक्षण करने के लिए कोशिश कर रहा है वर्ग बनाना मैं इस सवाल पर आया, और देखा कि निर्भरता गुणों को अपंजीकृत करने का कोई वास्तविक समाधान नहीं था। तो मैंने यह देखने के लिए Red Gate .NET Reflector का उपयोग करके कुछ खुदाई की थी कि मैं क्या कर सकता हूं।

DependencyProperty.Register भार के को देखते हुए, वे सब DependencyProperty.RegisterCommon को इंगित लग रहा था। यदि संपत्ति पहले से ही

FromNameKey key = new FromNameKey(name, ownerType); 
lock (Synchronized) 
{ 
    if (PropertyFromName.Contains(key)) 
    { 
    throw new ArgumentException(SR.Get("PropertyAlreadyRegistered", 
     new object[] { name, ownerType.Name })); 
    } 
} 

दूसरा पंजीकृत है, DependencyProperty

DependencyProperty dp = 
    new DependencyProperty(name, propertyType, ownerType, 
    defaultMetadata, validateValueCallback); 

defaultMetadata.Seal(dp, null); 
//...Yada yada... 
lock (Synchronized) 
{ 
    PropertyFromName[key] = dp; 
} 

के आसपास दोनों टुकड़े केंद्र DependencyProperty.PropertyFromName, एक HashTable का पंजीयन

पहले जाँच करने के लिए: यह विधि दो भागों है। मैं भी DependencyProperty.RegisteredPropertyList, एक ItemStructList<DependencyProperty> देखा लेकिन जहां यह प्रयोग किया जाता है नहीं देखा है। हालांकि, सुरक्षा के लिए, मैंने सोचा कि अगर मैं संभव हो तो उससे भी हटने की कोशिश करूंगा।

तो मैं निम्नलिखित कोड है कि मुझे "अपंजीकृत" करने के लिए एक निर्भरता संपत्ति की अनुमति के साथ समापन।

private void RemoveDependency(DependencyProperty prop) 
{ 
    var registeredPropertyField = typeof(DependencyProperty). 
    GetField("RegisteredPropertyList", BindingFlags.NonPublic | BindingFlags.Static); 
    object list = registeredPropertyField.GetValue(null); 
    var genericMeth = list.GetType().GetMethod("Remove"); 
    try 
    { 
    genericMeth.Invoke(list, new[] { prop }); 
    } 
    catch (TargetInvocationException) 
    { 
    Console.WriteLine("Does not exist in list"); 
    } 

    var propertyFromNameField = typeof(DependencyProperty). 
    GetField("PropertyFromName", BindingFlags.NonPublic | BindingFlags.Static); 
    var propertyFromName = (Hashtable)propertyFromNameField.GetValue(null); 

    object keyToRemove = null; 
    foreach (DictionaryEntry item in propertyFromName) 
    { 
    if (item.Value == prop) 
     keyToRemove = item.Key; 
    } 
    if (keyToRemove != null) 
    propertyFromName.Remove(keyToRemove); 
} 

यह मेरे लिए "पहले से ही पंजीकृत" अपवाद प्राप्त किए बिना मेरे परीक्षण चलाने के लिए काफी अच्छा काम करता है। हालांकि, मैं दृढ़ता से अनुशंसा करता हूं कि आप किसी भी प्रकार के उत्पादन कोड में इसका उपयोग न करें। संभवतः एक कारण है कि एमएसएफटी ने एक निर्भरता संपत्ति को अपंजीकृत करने का औपचारिक तरीका नहीं चुना है, और इसके खिलाफ जाने का प्रयास सिर्फ परेशानी के लिए है।

+1

बहुत अच्छा! आप सही हैं कि मैं इसे उत्पादन कोड में उपयोग नहीं करना चाहता लेकिन जासूसी कार्य का एक बहुत अच्छा काम! –

0

मुझे नहीं लगता कि आप किसी निर्भरता संपत्ति अन-रजिस्टर कर सकते हैं लेकिन आप इस तरह से मेटाडाटा अधिभावी द्वारा यह फिर से परिभाषित कर सकते हैं:

MyDependencyProperty.OverrideMetadata(typeof(MyNewType), 
        new PropertyMetadata()); 
2

बाकी सब विफल रहता है, तो आप हर टेस्ट के लिए एक नया AppDomain बना सकते हैं ।

0

हम इस तरह एक लेबल के लिए नाम पंजीकृत हैं:

Label myLabel = new Label(); 
this.RegisterName(myLabel.Name, myLabel); 

हम आसानी से उपयोग करके नाम का पंजीकरण रद्द कर सकते हैं:

this.UnregisterName(myLabel.Name); 
0

मुझे परिदृश्य का सामना करना पड़ रहा था जहां मैंने कस्टम नियंत्रण बनाया था जो Selector से प्राप्त होता है जिसका अर्थ है दो आइटम स्रोत गुण, HorizontalItemsSource और VerticalItemsSource

मैं आइटमकंट्रोल प्रॉपर्टी का भी उपयोग नहीं करता हूं, और नहीं चाहता कि उपयोगकर्ता इसे एक्सेस कर सके।

तो मैंने statenjason's great answer पढ़ा, और इसने मुझे डीपी को हटाने के तरीके पर एक विशाल पीओवी दिया।
हालांकि, मेरी समस्या थी, कि के बाद से मैं ItemsSourceProperty सदस्य और ItemsSourcePrivate Shadows (सी # में private new) के रूप में, मैं MyControlType.ItemsSourceProperty का उपयोग कर छाया चर को उल्लेख करता है के बाद से डिजाइन समय में यह लोड नहीं कर सका घोषित कर दिया।
इसके अलावा, ऊपर वर्णित लूप का उपयोग करते हुए उपरोक्त है (foreach DictionaryEntry इत्यादि), मुझे यह कहते हुए एक अपवाद था कि संग्रह पुनरावृत्ति के दौरान बदल गया है।

इसलिए मैं एक अलग दृष्टिकोण जहां DependencyProperty hardcodedly कार्यावधि में संदर्भित किया जाता है के साथ आया था, और इसलिए यह (VB.NET, खेद) नहीं बदल गया है संग्रह सरणी में कॉपी किया जाता है:

Dim dpType = GetType(DependencyProperty) 
Dim bFlags = BindingFlags.NonPublic Or BindingFlags.Static 

Dim FromName = 
    Function(name As String, ownerType As Type) DirectCast(dpType.GetMethod("FromName", 
    bFlags).Invoke(Nothing, {name, ownerType}), DependencyProperty) 

Dim PropertyFromName = DirectCast(dpType.GetField("PropertyFromName", bFlags). 
    GetValue(Nothing), Hashtable) 

Dim dp = FromName.Invoke("ItemsSource", GetType(DimensionalGrid)) 
Dim entries(PropertyFromName.Count - 1) As DictionaryEntry 
PropertyFromName.CopyTo(entries, 0) 
Dim entry = entries.Single(Function(e) e.Value Is dp) 
PropertyFromName.Remove(entry.Key) 

महत्वपूर्ण नोट: उपर्युक्त कोड सभी कस्टम नियंत्रण के साझा कन्स्ट्रक्टर से घिरे हुए हैं, और मुझे गीलेर को पंजीकृत करने की आवश्यकता नहीं है, क्योंकि मुझे पता है कि सेल्सेटर डीओईएस का एक उप-वर्ग ItemsSource डीपी प्रदान करता है।

0

अलग-अलग डेटामैप्लेट्स के साथ एक सामग्री प्रदाता के साथ कोई समस्या थी, जहां उनमें से एक को संपत्ति के साथ निर्भरता प्रॉपर्टी चेंजबैक थी जब सामग्री प्रस्तुतकर्ता सामग्री को किसी अन्य डेटा टेम्पलेट में बदलते समय कॉलबैक बनी रही।

UserControls घटना अनलोड में मैं कहा जाता है:

BindingOperations.ClearAllBindings(this); 
Dispatcher.CurrentDispatcher.Invoke(DispatcherPriority.Normal, new DispatcherOperationCallback(delegate { return null; }), null); 

वह मेरे लिए काम किया

संबंधित मुद्दे