【问题标题】:SystemFontFamilies error when binding to combobox绑定到组合框时出现 SystemFontFamilies 错误
【发布时间】:2016-03-02 13:21:07
【问题描述】:

我枚举字体家族列表并绑定到组合框,问题是系统中的字体已损坏。整个应用程序将崩溃。有什么方法可以绑定到 systemfontfamilies 却可以跳过显示错误的字体?

如果 itemtemplate 中的 fontfamily 绑定被注释,则以下代码运行良好。

 <ComboBox x:Name="comboFonts"
                          Grid.IsSharedSizeScope="True"
                          Grid.Row="0" Grid.Column="1"
                          ItemsSource="{Binding Source={x:Static Member=Fonts.SystemFontFamilies}}"
                          SelectedItem="{Binding FontFamily, Mode=TwoWay}"
                          HorizontalAlignment="Stretch">
        <ComboBox.ItemTemplate>
            <DataTemplate>
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="Auto" SharedSizeGroup="FontName"></ColumnDefinition>
                        <ColumnDefinition Width="*"></ColumnDefinition>
                    </Grid.ColumnDefinitions>
                    <TextBlock Text="{Binding Source}" HorizontalAlignment="Left"/>
                    <Label FontFamily="{Binding FallbackValue=Verdana}" HorizontalAlignment="Right">Sample</Label>
                </Grid>

            </DataTemplate>
        </ComboBox.ItemTemplate>
    </ComboBox>

得到的错误信息如下

Message=Input file or data stream does not conform to the expected file format specification.
Source=PresentationCore
StackTrace:
   at MS.Internal.Text.TextInterface.Native.Util.ConvertHresultToException(Int32 hr)
   at MS.Internal.Text.TextInterface.Font.CreateFontFace()
   at MS.Internal.Text.TextInterface.Font.AddFontFaceToCache()
   at MS.Internal.Text.TextInterface.Font.GetFontFace()

请帮忙。谢谢

【问题讨论】:

    标签: wpf fonts


    【解决方案1】:

    我遇到了同样的问题。 在 Richtextbox 编辑器中,我用所有可用的字体系列填充功能区组合框,并将该字体附加到组合框中的特定项目,以便用户立即看到字体的外观。

    当系统中存在 WPF 无法呈现的字体时,应用程序会崩溃。

    查看事件查看器中的堆栈跟踪,我注意到 WPF 尝试实例化 System.Windows.Media.GlyphTypeface 类型的对象。 我发现,当我尝试自己在代码中实例化该对象(通过 System.Windows.Media.Typeface 类型)并且 TryGetGlyphTypeface() 函数将为我的特定字体设置返回 false 时,该字体在 WPF 中不可用。

    为我解决问题的代码:

        foreach (FontFamily aFontFamily in Fonts.SystemFontFamilies)
        {
            // Instantiate a TypeFace object with the font settings you want to use
            Typeface ltypFace = new Typeface(aFontFamily, FontStyles.Normal, FontWeights.Normal, FontStretches.Normal);
            // Try to create a GlyphTypeface object from the TypeFace object
            GlyphTypeface lglyphTypeFace;
            if (ltypFace.TryGetGlyphTypeface(out lglyphTypeFace))
            {
                // Creation of the GlyphTypeface worked. You can use the font
                RibbonGalleryItem lribItem = new RibbonGalleryItem();
                lribItem.Content = aFontFamily.Source;
                lribItem.FontFamily = aFontFamily;
                lribGalCatFont.Items.Add(lribItem);
            }
        }
    

    为了防止每次加载组合框时都必须执行此代码(因为它位于用户控件中,所以执行的次数很多),我在应用程序启动时执行此操作,并将可用字体数组保存在全局变量。

    【讨论】:

    • 但是请注意,对于有效的字体系列,即复合字体,TryGetGlyphTypeface() 返回null正常。仅仅因为它返回null,这并不一定意味着字体文件已损坏(当然,如果您依赖GlyphTypeface 本身,则必须通过分解复合材料来做更多的工作来获得它字体...但这不是问题的一部分)。
    【解决方案2】:

    好的,5 年后,这是另一个解决方案:

    Window.Resource声明此代码:

    <CollectionViewSource x:Key="MyFonts" Source="{Binding Source={x:Static Fonts.SystemFontFamilies}, Converter={StaticResource FontToSupportedGliphConverter}}">
        <CollectionViewSource.SortDescriptions>
            <componentModel:SortDescription PropertyName="Source" />
        </CollectionViewSource.SortDescriptions>
    </CollectionViewSource>
    
    <Style x:Key="FontStyle">
        <Setter Property="Control.FontFamily" Value="{Binding .}" />
        <Setter Property="Control.FontSize" Value="16" />
    </Style>
    
    <DataTemplate x:Key="FontTemplate">
        <VirtualizingStackPanel IsVirtualizing="True" VirtualizationMode="Recycling" ScrollViewer.IsDeferredScrollingEnabled="True">
            <TextBlock Style="{StaticResource FontStyle}" Text="{Binding .}" ToolTip="{Binding .}" />
        </VirtualizingStackPanel>
    </DataTemplate>
    

    并使用这个Converter

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        var list = value as IReadOnlyCollection<FontFamily>;
    
        if (list == null)
            return DependencyProperty.UnsetValue;
    
        var returnList = new List<FontFamily>();
        foreach (FontFamily font in list)
        {
            //Instantiate a TypeFace object with the font settings you want to use
            Typeface ltypFace = new Typeface(font, FontStyles.Normal, FontWeights.Normal, FontStretches.Normal);
    
            //Try to create a GlyphTypeface object from the TypeFace object
            GlyphTypeface lglyphTypeFace;
            if (ltypFace.TryGetGlyphTypeface(out lglyphTypeFace))
            {
                returnList.Add(font);
            }
        }
    
        return returnList;
    }
    

    并将资源应用到ComboBox

    <ComboBox x:Name="FreeTextFontComboBox" Margin="10,5" 
              MinWidth="100" MaxWidth="110" IsEditable="True"
              ItemTemplate="{DynamicResource FontTemplate}" 
              SelectedItem="{Binding Source={x:Static prop:Settings.Default}, 
              Path=FreeTextFontFamily}">
        <ComboBox.ItemsSource>
            <Binding Source="{StaticResource MyFonts}" />
        </ComboBox.ItemsSource>
    </ComboBox>
    

    【讨论】:

    • 见另一个答案中的注释。除了具有损坏字体文件的字体之外,此方法将跳过有效的复合字体。
    • 我们可以做些什么来避免丢失一些字体?用returnList.Add(font); 包裹在try catch 内?
    • 正如我在另一条评论中所写的,当您遇到复合字体时,您需要做更多的工作才能获得真正的字体。 IE。检查其FamilyMaps 以找到支持您尝试呈现的Unicode 代码点的适当FontFamily。是的,对于无效/损坏的字体,处理异常可以解决这个问题。不过,恕我直言,如果您要这样做,您至少应该通知用户 哪个 字体导致了异常,以便他们可以修复他们的系统。
    猜你喜欢
    • 1970-01-01
    • 2011-12-14
    • 2023-03-15
    • 1970-01-01
    • 1970-01-01
    • 2011-04-14
    • 2016-01-08
    • 2013-12-19
    • 2014-10-18
    相关资源
    最近更新 更多