Рассмотрим WPF UserControl
, который определяет следующие ресурсы:
<UserControl.Resources >
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source = "LeftHeaderDataTemplates.xaml"/>
<ResourceDictionary Source = "RightHeaderDataTemplates.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
Будут ли объединенные ресурсы анализироваться для каждого экземпляра пользовательского элемента управления? Временная шкала приложения в профилировщике производительности, похоже, указывает на это, но я не уверен, правильно ли я читаю результаты.
РЕДАКТИРОВАТЬ
Как указано в ответе @Andy: да, ResourceDictionary анализируется каждый раз, и создается новый экземпляр. В комментариях ниже он упомянул, что есть «лучший способ» для ссылки на конвертеры, а именно позволить им реализовать MarkupExtension
, как показано в предоставленной им ссылке.
Это подняло вопрос о том, сколько экземпляров преобразователя создается в зависимости от того, каким образом на них ссылаются/реализуют. Я подумал, что добавлю сюда свои выводы, потому что нашел их актуальными в контексте моего первоначального вопроса.
Рассмотрим UserControl, который отображается 4 раза:
<UserControl>
<UserControl.Resources>
<converters1:TestConverter3 x:Key = "TestConverter3"/>
</UserControl.Resources>
<StackPanel Background = "Black">
<TextBlock Foreground = "White" Text = "{Binding Converter = {StaticResource TestConverter1}}"></TextBlock>
<TextBlock Foreground = "White" Text = "{Binding Converter = {StaticResource TestConverter1}}"></TextBlock>
<TextBlock Foreground = "White" Text = "{Binding Converter = {converters1:TestConverter2}}"></TextBlock>
<TextBlock Foreground = "White" Text = "{Binding Converter = {converters1:TestConverter2}}"></TextBlock>
<TextBlock Foreground = "White" Text = "{Binding Converter = {StaticResource TestConverter3}}"></TextBlock>
<TextBlock Foreground = "White" Text = "{Binding Converter = {StaticResource TestConverter3}}"></TextBlock>
</StackPanel>
</UserControl>
Кроме того, TestConverter1
определяется как глобальный/общий/статический ресурс в App.xaml, а TestConverter2
реализуется путем наследования MarkupExtension
.
Всего существует 3 разных преобразователя, каждый из которых используется дважды 4 экземплярами UserControl.
Это создало следующий вывод консоли (с добавленными пустыми строками):
CREATING: TestConverter1 {HashCode: 51949120}
CREATING: TestConverter2 {HashCode: 27832883}
CREATING: TestConverter2 {HashCode: 8329199}
CREATING: TestConverter3 {HashCode: 48129282}
CREATING: TestConverter2 {HashCode: 12052844}
CREATING: TestConverter2 {HashCode: 24470370}
CREATING: TestConverter3 {HashCode: 24336447}
CREATING: TestConverter2 {HashCode: 22270914}
CREATING: TestConverter2 {HashCode: 23473221}
CREATING: TestConverter3 {HashCode: 11043085}
CREATING: TestConverter2 {HashCode: 50932452}
CREATING: TestConverter2 {HashCode: 32788649}
CREATING: TestConverter3 {HashCode: 49189852}
Convert : TestConverter1 {HashCode: 51949120}
Convert : TestConverter1 {HashCode: 51949120}
Convert : TestConverter2 {HashCode: 27832883}
Convert : TestConverter2 {HashCode: 8329199}
Convert : TestConverter3 {HashCode: 48129282}
Convert : TestConverter3 {HashCode: 48129282}
Convert : TestConverter1 {HashCode: 51949120}
Convert : TestConverter1 {HashCode: 51949120}
Convert : TestConverter2 {HashCode: 12052844}
Convert : TestConverter2 {HashCode: 24470370}
Convert : TestConverter3 {HashCode: 24336447}
Convert : TestConverter3 {HashCode: 24336447}
Convert : TestConverter1 {HashCode: 51949120}
Convert : TestConverter1 {HashCode: 51949120}
Convert : TestConverter2 {HashCode: 22270914}
Convert : TestConverter2 {HashCode: 23473221}
Convert : TestConverter3 {HashCode: 11043085}
Convert : TestConverter3 {HashCode: 11043085}
Convert : TestConverter1 {HashCode: 51949120}
Convert : TestConverter1 {HashCode: 51949120}
Convert : TestConverter2 {HashCode: 50932452}
Convert : TestConverter2 {HashCode: 32788649}
Convert : TestConverter3 {HashCode: 49189852}
Convert : TestConverter3 {HashCode: 49189852}
Полученные результаты:
Конечно, преобразователи должны быть легкими, поэтому это часто не будет проблемой (относительно памяти или сборки мусора), но я, тем не менее, подумал, что стоит понаблюдать, особенно если вы выберете действительно очень гладкий синтаксис MarkupExtension.
@EldHasp: спасибо! если бы вы написали как ответ, я бы принял это как единственный; о)
Не разбирать каждый раз. В памяти есть экземпляр для каждого пользовательского элемента управления. Так что будьте осторожны с большими ресурсами, если у вас будет много экземпляров.
@Энди: да, теперь я вижу, это также относится ко всем ресурсам, например если ресурс является Converter
, новый экземпляр будет создан для каждого UserControl
.
Истинный. Но есть лучший способ сделать преобразователи.
@Энди: ты дразнишь ;о) не мог бы ты уточнить?
drwpf.com/blog/2009/03/17/…
@Andy: я изучил подход MarkupExtension, и у меня не было времени, чтобы изолировать и протестировать проблему, но на первый взгляд отладчик показывает, что в отношении создания экземпляра/мусора новый экземпляр создается каждый раз, когда ссылаются на конвертер, то есть даже больше раз, чем в разметке моего поста (где для каждого определения создается новый экземпляр).
Статика означает синглтон.
@Andy: Да, конечно, static=singleton, но метод ProvideValue
является методом экземпляра, его необходимо вызывать для фактического экземпляра (предположительно созданного WPF с использованием отражения), который затем возвращает общий/статический/одиночный экземпляр - вместо только себя.
Да - будет.
И даже больше. Если вы установите DynamicResource, это будет работать аналогично привязке. При изменении ресурса, замене словаря, изменении уровня ресурса - значение DynamicResource будет оцениваться заново.
Да, это будет. И даже больше. Если вы установите DynamicResource, это будет работать аналогично привязке. При изменении ресурса, замене словаря, изменении уровня ресурса - значение DynamicResource будет оцениваться заново.