我有一个ViewModel
class FontsViewModel : ObservableObject
{
public FontsViewModel()
{
InitFonts();
}
public ObservableCollection<Typeface> Fonts
{
get;
private set;
}
protected void InitFonts()
{
Fonts = (ObservableCollection<Typeface>)System.Windows.Media.Fonts.SystemFontFamilies;
}
}
我将它绑定在XAML
中<ribbon:RibbonComboBox.DataContext>
<vm:FontsViewModel />
</ribbon:RibbonComboBox.DataContext>
<ribbon:RibbonGallery>
<ribbon:RibbonGalleryCategory ItemsSource="{Binding Fonts}">
<ribbon:RibbonGalleryCategory.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}" FontFamily="{Binding}" />
</DataTemplate>
</ribbon:RibbonGalleryCategory.ItemTemplate>
</ribbon:RibbonGalleryCategory>
</ribbon:RibbonGallery>
当我尝试跑步时,我得到了
System.Windows.Markup.XamlParseException occurred
Message='The invocation of the constructor on type 'MarkdownEditMVVM.ViewModels.FontsViewModel' that matches the specified binding constraints threw an exception.' Line number '57' and line position '26'.
Source=PresentationFramework
LineNumber=57
LinePosition=26
StackTrace:
at System.Windows.Markup.XamlReader.RewrapException(Exception e, IXamlLineInfo lineInfo, Uri baseUri)
at System.Windows.Markup.WpfXamlLoader.Load(XamlReader xamlReader, IXamlObjectWriterFactory writerFactory, Boolean skipJournaledProperties, Object rootObject, XamlObjectWriterSettings settings, Uri baseUri)
at System.Windows.Markup.WpfXamlLoader.LoadBaml(XamlReader xamlReader, Boolean skipJournaledProperties, Object rootObject, XamlAccessLevel accessLevel, Uri baseUri)
at System.Windows.Markup.XamlReader.LoadBaml(Stream stream, ParserContext parserContext, Object parent, Boolean closeStream)
at System.Windows.Application.LoadComponent(Object component, Uri resourceLocator)
at MarkdownEditMVVM.MainWindow.InitializeComponent() in d:\Projects\MarkdownEdit\MarkdownEditMVVM\MainWindow.xaml:line 1
at MarkdownEditMVVM.MainWindow..ctor() in D:\Projects\MarkdownEdit\MarkdownEditMVVM\MainWindow.xaml.cs:line 25
InnerException: System.InvalidCastException
Message=Unable to cast object of type 'System.Collections.ObjectModel.ReadOnlyCollection`1[System.Windows.Media.FontFamily]' to type 'System.Collections.ObjectModel.ObservableCollection`1[System.Windows.Media.Typeface]'.
Source=MarkdownEditMVVM
StackTrace:
at MarkdownEditMVVM.ViewModels.FontsViewModel.InitFonts() in D:\Projects\MarkdownEdit\MarkdownEditMVVM\ViewModels\FontsViewModel.cs:line 26
at MarkdownEditMVVM.ViewModels.FontsViewModel..ctor() in D:\Projects\MarkdownEdit\MarkdownEditMVVM\ViewModels\FontsViewModel.cs:line 15
InnerException:
我在做错了什么?它就像我在Lesters Tutorial on WPF Ribbon 上看到的修改版本
答案 0 :(得分:4)
您无法将SystemFontFamilies转换为ObservableCollection。 而是实例化一个新的集合:
Fonts = new ObservableCollection<Typeface> (Fonts.SystemFontFamilies);
编辑:上面的代码在属性类型和集合类型之间不匹配 而是使用以下之一:
var myFonts = new ObservableCollection<FontFamily>(Fonts.SystemFontFamilies);
var typefaces = new ObservableCollection<Typeface>(Fonts.SystemTypefaces);
答案 1 :(得分:4)
两点:
这里你真的不需要ObservableCollection(如果字体列表永远不会改变。)公开IEnumerable<Typeface>
属性就足够了。
您实际上不应该从ViewModel引用特定于视图的对象,如字体。最好将可用的字体名称公开为字符串,并通过某些服务接口注入可用的名称。然后,服务接口(在View侧)将调用System.Windows.Media.Fonts.SystemFontFamilies
并转换为字符串名称。这使您可以隔离可测试性(您的单元测试可以提供自己的字体名称。)