Bindable richTextBox все еще висит в памяти {WPF, Caliburn.Micro} - PullRequest
0 голосов
/ 08 января 2011

Я использую в WFP Caliburn.Micro Framework.Мне нужно привязываемый richTextbox для свойства документа.Я нашел много способов, как это связывает richTextBox.

Но у меня есть одна проблема.Из родительского окна открываю дочернее окно.Дочернее окно состоит из привязываемого пользовательского элемента управления richTextBox.

После того, как я закрываю дочернее окно и использую класс представления профилировщика памяти с элементом управления bindabelrichTextBox и класс модели представления все еще висит в памяти.-> это вызывает утечку памяти.

Если я использую richTextBox из .NET Framework или richTextBox из Extended WPF Toolkit, это не вызывает эту проблему утечки памяти.

Я не могу определить проблему вbindable richTextBox class.

Вот класс ist для bindable richTextBox:

Базовый класс может быть из .NET или расширенного инструментария.

  /// <summary>
    /// Represents a bindable rich editing control which operates on System.Windows.Documents.FlowDocument
    /// objects.    
    /// </summary>
    public class BindableRichTextBox : RichTextBox
    {

        /// <summary>
        /// Identifies the <see cref="Document"/> dependency property.
        /// </summary>
        public static readonly DependencyProperty DocumentProperty = DependencyProperty.Register("Document",
            typeof(FlowDocument), typeof(BindableRichTextBox));

        /// <summary>
        /// Initializes a new instance of the <see cref="BindableRichTextBox"/> class.
        /// </summary>
        public BindableRichTextBox()
            : base()
        {
        }


        /// <summary>
        /// Initializes a new instance of the <see cref="BindableRichTextBox"/> class.
        /// </summary>
        /// <param title="document">A <see cref="T:System.Windows.Documents.FlowDocument"></see> to be added as the initial contents of the new <see cref="T:System.Windows.Controls.BindableRichTextBox"></see>.</param>
        public BindableRichTextBox(FlowDocument document)
            : base(document)
        {
        }

        /// <summary>
        /// Raises the <see cref="E:System.Windows.FrameworkElement.Initialized"></see> event. This method is invoked whenever <see cref="P:System.Windows.FrameworkElement.IsInitialized"></see> is set to true internally.
        /// </summary>
        /// <param title="e">The <see cref="T:System.Windows.RoutedEventArgs"></see> that contains the event data.</param>
        protected override void OnInitialized(EventArgs e)
        {
            // Hook up to get notified when DocumentProperty changes.
            DependencyPropertyDescriptor descriptor = DependencyPropertyDescriptor.FromProperty(DocumentProperty, typeof(BindableRichTextBox));
            descriptor.AddValueChanged(this, delegate
            {
                // If the underlying value of the dependency property changes,
                // update the underlying document, also.
                base.Document = (FlowDocument)GetValue(DocumentProperty);

            });

            // By default, we support updates to the source when focus is lost (or, if the LostFocus
            // trigger is specified explicity.  We don't support the PropertyChanged trigger right now.
            this.LostFocus += new RoutedEventHandler(BindableRichTextBox_LostFocus);

            base.OnInitialized(e);

        }

        /// <summary>
        /// Handles the LostFocus event of the BindableRichTextBox control.
        /// </summary>
        /// <param title="sender">The source of the event.</param>
        /// <param title="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
        void BindableRichTextBox_LostFocus(object sender, RoutedEventArgs e)
        {

            // If we have a binding that is set for LostFocus or Default (which we are specifying as default)
            // then update the source.
            Binding binding = BindingOperations.GetBinding(this, DocumentProperty);
            if (binding.UpdateSourceTrigger == UpdateSourceTrigger.Default ||
                binding.UpdateSourceTrigger == UpdateSourceTrigger.LostFocus)
            {
                BindingOperations.GetBindingExpression(this, DocumentProperty).UpdateSource();
            }

        }

        /// <summary>
        /// Gets or sets the <see cref="T:System.Windows.Documents.FlowDocument"></see> that represents the contents of the <see cref="T:System.Windows.Controls.BindableRichTextBox"></see>.
        /// </summary>
        /// <value></value>
        /// <returns>A <see cref="T:System.Windows.Documents.FlowDocument"></see> object that represents the contents of the <see cref="T:System.Windows.Controls.BindableRichTextBox"></see>.By default, this property is set to an empty <see cref="T:System.Windows.Documents.FlowDocument"></see>.  Specifically, the empty <see cref="T:System.Windows.Documents.FlowDocument"></see> contains a single <see cref="T:System.Windows.Documents.Paragraph"></see>, which contains a single <see cref="T:System.Windows.Documents.Run"></see> which contains no text.</returns>
        /// <exception cref="T:System.ArgumentException">Raised if an attempt is made to set this property to a <see cref="T:System.Windows.Documents.FlowDocument"></see> that represents the contents of another <see cref="T:System.Windows.Controls.RichTextBox"></see>.</exception>
        /// <exception cref="T:System.ArgumentNullException">Raised if an attempt is made to set this property to null.</exception>
        /// <exception cref="T:System.InvalidOperationException">Raised if this property is set while a change block has been activated.</exception>
        public new FlowDocument Document
        {
            get { return (FlowDocument)GetValue(DocumentProperty); }
            set { SetValue(DocumentProperty, value); }
        }

    }

Спасибо за помощь и совет.

Пример Qucik:

Дочернее окно с .NET richTextBox

<Window x:Class="WpfApplication2.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Window1" Height="300" Width="300">
    <Grid>
        <RichTextBox                        Background="Green"
                                            VerticalScrollBarVisibility="Auto" 
                                            HorizontalScrollBarVisibility="Auto"
                                            FontSize="13"
                                            Margin="4,4,4,4" 
                                            Grid.Row="0"/>
    </Grid>
</Window>

Это окно, открываемое из родительского окна:

        var w = new Window1();
        w.Show();

Затем закройте это окно, проверьте с помощью профилировщика памяти, и в памяти нет объекта window1 - richTextBox.Это нормально.

Но затем я пытаюсь привязать richTextBox:

Дочернее окно 2:

<Window x:Class="WpfApplication2.Window2"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
        xmlns:Controls="clr-namespace:WpfApplication2.Controls" 
        Title="Window2" Height="300" Width="300">
    <Grid>
        <Controls:BindableRichTextBox       Background="Red"
                                            VerticalScrollBarVisibility="Auto" 
                                            HorizontalScrollBarVisibility="Auto"
                                            FontSize="13"
                                            Margin="4,4,4,4" 
                                            Grid.Row="0" />
    </Grid>
</Window>

Открыть дочернее окно 2, закрыть это дочернее окнои в памяти все еще жив объект этого дочернего окна, также привязываемый объект richTextBox.

Ответы [ 2 ]

1 голос
/ 08 января 2011

Я подозреваю, что, поскольку экземпляры DependencyPropertyDescriptor могут кэшироваться на уровне приложения, ссылки на делегат ValueChanged (анонимный делегат в методе OnInitialized) могут пропускать экземпляры BindableRichTextBox.

В показанном коде, действительно, нет вызова DependencyPropertyDescriptor.RemoveValueChanged для удаления обработчика.

Вы могли бы рассмотреть возможность использования перегрузки DependencyProperty.Register, которая поддерживает параметр PropertyMetadata;это позволяет вам указать правильный PropertyChangedCallback для свойства (см. http://msdn.microsoft.com/en-us/library/cc903933(v=VS.95).aspx#metadata):

public static readonly DependencyProperty DocumentProperty = 
  DependencyProperty.Register("Document", 
    typeof(FlowDocument), typeof(BindableRichTextBox),
    new PropertyMetadata(null,       
      new PropertyChangedCallback(OnDocumentChanged)
    )
  );

public static void OnDocumentChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
  ((BindableRichTextBox)d).SetBaseDocument((FlowDocument)e.NewValue);
}

public new FlowDocument Document
{
  get { return (FlowDocument)GetValue(DocumentProperty); }
  set { SetValue(DocumentProperty, value); }
}

private SetBaseDocument(FlowDocument document) {
  base.Document = (FlowDocument)GetValue(DocumentProperty);
}
0 голосов
/ 08 января 2011

Возможно, лучше создать пользовательский элемент управления с помощью richTextBox. Richtextbox wpf переплет

...