到目前为止,在本教程中,我们只使用了 WPF 框架中的内置控件。它们会让你走很长的路,因为它们非常灵活,可以进行样式和模板化,几乎可以做任何事情。但是,在某些时候,您可能会从创建自己的控件中受益。在其他 UI 框架中,这可能非常麻烦,但 WPF 使它变得非常简单,为您提供了两种完成此任务的方法:UserControls和自定义控件。
WPF UserControl 继承了 UserControl 类,其行为与 WPF 窗口非常相似:您有一个 XAML 文件和一个代码隐藏文件。在 XAML 文件中,您可以添加现有的 WPF 控件来创建您想要的外观,然后将其与代码隐藏文件中的代码结合起来,以实现您想要的功能。然后,WPF 将允许您在应用程序的一个或多个位置嵌入此功能集合,从而允许您轻松地在应用程序中分组和重用功能。
自定义控件
自定义控件比 UserControl 的级别更低。当您创建自定义控件时,您将从现有类继承,具体取决于您需要的深度。在许多情况下,您可以继承Control类,其他 WPF 控件从该类继承(例如 TextBox),但如果您需要更深入,您可以继承FrameworkElement甚至UIElement。你走得越深,你得到的控制就越多,继承的功能就越少。
自定义控件的外观通常通过主题文件中的样式进行控制,而用户控件的外观将遵循应用程序其余部分的外观。这也突出了 UserControl 和自定义控件之间的主要区别之一:自定义控件可以设置样式/模板,而 UserControl 不能。
创建和使用用户控件
在 WPF 中,由 UserControl 类表示的用户控件是将标记和代码分组到一个可重用容器中的概念,以便具有相同功能的相同界面可以在多个不同位置甚至跨多个应用程序使用。
用户控件的行为很像 WPF 窗口 - 您可以在其中放置其他控件的区域,然后是代码隐藏文件,您可以在其中与这些控件进行交互。包含用户控件的文件也以 .xaml 结尾,而代码隐藏以 .xaml.cs 结尾——就像一个窗口。不过,起始标记看起来有点不同:
<UserControl x:Class="WpfTutorialSamples.User_Controls.LimitedInputUserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
</Grid>
</UserControl>
不过没什么奇怪的 - 一个根 UserControl 元素而不是 Window 元素,然后是 DesignHeight 和 DesignWidth 属性,它们在设计时控制用户控件的大小(在运行时,大小将由保存用户控制)。您会在代码隐藏中注意到同样的事情,它只是继承UserControl而不是Window。
创建用户控件
向您的项目添加一个用户控件,就像添加另一个窗口一样,通过右键单击要添加它的项目或文件夹名称,如此屏幕截图所示(事情可能看起来有点不同,具体取决于版本您正在使用的 Visual Studio):
在本文中,我们将创建一个有用的用户控件,该控件能够将 TextBox 中的文本数量限制为特定数量的字符,同时向用户显示已使用的字符数以及总共可能使用的字符数. 这很容易做到,并且在很多 Web 应用程序中使用,比如 Twitter。将此功能添加到常规 Window 会很容易,但由于在应用程序的多个位置执行此操作可能很有用,因此将其包装在易于重用的 UserControl 中是有意义的。
在我们深入研究代码之前,让我们先看看我们想要的最终结果:
这是用户控件本身的代码:
<UserControl x:Class="WpfTutorialSamples.User_Controls.LimitedInputUserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Label Content="{Binding Title}" />
<Label Grid.Column="1">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding ElementName=txtLimitedInput, Path=Text.Length}" />
<TextBlock Text="/" />
<TextBlock Text="{Binding MaxLength}" />
</StackPanel>
</Label>
<TextBox MaxLength="{Binding MaxLength}" Grid.Row="1" Grid.ColumnSpan="2" Name="txtLimitedInput" ScrollViewer.VerticalScrollBarVisibility="Auto" TextWrapping="Wrap" />
</Grid>
</UserControl>
using System;
using System.Windows.Controls;
namespace WpfTutorialSamples.User_Controls
{
public partial class LimitedInputUserControl : UserControl
{
public LimitedInputUserControl()
{
InitializeComponent();
this.DataContext = this;
}
public string Title { get; set; }
public int MaxLength { get; set; }
}
}
标记非常简单:一个有两列两行的网格。网格的上部包含两个标签,一个显示标题,另一个显示统计信息。它们中的每一个都使用数据绑定来获取所需的所有信息 - Title和MaxLength来自代码隐藏属性,我们在常规类中将其定义为常规属性。
当前字符数是通过直接绑定到 TextBox 控件上的 Text.Length 属性获得的,该控件使用用户控件的下部。结果可以在上面的屏幕截图中看到。请注意,由于所有这些绑定,我们不需要任何 C# 代码来更新标签或设置 TextBox 上的 MaxLength 属性 - 相反,我们只需直接绑定到属性。
消费/使用用户控件
有了上面的代码,我们所需要的就是在我们的窗口中消费(使用)用户控件。我们将通过在 Window 的 XAML 代码的顶部添加对 UserControl 所在的命名空间的引用来实现这一点:
xmlns:uc="clr-namespace:WpfTutorialSamples.User_Controls"
之后,我们可以使用 uc 前缀将控件添加到我们的 Window 中,就像添加任何其他 WPF 控件一样:
<uc:LimitedInputUserControl Title="Enter title:" MaxLength="30" Height="50" />
请注意我们如何直接在 XAML 中使用Title和MaxLength属性。这是我们窗口的完整代码示例:
<Window x:Class="WpfTutorialSamples.User_Controls.LimitedInputSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:uc="clr-namespace:WpfTutorialSamples.User_Controls"
Title="LimitedInputSample" Height="200" Width="300">
<Grid Margin="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<uc:LimitedInputUserControl Title="Enter title:" MaxLength="30" Height="50" />
<uc:LimitedInputUserControl Title="Enter description:" MaxLength="140" Grid.Row="1" />
</Grid>
</Window>
有了这个,我们可以在一行代码中重用整个功能,如本例所示,我们有两次有限的文本输入控件。如上所示,最终结果如下所示:
概括
强烈建议将常用的界面和功能放在用户控件中,从上面的示例中可以看出,它们非常易于创建和使用。