WPF中不指定控件名称...性能影响

问题描述 投票:0回答:2

如果需要从后面的代码访问 WPF 控件,则需要在 XAML 中为其提供

Name
属性。

在许多情况下,您不需要从后面的代码访问控件,因为许多编码逻辑(例如绑定)最好直接在 XAML 中应用。

我的问题是:向控件提供 name 属性是否会带来性能提升?或者给页面上的所有控件命名是一个好习惯吗?

wpf performance xaml coding-style
2个回答
17
投票

是的,不提供“名称”属性肯定会带来性能提升。

WPF 的“名称”机制可能很有用,但它以多种方式使用额外的 RAM 和 CPU:

  1. XAML 编译器在类中为每个命名对象分配一个额外的槽(每个命名对象 4 个字节)
  2. XAML 编译器将代码添加到您的类中以启动其中的每一个
  3. BAML 处理器回调您的代码以初始化每种情况下的名称
  4. BAML 处理器还将名称添加到字典中,每个名称需要额外 20+ 字节
  5. 当查找您真正需要的名称时,您可能会遇到与您并不真正需要的名称的字典冲突

对于一个简单的控件,为控件添加名称可以使该控件的使用成本增加 5% 左右。 这并不是很多,但为什么要把 CPU 周期和 RAM 浪费在不必要的名称上呢?

底线:如果您的对象不需要名称,请不要为它们命名。 通常,控件的内容或绑定足以识别控件的用途。 如果这还不够,您可以随时使用免费的 XML 注释。

我不得不说,为所有控件命名是一个非常“坏”的习惯,不仅是因为成本,还因为它鼓励您通过名称引用控件,而不是使用正确的视图模型和绑定技术。 我的大部分 XAML 都不使用“名称”来表示任何控件,更不用说所有控件了。


0
投票

在某些情况下,命名元素是不可避免的,但在很多情况下,您可以避免它。有几种方法可以做到这一点。我下面的例子简要介绍了这一点。

假设您有一个带有包含两行的网格的用户控件。第 0 行包含一个带有一些文本的 TextBlock,第 1 行包含一个椭圆。假设您想要为这两个元素设置动画,以便当用户将鼠标悬停在控件上时,文本和椭圆会以橙色突出显示。现在您需要为元素指定名称吗?在这种情况下,不。可以简单地使用绑定来实现效果,如下图:

<UserControl x:Class="test.Components.AnimatedTextEllipseControl" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Background="White"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="Auto" /> <RowDefinition Height="*" /> </Grid.RowDefinitions> <!-- TextBlock with Foreground bound to the UserControl's Foreground --> <TextBlock Text="Sample Text" Foreground="{Binding Foreground, RelativeSource={RelativeSource AncestorType=UserControl}}" HorizontalAlignment="Center" VerticalAlignment="Center" /> <!-- Ellipse with Fill bound to the UserControl's Foreground --> <Ellipse Grid.Row="1" Fill="{Binding Foreground, RelativeSource={RelativeSource AncestorType=UserControl}}" Width="50" Height="50" HorizontalAlignment="Center" VerticalAlignment="Center"/> </Grid> <UserControl.Triggers> <EventTrigger RoutedEvent="MouseEnter"> <BeginStoryboard> <Storyboard> <!-- Color animation from Blue to Orange --> <ColorAnimation Storyboard.TargetProperty="(UserControl.Foreground).(SolidColorBrush.Color)" To="Orange" Duration="0:0:0.3"/> </Storyboard> </BeginStoryboard> </EventTrigger> <EventTrigger RoutedEvent="MouseLeave"> <BeginStoryboard> <Storyboard> <!-- Color animation from Orange back to Blue --> <ColorAnimation Storyboard.TargetProperty="(UserControl.Foreground).(SolidColorBrush.Color)" To="Blue" Duration="0:0:0.3"/> </Storyboard> </BeginStoryboard> </EventTrigger> </UserControl.Triggers> </UserControl>

请注意,没有为元素分配任何名称,但由于绑定,动画仍然有效。

假设您现在想要在 MouseEnter 上对椭圆的大小进行动画处理。如果不告诉 Storyboard 要定位哪个元素,您将如何实现这一目标?此处的命名对于专门针对椭圆来说至关重要。以下是代码的更改方式:

<UserControl x:Class="test.Components.AnimatedTextEllipseControl" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Background="White"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="Auto" /> <RowDefinition Height="*" /> </Grid.RowDefinitions> <TextBlock Text="Sample Text" Foreground="{Binding Foreground, RelativeSource={RelativeSource AncestorType=UserControl}}" HorizontalAlignment="Center" VerticalAlignment="Center" /> <!-- Named Ellipse required for targeted size animations --> <Ellipse Name="EllipseElem" Grid.Row="1" Fill="{Binding Foreground, RelativeSource={RelativeSource AncestorType=UserControl}}" Width="50" Height="50" HorizontalAlignment="Center" VerticalAlignment="Center"/> </Grid> <UserControl.Triggers> <EventTrigger RoutedEvent="MouseEnter"> <BeginStoryboard> <Storyboard> <ColorAnimation Storyboard.TargetProperty="(UserControl.Foreground).(SolidColorBrush.Color)" <!-- Targeting the Ellipse using its name (EllipseElem) to increase its size on mouse enter --> To="Orange" Duration="0:0:0.3"/> <DoubleAnimation Storyboard.TargetName="EllipseElem" Storyboard.TargetProperty="Width" To="100" Duration="0:0:0.3"/> <DoubleAnimation Storyboard.TargetName="EllipseElem" Storyboard.TargetProperty="Height" To="100" Duration="0:0:0.3"/> </Storyboard> </BeginStoryboard> </EventTrigger> <EventTrigger RoutedEvent="MouseLeave"> <BeginStoryboard> <Storyboard> <ColorAnimation Storyboard.TargetProperty="(UserControl.Foreground).(SolidColorBrush.Color)" To="Blue" Duration="0:0:0.3"/> <!-- Targeting the Ellipse using its name (EllipseElem) to decrease its size on mouse enter --> <DoubleAnimation Storyboard.TargetName="EllipseElem" Storyboard.TargetProperty="Width" To="50" Duration="0:0:0.3"/> <DoubleAnimation Storyboard.TargetName="EllipseElem" Storyboard.TargetProperty="Height" To="50" Duration="0:0:0.3"/> </Storyboard> </BeginStoryboard> </EventTrigger> </UserControl.Triggers> </UserControl>

上面的例子重申,虽然命名元素有时是不可避免的(例如,有针对性的动画),但请避免过度命名。在我的示例中,只有椭圆需要动画定位的名称,而 TextBlock 不需要。正如 Ray 提到的,过度使用名称会增加内存使用量和复杂性,尤其是在大型应用程序中。上面的例子也旨在强调对语言及其特性的正确了解。

另请注意,由于 WPF 的限制,Name 属性本身无法进行动画处理。正如 FrameworkElement 文档中所述:

名称是极少数无法动画的依赖属性之一...因为名称对于定位动画至关重要。

© www.soinside.com 2019 - 2024. All rights reserved.