我是否錯過了從.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='<PIN>'}"/>
<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=<Add Account>}"/>
</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。
很顯然,解決方案是將兩個資源放入同一個字典中,但據我所知這是一個黑客行爲,並不是邏輯資源查找系統的預期行爲。我現在不是一個快樂的兔子。這似乎相當無證...