Wpf 使用MultiDataTrigger设置ContentPresenter会产生内存泄漏
我有一个列表框,其中项目的ContentPresenter由MultiDataTrigger更改,具体取决于某些IsTool和IsAlerting布尔属性:Wpf 使用MultiDataTrigger设置ContentPresenter会产生内存泄漏,wpf,Wpf,我有一个列表框,其中项目的ContentPresenter由MultiDataTrigger更改,具体取决于某些IsTool和IsAlerting布尔属性: <Grid> <Grid.Resources> <DataTemplate x:Key="LayerTemplate"> <ContentControl x:Name="contentControl" Style="{DynamicResource P
<Grid>
<Grid.Resources>
<DataTemplate x:Key="LayerTemplate">
<ContentControl x:Name="contentControl" Style="{DynamicResource PageHeaderContentControlStyle}">
<layers:PageHeader/>
</ContentControl>
</DataTemplate>
<DataTemplate x:Key="ToolTemplate">
<ContentControl x:Name="contentControl" Style="{DynamicResource ToolHeaderContentControlStyle}">
<layers:ToolHeader/>
</ContentControl>
</DataTemplate>
<DataTemplate x:Key="LayerAlertTemplate">
<ContentControl x:Name="contentControl" Style="{DynamicResource PageHeaderAlertContentControlStyle}">
<layers:PageHeader/>
</ContentControl>
</DataTemplate>
<DataTemplate x:Key="ToolAlertTemplate">
<ContentControl x:Name="contentControl" Style="{DynamicResource ToolHeaderAlertContentControlStyle}">
<layers:ToolHeader/>
</ContentControl>
</DataTemplate>
<Style TargetType="{x:Type ListBoxItem}" x:Key="EmptyListViewSelection">
<Setter Property="Background" Value="Transparent" />
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<Border BorderBrush="Transparent"
BorderThickness="0"
Background="{TemplateBinding Background}"
Margin="2"
FocusVisualStyle="{x:Null}">
<ContentPresenter DataContext="{Binding}" Name="contentPresenter"/>
</Border>
<ControlTemplate.Triggers>
<DataTrigger Binding="{Binding IsTool}" Value="False">
<Setter TargetName="contentPresenter" Property="ContentTemplate" Value="{StaticResource LayerTemplate}"/>
</DataTrigger>
<DataTrigger Binding="{Binding IsTool}" Value="True">
<Setter TargetName="contentPresenter" Property="ContentTemplate" Value="{StaticResource ToolTemplate}"/>
</DataTrigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding IsTool}" Value="False"/>
<Condition Binding="{Binding IsAlerting}" Value="True"/>
</MultiDataTrigger.Conditions>
<MultiDataTrigger.Setters>
<Setter TargetName="contentPresenter" Property="ContentTemplate" Value="{StaticResource LayerAlertTemplate}"/>
</MultiDataTrigger.Setters>
</MultiDataTrigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding IsTool}" Value="True"/>
<Condition Binding="{Binding IsAlerting}" Value="True"/>
</MultiDataTrigger.Conditions>
<MultiDataTrigger.Setters>
<Setter TargetName="contentPresenter" Property="ContentTemplate" Value="{StaticResource ToolAlertTemplate}"/>
</MultiDataTrigger.Setters>
</MultiDataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Grid.Resources>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<ListBox Name="listView"
BorderThickness="0"
ItemsSource="{Binding Pages}"
SelectedValue="{Binding SelectedPage}"
ScrollViewer.HorizontalScrollBarVisibility="Hidden"
ScrollViewer.VerticalScrollBarVisibility="Hidden"
ItemContainerStyle="{StaticResource EmptyListViewSelection}"
IsTabStop="False"
FocusVisualStyle="{x:Null}"
Focusable="False" Background="{x:Null}">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal" MaxWidth="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListBox}}, Path=ActualWidth}" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>
<GroupBox Name="pageBox" IsEnabled="{Binding Visible}" Grid.Row="1" DataContext="{Binding Path=SelectedValue, ElementName=listView}">
<GroupBox.Header>
<Label Content="{Binding Name}" Padding="0"/>
</GroupBox.Header>
<ContentControl Content="{Binding}"/>
</GroupBox>
</Grid>
如果IsAlerting属性更改通知(通过INotifyPropertyChange)大约每秒触发一次,则我的应用程序的内存使用量将从230MB增加到804MB,持续15分钟,并且应用程序最终会因以下调用堆栈而崩溃:
Exception Info: System.Reflection.TargetInvocationException
Stack:
at System.Windows.FrameworkTemplate.LoadTemplateXaml(System.Xaml.XamlReader, System.Xaml.XamlObjectWriter)
at System.Windows.FrameworkTemplate.LoadTemplateXaml(System.Xaml.XamlObjectWriter)
at System.Windows.FrameworkTemplate.LoadOptimizedTemplateContent(System.Windows.DependencyObject, System.Windows.Markup.IComponentConnector, System.Windows.Markup.IStyleConnector, System.Collections.Generic.List`1<System.Windows.DependencyObject>, System.Windows.UncommonField`1<System.Collections.Hashtable>)
at System.Windows.FrameworkTemplate.LoadContent(System.Windows.DependencyObject, System.Collections.Generic.List`1<System.Windows.DependencyObject>)
at System.Windows.StyleHelper.ApplyTemplateContent(System.Windows.UncommonField`1<System.Collections.Specialized.HybridDictionary[]>, System.Windows.DependencyObject, System.Windows.FrameworkElementFactory, Int32, System.Collections.Specialized.HybridDictionary, System.Windows.FrameworkTemplate)
at System.Windows.FrameworkTemplate.ApplyTemplateContent(System.Windows.UncommonField`1<System.Collections.Specialized.HybridDictionary[]>, System.Windows.FrameworkElement)
at System.Windows.FrameworkElement.ApplyTemplate()
at System.Windows.FrameworkElement.MeasureCore(System.Windows.Size)
at System.Windows.UIElement.Measure(System.Windows.Size)
at System.Windows.ContextLayoutManager.UpdateLayout()
at System.Windows.ContextLayoutManager.UpdateLayoutCallback(System.Object)
at System.Windows.Media.MediaContext+InvokeOnRenderCallback.DoWork()
at System.Windows.Media.MediaContext.FireInvokeOnRenderCallbacks()
at System.Windows.Media.MediaContext.RenderMessageHandlerCore(System.Object)
at System.Windows.Media.MediaContext.RenderMessageHandler(System.Object)
at System.Windows.Threading.ExceptionWrapper.InternalRealCall(System.Delegate, System.Object, Int32)
.............
异常信息:System.Reflection.TargetInvocationException
堆栈:
位于System.Windows.FrameworkTemplate.LoadTemplateXaml(System.Xaml.XamlReader、System.Xaml.XamlObjectWriter)
位于System.Windows.FrameworkTemplate.LoadTemplateXaml(System.Xaml.XamlObjectWriter)
位于System.Windows.FrameworkTemplate.LoadOptimizedTemplateContent(System.Windows.DependencyObject、System.Windows.Markup.IComponentConnector、System.Windows.Markup.IStyleConnector、System.Collections.Generic.List`1、System.Windows.Unmonfield`1)
位于System.Windows.FrameworkTemplate.LoadContent(System.Windows.DependencyObject、System.Collections.Generic.List`1)
位于System.Windows.StyleHelper.ApplyTemplateContent(System.Windows.Unmonfield`1,System.Windows.DependencyObject,System.Windows.FrameworkElementFactory,Int32,System.Collections.Specialized.HybridDictionary,System.Windows.FrameworkTemplate)
位于System.Windows.FrameworkTemplate.ApplyTemplateContent(System.Windows.UncommonField`1,System.Windows.FrameworkElement)
在System.Windows.FrameworkElement.ApplyTemplate()中
位于System.Windows.FrameworkElement.MeasureCore(System.Windows.Size)
在System.Windows.UIElement.Measure处(System.Windows.Size)
位于System.Windows.ContextLayoutManager.UpdateLayout()处
位于System.Windows.ContextLayoutManager.UpdateLayoutCallback(System.Object)
在System.Windows.Media.MediaContext+InvokeRenderCallback.DoWork()中
在System.Windows.Media.MediaContext.FireInvokeOnRenderCallbacks()中
位于System.Windows.Media.MediaContext.RenderMessageHandlerCore(System.Object)
位于System.Windows.Media.MediaContext.RenderMessageHandler(System.Object)
位于System.Windows.Threading.ExceptionWrapper.InternalRealCall(System.Delegate、System.Object、Int32)
.............
有什么想法吗?不确定内存泄漏,但我不会像这样更改contenttemplate。如果在ContentPresenter上设置ContentTemplate,ContentPresenter的ContentSource属性(默认为“Content”)将被否决/忽略,Content属性将为空,并且ContentTemplate不再具有datacontext 最好在样式设置器中设置ContentTemplate,并使用样式触发器对其进行更改。ContentPresenter的默认ContentSource将执行其余操作
我怀疑这可能会解决您的内存泄漏问题。您的内存泄漏可能是由中描述的情况造成的,可能是列表框中的虚拟化加剧了这种情况(或者如果您有很多项,并且它正在一次分配它们,则可能缺少这些项)。事实上,您有一个System.Reflection.TargetInvocationException,这让我觉得您绑定的不是INotifyPropertyChanged,它必须使用反射来确定值是否在更改
在较新版本的Visual Studio(2013,可能2012)中,有一个内存探查器,可以显示哪些对象正在泄漏,这可能有助于缩小搜索范围。出于某种原因,将MultiDataTrigger移动到单独的样式解决了问题(不再存在内存泄漏):
....
<Style TargetType="{x:Type ContentControl}" x:Key="PageToolHeaderContentControlThemeStyle">
<Setter Property="Foreground" Value="{StaticResource ForegroundBrush}"/>
<Setter Property="Padding" Value="5,3"/>
....
<ControlTemplate.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding Alert}" Value="Warning"/>
<Condition Binding="{Binding IsAcknowledged}" Value="True"/>
</MultiDataTrigger.Conditions>
<MultiDataTrigger.Setters>
<Setter TargetName="PART_BorderAlarmFrame" Property="Stroke" Value="Orange"/>
<Setter TargetName="PART_BorderAlarmFrame" Property="Visibility" Value="Visible"/>
</MultiDataTrigger.Setters>
</MultiDataTrigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding Alert}" Value="Warning"/>
<Condition Binding="{Binding IsAcknowledged}" Value="False"/>
</MultiDataTrigger.Conditions>
<MultiDataTrigger.Setters>
<Setter TargetName="PART_BorderAlarmFrame" Property="Visibility" Value="Visible"/>
</MultiDataTrigger.Setters>
<MultiDataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation Storyboard.TargetName="BackgroundBrush"
Storyboard.TargetProperty="Color"
From="Transparent" To="Orange" Duration="0:0:0.5"
AutoReverse="True"
RepeatBehavior="Forever" />
</Storyboard>
</BeginStoryboard>
</MultiDataTrigger.EnterActions>
</MultiDataTrigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding Alert}" Value="Alarm"/>
<Condition Binding="{Binding IsAcknowledged}" Value="True"/>
</MultiDataTrigger.Conditions>
<MultiDataTrigger.Setters>
<Setter TargetName="PART_BorderAlarmFrame" Property="Stroke" Value="Red"/>
<Setter TargetName="PART_BorderAlarmFrame" Property="Visibility" Value="Visible"/>
</MultiDataTrigger.Setters>
</MultiDataTrigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding Alert}" Value="Alarm"/>
<Condition Binding="{Binding IsAcknowledged}" Value="False"/>
</MultiDataTrigger.Conditions>
<MultiDataTrigger.Setters>
<Setter TargetName="PART_BorderAlarmFrame" Property="Visibility" Value="Visible"/>
</MultiDataTrigger.Setters>
<MultiDataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation Storyboard.TargetName="BackgroundBrush"
Storyboard.TargetProperty="Color"
From="Transparent" To="Red" Duration="0:0:0.5"
AutoReverse="True"
RepeatBehavior="Forever" />
</Storyboard>
</BeginStoryboard>
</MultiDataTrigger.EnterActions>
</MultiDataTrigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Foreground" Value="{DynamicResource LightForegroundBrush}"/>
<Setter TargetName="PART_BorderDefaultFrame" Property="Stroke" Value="{StaticResource ButtonPressedBackgroundBrush}"/>
<Setter TargetName="PART_Border" Property="Background" Value="{StaticResource ButtonHoverBackgroundBrush}"/>
</Trigger>
<DataTrigger Binding="{Binding IsSelected}" Value="True">
<Setter Property="Foreground" Value="{DynamicResource LightForegroundBrush}"/>
<Setter TargetName="PART_BorderDefaultFrame" Property="Stroke" Value="{StaticResource ButtonPressedBackgroundBrush}"/>
<Setter TargetName="PART_Border" Property="Background" Value="{StaticResource ButtonPressedBackgroundBrush}"/>
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>