可绑定的 richTextBox 仍挂在内存中 {WPF, Caliburn.Micro}
我在 WFP Caliburn.Micro 框架中使用。 我需要可绑定的 richTextbox 作为 Document 属性。我发现了很多方法如何绑定 richTextBox。
但我有一个问题。从父窗口我打开子窗口。子窗口包含可绑定的 richTextBox 用户控件。
在我关闭子窗口并使用内存探查器视图类和 bindabelrichTextBox 控件之后,视图模型类仍然挂在内存中。 ->这会导致内存泄漏。
如果我使用 .NET Framework 中的 richTextBox 或扩展 WPF 工具包中的 richTextBox,则不会导致此内存泄漏问题。
我无法识别可绑定 richTextBox 类中的问题。
以下是可绑定 richTextBox 的 ist 类:
基类可以来自 .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对象。
I use in WFP Caliburn.Micro Framework.
I need bindable richTextbox for Document property. I found many ways how do it bindable richTextBox.
But I have one problem. From parent window I open child window. Child window consist bindable richTextBox user control.
After I close child window and use memory profiler view class with bindabelrichTextBox control and view model class is still hanging in memory. -> this cause memory leaks.
If I use richTextBox from .NET Framework or richTextBox from Extended WPF Toolkit it doesn’t cause this memory leak problem.
I can’t identified problem in bindable richTextBox class.
Here is ist class for bindable richTextBox:
Base class can be from .NET or Extended toolkit.
/// <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); }
}
}
Thank fro help and advice.
Qucik example:
Child window with .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>
This window I open from parent window:
var w = new Window1();
w.Show();
Then close this window, check with memory profiler and it memory doesn’t exist any object of window1 - richTextBox. It’s Ok.
But then I try bindable richTextBox:
Child window 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>
Open child window 2, close this child window and in memory are still alive object of this child window also bindable richTextBox object.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我怀疑,由于
DependencyPropertyDescriptor
的实例可能会在应用程序级别缓存,因此对 ValueChanged 委托(OnInitialized
方法中的匿名委托)的引用可能会泄漏>BindableRichTextBox
。在显示的代码中,确实没有调用 DependencyPropertyDescriptor.RemoveValueChanged 来删除处理程序。
您可以考虑使用
DependencyProperty.Register
重载,它支持PropertyMetadata
参数;这允许您为属性指定正确的 PropertyChangedCallback (请参阅 http://msdn.microsoft.com/en-us/library/cc903933(v=VS.95).aspx#metadata):I suspect that since instances of
DependencyPropertyDescriptor
are likely to be cached at application level, the references to ValueChanged delegate (the anonymous delegate inOnInitialized
method) might leak instances of theBindableRichTextBox
.In the code shown there isn't, indeed, any call to
DependencyPropertyDescriptor.RemoveValueChanged
to remove the handler.You might consider using the
DependencyProperty.Register
overload, which supports aPropertyMetadata
parameter; this allows you to specify a proper PropertyChangedCallback for the property (see http://msdn.microsoft.com/en-us/library/cc903933(v=VS.95).aspx#metadata):也许使用 richTextBox 创建用户控件更好。
Richtextbox wpf 绑定
Maybe is better to create user control with richTextBox.
Richtextbox wpf binding