数据绑定ViewModel的问题

时间:2010-09-28 22:50:14

标签: c# mvvm

我有一个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

上看到的修改版本

2 个答案:

答案 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)

两点:

  1. 这里你真的不需要ObservableCollection(如果字体列表永远不会改变。)公开IEnumerable<Typeface>属性就足够了。

  2. 您实际上不应该从ViewModel引用特定于视图的对象,如字体。最好将可用的字体名称公开为字符串,并通过某些服务接口注入可用的名称。然后,服务接口(在View侧)将调用System.Windows.Media.Fonts.SystemFontFamilies并转换为字符串名称。这使您可以隔离可测试性(您的单元测试可以提供自己的字体名称。)