2010-12-10 84 views
2

我是否错过了从.net 3.5升级到.net 4的某些内容,因为我看到似乎与系统目标相反的错误行为。WPF静态资源对DataTemplates中的逻辑资源的引用在运行时不能解析

我想用一些例子来鼓起一个简单的MVVM库的工作。我在Twitter客户端应用程序中使用它进行了一些额外的学习,并且遇到了很大的绊脚石。

情况是这样的。我的根ViewModel(TwitterClientViewModel)对象被给予用于显示的DialogViewModel对象的实例。 DialogViewModel被添加到一个集合中,而一个布尔HasDialogs被设置为true。 PropertyChanged事件被调用的集合和标志,如果有必要。这部分工作惊人。

TwitterClientViewModel的视图称为TwitterClientTemplate,使Visible成为DialogViewTemplate(DialogViewModel的视图)托管的叠加层。托管ContentControl的模板引用带有DynamicResource扩展名的DialogViewTemplate。这在设计器和运行时显示很棒。

这是事情变得奇怪的地方。 DialogViewTemplate的“主体”托管与DialogViewModel.Content(类型对象)绑定的进一步内容控件的对话内容。我希望通过使用TemplateSelector(我写了一个很好的声明式的模板选择器,但为了测试目的而将其注释掉),我可以同时显示文本和交互式元素。例如,在验证Twitter帐户时请求用户的详细信息。在这种情况下,PIN码。

在这一点上,我有两个嵌套的对话框实现的内容控件。出于测试目的,DialogViewTemplate正文中的contentcontrol使用静态资源扩展来检索EnterPINDialogTemplate(查看EnterPINDialogViewModel)。 EnterPINDialogTemplate和DialogViewTemplate都在同一个文件中(前者当然是首先定义的),尽管它们最初是分开的。

在运行时,staticresource扩展会在消息中抛出XamlParseException; '在'System.Windows.Markup.StaticResourceHolder'上提供值引发异常。'

和内部异常消息;

'找不到名为'EnterPINDialogTemplate'的资源。资源名称区分大小写'

使用动态资源返回null,并在contentcontrol中显示EnterPINDialogViewModel类型的完整名称 - 如资源未解析时所预期的那样。打破我的自定义TemplateSelector调用FrameWorkElement.FindResource()抛出一个类似的异常(TryFindResource返回null)。

我的第一个想法是逻辑树在构建数据模板时被拆分,并且我从早期的项目中记起该区域的问题。我试着用资源字典的MergeDictionaries属性,以使词典从内DataTemplate中的avaliable资源,但设计师并没有像我,一个比特,并且在这里描述的错误: http://connect.microsoft.com/VisualStudio/feedback/details/498844/wpf-designer-throws-invalidcastexception

刮开这一想法。我尝试在Application,Window和TwitterClientTemplate级别合并字典,但没有运气。

以下是xaml文件。

DialogTemplates。XAML

<ResourceDictionary 
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
xmlns:VM="clr-namespace:EpicTweet.ViewModel" 
xmlns:ET="clr-namespace:EpicTweet" 
xmlns:T="clr-namespace:EpicTweet.Tools" 
xmlns:MV="clr-namespace:MVVM;assembly=MVVM" 
xmlns:Loc="clr-namespace:EpicTweet.Localization" 
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"> 
<DataTemplate DataType="VM:EnterPINDialogViewModel" x:Key="EnterPINDialogTemplate"> 
    <Grid d:DesignWidth="453.89" d:DesignHeight="78.92" Loc:ResXManagerProperty.ResourceManager="{x:Static ET:Language.ResourceManager}"> 
     <Grid.RowDefinitions> 
      <RowDefinition Height="Auto"/> 
      <RowDefinition/> 
     </Grid.RowDefinitions> 
     <Grid.ColumnDefinitions> 
      <ColumnDefinition Width="Auto"/> 
      <ColumnDefinition/> 
     </Grid.ColumnDefinitions> 
     <Label Content="{Loc:ResxExtension ResourceName=String_PIN, FallbackValue='&lt;PIN&gt;'}"/> 
     <TextBox Grid.Column="1"/> 
     <TextBlock Grid.Row="1" Grid.RowSpan="2"></TextBlock> 
    </Grid> 
</DataTemplate> 
<DataTemplate x:Key="DialogViewTemplate" DataType="MV:DialogViewModel"> 
    <Border BorderBrush="Black" BorderThickness="1"> 
     <Grid d:DesignWidth="277.419" d:DesignHeight="74.96" Background="{DynamicResource {x:Static SystemColors.ControlDarkBrushKey}}" Height="Auto" Width="Auto"> 
      <Grid.RowDefinitions> 
       <RowDefinition Height="Auto"/> 
       <RowDefinition/> 
       <RowDefinition Height="Auto"/> 
      </Grid.RowDefinitions> 
      <Border d:LayoutOverrides="Width, Height" BorderThickness="0,0,0,1" BorderBrush="Black"> 
       <Label Content="{Binding DisplayName, FallbackValue=Header}" VerticalAlignment="Center" HorizontalAlignment="Left"/>  
      </Border> 
      <ContentControl Content="{Binding Content, FallbackValue=Body}" ContentTemplate="{StaticResource EnterPINDialogTemplate}" HorizontalAlignment="Stretch" d:LayoutOverrides="Height" Grid.Row="1" Margin="5"> 
       <!--<ContentControl.ContentTemplateSelector> 
        <T:TypeTemplateSelector> 
         <T:TemplateTypeRelationship Type="{x:Type VM:EnterPINDialogViewModel}" ResourceKey="EnterPINDialogTemplate"/> 
        </T:TypeTemplateSelector> 
       </ContentControl.ContentTemplateSelector>--> 
      </ContentControl> 
       <ItemsControl Grid.Row="2" Margin="10" 
       ItemsSource="{Binding Commands, Mode=OneTime, FallbackValue={x:Static VM:TwitterClientViewModel.DEFAULT_DIALOG_COMMANDS}}"> 
       <ItemsControl.ItemTemplate> 
        <DataTemplate> 
         <Button 
         Content="{Binding DisplayName, FallbackValue=CommandName, Mode=OneWay}" 
         Command="{Binding}"/> 
        </DataTemplate> 
       </ItemsControl.ItemTemplate> 
       <ItemsControl.ItemsPanel> 
        <ItemsPanelTemplate> 
         <WrapPanel Orientation="Horizontal"/> 
        </ItemsPanelTemplate> 
       </ItemsControl.ItemsPanel> 
      </ItemsControl> 
     </Grid> 
    </Border> 
</DataTemplate> 

TwitterClientDataTemplate.xaml

<ResourceDictionary 
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
xmlns:VM="clr-namespace:EpicTweet.ViewModel" 
xmlns:ET="clr-namespace:EpicTweet" 
xmlns:MV="clr-namespace:MVVM;assembly=MVVM" 
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"> 
<ResourceDictionary.MergedDictionaries> 
    <ResourceDictionary Source="DialogTemplates.xaml"/> 
</ResourceDictionary.MergedDictionaries> 
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/> 
<DataTemplate x:Key="TwitterClientTemplate" DataType="MV:TwitterClientViewModel"> 
    <ScrollViewer d:DesignWidth="285.083" d:DesignHeight="119.96"> 
     <Grid> 
      <StackPanel d:LayoutOverrides="Width, Height"> 
       <StackPanel Orientation="Horizontal"> 
        <Button Command="{Binding AddAccountCommand.Command}" Content="{Binding AddAccountCommand.DisplayName, FallbackValue=&lt;Add Account&gt;}"/> 
       </StackPanel> 
       <ContentControl/> 
      </StackPanel> 
      <Border BorderThickness="1" Background="#80000000" Visibility="{Binding HasDialogs, Converter={StaticResource BooleanToVisibilityConverter}, FallbackValue=Collapsed, Mode=OneWay}"> 
       <Grid VerticalAlignment="Stretch" MinWidth="50" MaxWidth="200"> 
        <ContentControl Content="{Binding Dialogs[0], Mode=OneWay}" ContentTemplate="{DynamicResource DialogViewTemplate}" HorizontalAlignment="Center" VerticalAlignment="Center"/> 
       </Grid> 
      </Border> 
     </Grid> 
    </ScrollViewer> 
</DataTemplate> 

帮我计算器,你是我唯一的希望!

编辑:在这个问题上做了一些进一步的工作。如果两个模板都在同一个文件中,那么动态资源和静态资源扩展都可以毫无问题地解决资源问题。如果它们位于单独的文件中,则无论我如何合并字典,资源都不会解析;每个扩展返回null。

很显然,解决方案是将两个资源放入同一个字典中,但据我所知这是一个黑客行为,并不是逻辑资源查找系统的预期行为。我现在不是一个快乐的兔子。这似乎相当无证...

回答

7

如果有一个普拉特,那就是我。在星期五晚上试图解决这个问题之后的4个小时后,我已经破解了它,不用感谢我只能称为片状错误报告。

这里是嗡嗡声。

<DataTemplate x:Key="TwitterClientTemplate" DataType="MV:TwitterClientViewModel"> 

应该

<DataTemplate x:Key="TwitterClientTemplate" DataType="{x:Type MV:TwitterClientViewModel}"> 

和BAM,它的工作原理。然而,我的大抱怨仍然存在。为什么不正确的语法在设计器中工作,而不是在运行时?我的猜测是,因为运行时优化并没有费心去填充xaml编写不好的字典,但是很容易得到一个错误的警告。