65.9K
CodeProject 正在变化。 阅读更多。
Home

纯 XAML 字体 ComboBox

starIconstarIconstarIconstarIconstarIcon

5.00/5 (17投票s)

2012年2月6日

CPOL

3分钟阅读

viewsIcon

68639

downloadIcon

1489

一个纯 XAML 的字体组合框。

325753/xamlfontchooser_menu.png

引言

我需要在 WPF 应用程序中选择 FontFamily 的一个简单 ComboBox(我不关心字体粗细)。 经过一番搜索,我找到了 Pete O'Hanlon 的文章,其中描述了我想要的内容。

那么为什么还要写另一篇(短!)文章呢?文章中的第一个评论者提出了这个

<ListBox ItemsSource="{Binding Source={x:Static Member=Fonts.SystemFontFamilies}}">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <Label FontFamily="{Binding .}" Content="{Binding Source}" />
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

作为一种替代方案,这让我考虑将两者结合起来,作为一个纯 XAML 解决方案,您可以剪切和粘贴(因为 Pete 的代码有一点代码隐藏)。为了创建 XAML 解决方案,我发现了一些有趣的事情,我想在一个真实的例子中分享一下(因为我仍然在努力掌握 WPF 的许多方面)。

展示 XAML 代码!

这是它的全部内容

<ComboBox 
          xmlns:ComponentModel="clr-namespace:System.ComponentModel;assembly=WindowsBase"
          ItemTemplate="{DynamicResource FontTemplate}">
    <ComboBox.Resources>

        <CollectionViewSource x:Key="myFonts" Source="{Binding Source={x:Static Fonts.SystemFontFamilies}}">
            <CollectionViewSource.SortDescriptions>
                <ComponentModel:SortDescription PropertyName="Source" />
            </CollectionViewSource.SortDescriptions>
        </CollectionViewSource>

        <Style x:Key="FontStyle">
            <Setter Property="Control.FontFamily" Value="{Binding Source}" />
            <Setter Property="Control.FontSize" Value="16" />
        </Style>

        <DataTemplate x:Key="FontTemplate">
            <StackPanel VirtualizingStackPanel.IsVirtualizing="True">
                <TextBlock Style="{StaticResource FontStyle}"
                           Text="{Binding Source}"
                           ToolTip="{Binding Source}" />
            </StackPanel>
        </DataTemplate>

    </ComboBox.Resources>

    <ComboBox.ItemsSource>
        <Binding Source="{StaticResource myFonts}" />
    </ComboBox.ItemsSource>
</ComboBox>

您应该能够直接将它剪切并粘贴到您的代码中。然后,您会将 ComboBoxSelectedValue 绑定到您选择的属性。 SelectedValue 的类型为 System.Windows.Media.FontFamily

发生了什么?

我们需要描述几件事。当心!更冗长的 XAML!

排序的字体列表

直接跳到 ComboBox.Resources 部分:我们获得了完整的系统字体集合。 但是,默认情况下,它们仅部分排序(按 FamilyName),因此我们将它们排序到我们自己的名为 myFonts 的集合中。 我们通过此 XAML 标记导入 ComponentModel 命名空间来做到这一点

xmlns:ComponentModel="clr-namespace:System.ComponentModel;assembly=WindowsBase"

然后创建我们自己的按 Source 属性(字体系列名称)排序的集合

<CollectionViewSource x:Key="myFonts" Source="{Binding Source={x:Static Fonts.SystemFontFamilies}}">
    <CollectionViewSource.SortDescriptions>
        <ComponentModel:SortDescription PropertyName="Source" />
    </CollectionViewSource.SortDescriptions>
</CollectionViewSource>

数据模板

我们声明一个简单的模板,在 ComboBox 中以其自己的字体类型呈现字体,并提供工具提示。

静态资源

最后,我们使用长格式 XAML 绑定将 ComboBox.ItemsSource 绑定到我们排序的字体集合 myFonts。 为什么我们要最后执行此操作,而不是直接作为 ComboBox 属性?

ItemsSource 属性要求它绑定到静态资源。 假设我们这样做

<ComboBox 
  xmlns:ComponentModel="clr-namespace:System.ComponentModel;assembly=WindowsBase"
  ItemTemplate="{DynamicResource FontTemplate}"
  ItemsSource="{Binding Source={StaticResource myFonts}}">

我们得到一个异常抛出

"找不到名为“myFonts”的资源。 资源名称区分大小写。"

因为 myFonts 尚未声明。

当然,我们可以将字体集合移动到 UserControl/Window/Application Resources 部分,但是在此示例中,我们只有一个字体组合框,因此最好将其放在 ComboBox.Resources 部分中。

您还可以尝试通过以下方式将 ItemsSource 设置为动态引用 myFonts

<ComboBox 
  xmlns:ComponentModel="clr-namespace:System.ComponentModel;assembly=WindowsBase"
  ItemTemplate="{DynamicResource FontTemplate}"
  ItemsSource="{Binding Source={DynamicResource myFonts}}">

这也会失败,并出现异常

"不能在类型为“Binding”的“Source”属性上设置“DynamicResourceExtension”。 “DynamicResourceExtension”只能在 DependencyObject 的 DependencyProperty 上设置。"

因此,为了回答我们的问题:由于 XAML 有一个“单遍编译器”,因此必须在词法上声明 StaticResource然后才能引用它:如果我们最后声明绑定,那么我们可以在 ComboBox.Resources 中创建我们排序的字体列表 StaticResource,然后在 ComboBox 的 XAML 中绑定到它,因此有了这段 XAML

<ComboBox.ItemsSource>
    <Binding Source="{StaticResource myFonts}" />
</ComboBox.ItemsSource>

使用此 XAML 代码段

如上所述,如果您打算使用此 XAML(并多次使用字体组合框),请移动排序的字体集合

<CollectionViewSource x:Key="myFonts" Source="{Binding Source={x:Static Fonts.SystemFontFamilies}}">
    ...
</CollectionViewSource>

到您的 Application/Window/UserControl Resources 部分,并将此属性

xmlns:ComponentModel="clr-namespace:System.ComponentModel;assembly=WindowsBase"

放入相应的 XAML 文档根目录。

感谢 Pete 的原始 XAML。

关于安全字体使用的最后一句话

永远,永远不要选择 Comic Sans。 永远。

© . All rights reserved.