если вы работали над некоторыми более крупными wpf-приложениями, вы, возможно, знакомы с this .Поскольку ResourceDictionaries всегда создаются, каждый раз, когда они находятся в XAML, мы можем в конечном итоге иметь один словарь ресурсов несколько раз в памяти.Таким образом, вышеупомянутое решение кажется очень хорошей альтернативой.Фактически для нашего текущего проекта этот трюк многое сделал ... Потребление памяти от 800 Мб до 44 Мб, что очень сильно сказывается.К сожалению, это решение стоит денег, которые я хотел бы показать здесь, и, надеюсь, найти способ избежать этого, все еще используя SharedResourceDictionary
.
Я сделал небольшой пример для визуализации проблемы с общимсловарь ресурсов.
Просто создайте простое приложение WPF.Добавьте один ресурс Xaml
Shared.xaml
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<SolidColorBrush x:Key="myBrush" Color="Yellow"/>
</ResourceDictionary>
Теперь добавьте UserControl.Кодовое обозначение задано по умолчанию, поэтому я просто показываю xaml
MyUserControl.xaml
<UserControl x:Class="Leak.MyUserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:SharedResourceDictionary="clr-namespace:Articy.SharedResourceDictionary" Height="128" Width="128">
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/Leak;component/Shared.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
<Grid>
<Rectangle Fill="{StaticResource myBrush}"/>
</Grid>
</UserControl>
Код окна выглядит примерно так
Window1.xaml.cs
// [ ... ]
public Window1()
{
InitializeComponent();
myTabs.ItemsSource = mItems;
}
private ObservableCollection<string> mItems = new ObservableCollection<string>();
private void OnAdd(object aSender, RoutedEventArgs aE)
{
mItems.Add("Test");
}
private void OnRemove(object aSender, RoutedEventArgs aE)
{
mItems.RemoveAt(mItems.Count - 1);
}
И окно xaml вот так
Window1.xaml
<Window.Resources>
<DataTemplate x:Key="myTemplate" DataType="{x:Type System:String}">
<Leak:MyUserControl/>
</DataTemplate>
</Window.Resources>
<Grid>
<DockPanel>
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal">
<Button Content="Add" Click="OnAdd"/>
<Button Content="Remove" Click="OnRemove"/>
</StackPanel>
<TabControl x:Name="myTabs" ContentTemplate="{StaticResource myTemplate}">
</TabControl>
</DockPanel>
</Grid>
</Window>
Я знаю, что программа не идеальна, и, вероятно, ее можно было бы упростить, но, придумывая способ показать проблему, я пришел к этому.В любом случае:
Запустите это, и вы проверите потребление памяти, если у вас есть профилировщик памяти, это становится намного проще.Добавьте (с показом, нажав на вкладку) и удалите страницу, и вы увидите, что все работает отлично.Ничего не подтекает.Теперь в разделе UserControl.Resources
используйте SharedResourceDictionary
вместо ResourceDictionary
, чтобы включить Shared.xaml .Вы увидите, что MyUserControl
будет храниться в памяти после удаления страницы, а MyUserControl
в ней.
Я полагал, что это происходит со всем, что создается с помощью XAML, такими как преобразователи, пользовательские элементы управления и т. Д.Странно, что это не произойдет с пользовательскими элементами управления.Я предполагаю, что на самом деле ничего не создается в пользовательских элементах управления, шаблонах данных и т. Д.В нашем случае использование SharedResourceDictionary является обязательным, но утечка памяти делает невозможным его продуктивное использование.Утечки можно избежать, используя CustomControls вместо UserControls, что не всегда практически.Так почему же на UserControls сильно ссылается ResourceDictionary?Я удивляюсь, почему никто не сталкивался с этим раньше, как я сказал в старом вопросе, кажется, что мы используем словари ресурсов и XAML абсолютно неправильно, в противном случае я удивляюсь, почему они так неэффективны.
Я надеюсь, что кто-то может пролить светпо этому вопросу.
Заранее спасибо Нико