2010-12-10 63 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編寫不好的字典,但是很容易得到一個錯誤的警告。