如果需要从后面的代码访问 WPF 控件,则需要在 XAML 中为其提供
Name
属性。
在许多情况下,您不需要从后面的代码访问控件,因为许多编码逻辑(例如绑定)最好直接在 XAML 中应用。
我的问题是:不向控件提供 name 属性是否会带来性能提升?或者给页面上的所有控件命名是一个好习惯吗?
是的,不提供“名称”属性肯定会带来性能提升。
WPF 的“名称”机制可能很有用,但它以多种方式使用额外的 RAM 和 CPU:
对于一个简单的控件,为控件添加名称可以使该控件的使用成本增加 5% 左右。 这并不是很多,但为什么要把 CPU 周期和 RAM 浪费在不必要的名称上呢?
底线:如果您的对象不需要名称,请不要为它们命名。 通常,控件的内容或绑定足以识别控件的用途。 如果这还不够,您可以随时使用免费的 XML 注释。
我不得不说,为所有控件命名是一个非常“坏”的习惯,不仅是因为成本,还因为它鼓励您通过名称引用控件,而不是使用正确的视图模型和绑定技术。 我的大部分 XAML 都不使用“名称”来表示任何控件,更不用说所有控件了。
在某些情况下,命名元素是不可避免的,但在很多情况下,您可以避免它。有几种方法可以做到这一点。我下面的例子简要介绍了这一点。
假设您有一个带有包含两行的网格的用户控件。第 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 文档中所述:
名称是极少数无法动画的依赖属性之一...因为名称对于定位动画至关重要。