9

मुझे पता है कि मुझे RemoveValueChanged को कॉल करने की आवश्यकता है, लेकिन मुझे इसे कॉल करने के लिए एक विश्वसनीय स्थान नहीं मिला है। मैं सीख रहा हूं कि शायद कोई नहीं है।मैं संलग्न व्यवहार पर निर्भरताप्रॉपर्टी डिस्क्रिप्टर AddValueChanged मेमोरी लीक को कैसे ठीक कर सकता हूं?

मुझे लगता है कि मुझे परिवर्तन की निगरानी करने के लिए एक अलग तरीका खोजने की आवश्यकता है, फिर AddValueChanged का उपयोग करके हैंडलर जोड़ना। मैं इसे प्राप्त करने के सर्वोत्तम तरीके पर सलाह की तलाश में हूं। मैंने PropertyMetadata में PropertyChangedCallback का उपयोग करने की सिफारिश देखी है, लेकिन मुझे यकीन नहीं है कि यह कैसे करें जब मेरे टेक्स्टबॉक्स और एडॉर्नर स्थिर नहीं हैं। साथ ही, IsFocused संपत्ति मेरी कक्षा में बनाई गई निर्भरता प्रॉपर्टी नहीं है।

धन्यवाद।

public sealed class WatermarkTextBoxBehavior 
{ 
    private readonly TextBox m_TextBox; 
    private TextBlockAdorner m_TextBlockAdorner; 

    private WatermarkTextBoxBehavior(TextBox textBox) 
    { 
     if (textBox == null) 
      throw new ArgumentNullException("textBox"); 

     m_TextBox = textBox; 
    } 

    #region Behavior Internals 

    private static WatermarkTextBoxBehavior GetWatermarkTextBoxBehavior(DependencyObject obj) 
    { 
     return (WatermarkTextBoxBehavior)obj.GetValue(WatermarkTextBoxBehaviorProperty); 
    } 

    private static void SetWatermarkTextBoxBehavior(DependencyObject obj, WatermarkTextBoxBehavior value) 
    { 
     obj.SetValue(WatermarkTextBoxBehaviorProperty, value); 
    } 

    private static readonly DependencyProperty WatermarkTextBoxBehaviorProperty = 
     DependencyProperty.RegisterAttached("WatermarkTextBoxBehavior", 
      typeof(WatermarkTextBoxBehavior), typeof(WatermarkTextBoxBehavior), new UIPropertyMetadata(null)); 

    public static bool GetEnableWatermark(TextBox obj) 
    { 
     return (bool)obj.GetValue(EnableWatermarkProperty); 
    } 

    public static void SetEnableWatermark(TextBox obj, bool value) 
    { 
     obj.SetValue(EnableWatermarkProperty, value); 
    } 

    public static readonly DependencyProperty EnableWatermarkProperty = 
     DependencyProperty.RegisterAttached("EnableWatermark", typeof(bool), 
      typeof(WatermarkTextBoxBehavior), new UIPropertyMetadata(false, OnEnableWatermarkChanged)); 

    private static void OnEnableWatermarkChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
    { 
     if (e.OldValue != null) 
     { 
      var enabled = (bool)e.OldValue; 

      if (enabled) 
      { 
       var textBox = (TextBox)d; 
       var behavior = GetWatermarkTextBoxBehavior(textBox); 
       behavior.Detach(); 

       SetWatermarkTextBoxBehavior(textBox, null); 
      } 
     } 

     if (e.NewValue != null) 
     { 
      var enabled = (bool)e.NewValue; 

      if (enabled) 
      { 
       var textBox = (TextBox)d; 
       var behavior = new WatermarkTextBoxBehavior(textBox); 
       behavior.Attach(); 

       SetWatermarkTextBoxBehavior(textBox, behavior); 
      } 
     } 
    } 

    private void Attach() 
    { 
     m_TextBox.Loaded += TextBoxLoaded; 
     m_TextBox.TextChanged += TextBoxTextChanged; 
     m_TextBox.DragEnter += TextBoxDragEnter; 
     m_TextBox.DragLeave += TextBoxDragLeave; 
     m_TextBox.IsVisibleChanged += TextBoxIsVisibleChanged; 
    } 

    private void Detach() 
    { 
     m_TextBox.Loaded -= TextBoxLoaded; 
     m_TextBox.TextChanged -= TextBoxTextChanged; 
     m_TextBox.DragEnter -= TextBoxDragEnter; 
     m_TextBox.DragLeave -= TextBoxDragLeave; 
     m_TextBox.IsVisibleChanged -= TextBoxIsVisibleChanged; 
    } 

    private void TextBoxDragLeave(object sender, DragEventArgs e) 
    { 
     UpdateAdorner(); 
    } 

    private void TextBoxDragEnter(object sender, DragEventArgs e) 
    { 
     m_TextBox.TryRemoveAdorners<TextBlockAdorner>(); 
    } 

    private void TextBoxIsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e) 
    { 
     UpdateAdorner(); 
    } 

    private void TextBoxTextChanged(object sender, TextChangedEventArgs e) 
    { 
     var hasText = !string.IsNullOrEmpty(m_TextBox.Text); 
     SetHasText(m_TextBox, hasText); 
    } 

    private void TextBoxLoaded(object sender, RoutedEventArgs e) 
    { 
     Init(); 
    } 

    #endregion 

    #region Attached Properties 

    public static string GetLabel(TextBox obj) 
    { 
     return (string)obj.GetValue(LabelProperty); 
    } 

    public static void SetLabel(TextBox obj, string value) 
    { 
     obj.SetValue(LabelProperty, value); 
    } 

    public static readonly DependencyProperty LabelProperty = 
     DependencyProperty.RegisterAttached("Label", typeof(string), typeof(WatermarkTextBoxBehavior)); 

    public static Style GetLabelStyle(TextBox obj) 
    { 
     return (Style)obj.GetValue(LabelStyleProperty); 
    } 

    public static void SetLabelStyle(TextBox obj, Style value) 
    { 
     obj.SetValue(LabelStyleProperty, value); 
    } 

    public static readonly DependencyProperty LabelStyleProperty = 
     DependencyProperty.RegisterAttached("LabelStyle", typeof(Style), 
      typeof(WatermarkTextBoxBehavior)); 

    public static bool GetHasText(TextBox obj) 
    { 
     return (bool)obj.GetValue(HasTextProperty); 
    } 

    private static void SetHasText(TextBox obj, bool value) 
    { 
     obj.SetValue(HasTextPropertyKey, value); 
    } 

    private static readonly DependencyPropertyKey HasTextPropertyKey = 
     DependencyProperty.RegisterAttachedReadOnly("HasText", typeof(bool), 
      typeof(WatermarkTextBoxBehavior), new UIPropertyMetadata(false)); 

    public static readonly DependencyProperty HasTextProperty = 
     HasTextPropertyKey.DependencyProperty; 

    #endregion 

    private void Init() 
    { 
     m_TextBlockAdorner = new TextBlockAdorner(m_TextBox, GetLabel(m_TextBox), GetLabelStyle(m_TextBox)); 
     UpdateAdorner(); 

     DependencyPropertyDescriptor focusProp = DependencyPropertyDescriptor.FromProperty(UIElement.IsFocusedProperty, typeof(FrameworkElement)); 
     if (focusProp != null) 
     { 
      focusProp.AddValueChanged(m_TextBox, (sender, args) => UpdateAdorner()); 
     } 

     DependencyPropertyDescriptor containsTextProp = DependencyPropertyDescriptor.FromProperty(HasTextProperty, typeof(TextBox)); 
     if (containsTextProp != null) 
     { 
      containsTextProp.AddValueChanged(m_TextBox, (sender, args) => UpdateAdorner()); 
     } 
    } 

    private void UpdateAdorner() 
    { 
     if (GetHasText(m_TextBox) || 
      m_TextBox.IsFocused || 
      !m_TextBox.IsVisible) 
     { 
      // Hide the Watermark Label if the adorner layer is visible 
      m_TextBox.ToolTip = GetLabel(m_TextBox); 
      m_TextBox.TryRemoveAdorners<TextBlockAdorner>(); 
     } 
     else 
     { 
      // Show the Watermark Label if the adorner layer is visible 
      m_TextBox.ToolTip = null; 
      m_TextBox.TryAddAdorner<TextBlockAdorner>(m_TextBlockAdorner); 
     } 
    } 
} 
स्मृति रिसाव में संपत्ति वर्णनकर्ता परिणाम निर्भरता के

उत्तर

16

AddValueChanged के रूप में आप पहले से ही पता है। इसलिए, जैसा कि here वर्णित है, आप किसी भी निर्भरता संपत्ति परिवर्तनों को सुनने के लिए कस्टम क्लास PropertyChangeNotifier बना सकते हैं।

पूर्ण कार्यान्वयन यहां पाया जा सकता है - PropertyDescriptor AddValueChanged Alternative। लिंक से


उद्धरण:

इस वर्ग के तथ्य यह है कि बाइंडिंग कमजोर संदर्भ उपयोग करती हैं इसलिए वर्ग वस्तु जो संपत्ति में परिवर्तन देख रहा है जड़ नहीं होंगे संघों का प्रबंधन करने का लाभ लेता है। यह WeakReference का उपयोग उस ऑब्जेक्ट के संदर्भ को बनाए रखने के लिए करता है जिसकी संपत्ति उस ऑब्जेक्ट को रूट किए बिना देख रही है। इस तरह, आप इन ऑब्जेक्ट्स का संग्रह बनाए रख सकते हैं ताकि आप उस ऑब्जेक्ट को पर रूट करने वाले संग्रह के बारे में चिंता किए बिना संपत्ति को अनदेखा कर सकें जिनके मूल्य आप देख रहे हैं।

इसके अलावा उत्तर की पूर्णता के लिए मैं भविष्य में किसी भी सड़कों के मुद्दे से बचने के लिए यहां पूरा कोड पोस्ट कर रहा हूं।

public sealed class PropertyChangeNotifier : DependencyObject, IDisposable 
{ 
    #region Member Variables 

    private readonly WeakReference _propertySource; 

    #endregion // Member Variables 

    #region Constructor 
    public PropertyChangeNotifier(DependencyObject propertySource, string path) 
     : this(propertySource, new PropertyPath(path)) 
    { 
    } 
    public PropertyChangeNotifier(DependencyObject propertySource, DependencyProperty property) 
     : this(propertySource, new PropertyPath(property)) 
    { 
    } 
    public PropertyChangeNotifier(DependencyObject propertySource, PropertyPath property) 
    { 
     if (null == propertySource) 
      throw new ArgumentNullException("propertySource"); 
     if (null == property) 
      throw new ArgumentNullException("property"); 
     _propertySource = new WeakReference(propertySource); 
     Binding binding = new Binding 
     { 
      Path = property, 
      Mode = BindingMode.OneWay, 
      Source = propertySource 
     }; 
     BindingOperations.SetBinding(this, ValueProperty, binding); 
    } 
    #endregion // Constructor 

    #region PropertySource 
    public DependencyObject PropertySource 
    { 
     get 
     { 
      try 
      { 
       // note, it is possible that accessing the target property 
       // will result in an exception so i’ve wrapped this check 
       // in a try catch 
       return _propertySource.IsAlive 
       ? _propertySource.Target as DependencyObject 
       : null; 
      } 
      catch 
      { 
       return null; 
      } 
     } 
    } 
    #endregion // PropertySource 

    #region Value 
    /// <summary> 
    /// Identifies the <see cref="Value"/> dependency property 
    /// </summary> 
    public static readonly DependencyProperty ValueProperty = DependencyProperty.Register("Value", 
    typeof(object), typeof(PropertyChangeNotifier), new FrameworkPropertyMetadata(null, OnPropertyChanged)); 

    private static void OnPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
    { 
     PropertyChangeNotifier notifier = (PropertyChangeNotifier)d; 
     if (null != notifier.ValueChanged) 
      notifier.ValueChanged(notifier, EventArgs.Empty); 
    } 

    /// <summary> 
    /// Returns/sets the value of the property 
    /// </summary> 
    /// <seealso cref="ValueProperty"/> 
    [Description("Returns/sets the value of the property")] 
    [Category("Behavior")] 
    [Bindable(true)] 
    public object Value 
    { 
     get 
     { 
      return GetValue(ValueProperty); 
     } 
     set 
     { 
      SetValue(ValueProperty, value); 
     } 
    } 
    #endregion //Value 

    #region Events 
    public event EventHandler ValueChanged; 
    #endregion // Events 

    #region IDisposable Members 

    public void Dispose() 
    { 
     BindingOperations.ClearBinding(this, ValueProperty); 
    } 

    #endregion 
} 
+1

सहायता के लिए धन्यवाद। मुझे नहीं पता कि मैं इस संसाधन को कैसे चूक गया! – scuba88

+0

यह समाधान मेरे लिए काम नहीं करता प्रतीत होता है, मुझे प्रॉपर्टी चेंज नॉटिफायर से ऑनप्रॉपर्टी चेंज किया गया ईवेंट नहीं मिल रहा है –

4

FrameworkElements और FrameworkContentElements के लिए एक अधिक हल्के समाधान Unloaded घटना की सदस्यता और प्रबंधक को निकाल रहा है। इसके लिए एक गैर-अज्ञात प्रतिनिधि (UpdateAdorner उस मामले में) की आवश्यकता है हालांकि:

focusProp.AddValueChanged(m_TextBox, UpdateAdorner); 
m_TextBox.Unloaded += (sender, args) => focusProp.RemoveValueChanged(sender, UpdateAdorner); 
संबंधित मुद्दे

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