使用来自不同程序集的资源和DataTemplateSelector
问题描述:
我在基本程序集中有一个控件,其中包含我想基于当前DataContext设置的内容。使用来自不同程序集的资源和DataTemplateSelector
为此,我试图在调用程序集中使用资源和子类DataTemplateSelector,如下所示。我最初的希望是调用子类DataTemplateSelector,但事实并非如此。然后我尝试在调用程序集的资源字典中使用相同的键添加一个条目,但使用了子类选择器,但是这也不能完成。
有没有办法解决我必须使这项工作的代码?有没有更好的策略来设置来自调用程序集的内容?
干杯,
Berryl
用户控制(底座组件)
<UserControl
...
<Grid>
<Border Style="{StaticResource FilterPanelBorderStyle}">
<StackPanel Orientation="Horizontal" x:Name="myFilterPanel" >
***** <ContentControl x:Name="ctrlFilters" ContentTemplateSelector="{StaticResource filterControlsTemplateSelector}" /> ****
<Button x:Name="btnClearFilter" Style="{StaticResource FilterPanelClearButtonStyle}" />
<Label x:Name="lblStatus" Style="{StaticResource FilterPanelLabelStyle}" Content="{Binding Status}" />
</StackPanel>
</Border>
</Grid>
</UserControl>
资源和DataTemplateSelector(底座组件)
<views:FilterControlsTemplateSelector x:Key="filterControlsTemplateSelector"/>
<DataTemplate x:Key="defaultFilterContent">
<TextBlock>Replace ME with real filters!</TextBlock>
</DataTemplate>
public class FilterControlsTemplateSelector : DataTemplateSelector
{
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
var fe = container as FrameworkElement;
if (fe == null) return null;
return _GetDataTemplate(fe);
}
protected virtual DataTemplate _GetDataTemplate(FrameworkElement fe) {
var template = fe.FindResource("defaultFilterContent") as DataTemplate;
return template;
}
}
资源和选择器(调用部件)
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/Core.Presentation.Wpf;component/Themes/Generic.xaml" />
</ResourceDictionary.MergedDictionaries>
<local:PimFilterControlsTemplateSelector x:Key="filterControlsTemplateSelector"/>
<DataTemplate x:Key="pimFilterContent">
<Grid>
<Border Style="{StaticResource FilterPanelBorderStyle}">
<StackPanel Orientation="Horizontal" >
<cc:SearchTextBox
x:Name="stbLastNameFilter" Style="{StaticResource FilterPanelSearchTextBoxStyle}"
/>
<cc:SearchTextBox
x:Name="stbFirstNameFilter" Style="{StaticResource FilterPanelSearchTextBoxStyle}"
/>
</StackPanel>
</Border>
</Grid>
</DataTemplate>
public class PimFilterControlsTemplateSelector : FilterControlsTemplateSelector
{
protected override DataTemplate _GetDataTemplate(FrameworkElement fe)
{
var dc = fe.DataContext;
if (dc == null) return null;
DataTemplate result = null;
if (dc is PimMasterVm)
{
result = fe.FindResource("pimFilterContent") as DataTemplate;
}
else {
result = base._GetDataTemplate(fe);
}
return result;
}
}
应用词典的设置(调用组件)
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/Parties.Presentation.Wpf;component/PimCommonResources.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
答
我放弃了使DataTemplateSelector工作和清盘执行以下操作:
- 创建FilterContentConverter
- 加入FilterContentKey(串)我的观点模型
该转换器只需要FilterContentKey和做es资源查找以获取具有该密钥的DataTemplate。这样可以很好地测试,甚至更好 - 它的工作原理!
以下解决方案代码,感谢Vladamir Dorokhov and this SO answer帮助我获得ContentControl绑定的权利。
HTH,
Berryl
滤波控制
<Grid>
<Border Style="{StaticResource FilterPanelBorderStyle}">
<StackPanel Orientation="Horizontal" x:Name="myFilterPanel" >
<ContentControl x:Name="ctrlFilters"
ContentTemplate="{Binding Path=FilterContentKey, Converter={StaticResource filterTemplateContentConv}}" />
<Button x:Name="btnClearFilter" Style="{StaticResource FilterPanelClearButtonStyle}" />
<Label x:Name="lblStatus" Style="{StaticResource FilterPanelLabelStyle}" Content="{Binding Status}" />
</StackPanel>
</Border>
</Grid>
数据模板(资源)
<DataTemplate x:Key="pimFilterContent">
<StackPanel Orientation="Horizontal" >
<cc:SearchTextBox x:Name="stbLastNameFilter"
Style="{StaticResource FilterPanelSearchTextBoxStyle}"
Text="{Binding Path=LastNameFilter, UpdateSourceTrigger=PropertyChanged}"
/>
<cc:SearchTextBox x:Name="stbFirstNameFilter"
Style="{StaticResource FilterPanelSearchTextBoxStyle}"
Text="{Binding Path=FirstNameFilter, UpdateSourceTrigger=PropertyChanged}"
/>
</StackPanel>
</DataTemplate>
转换器
/// <summary>
/// Thin wrapper around a resource lookup designed to result in a <see cref="DataTemplate"/>
/// representing filering controls.
/// </summary>
[ValueConversion(typeof(object), typeof(DataTemplate))]
public class FilterTemplateContentConverter : IValueConverter
{
public const string DEFAULT_CONTENT = "undefinedFilterContent";
protected readonly ResourceLocator _resourceLocator;
/// <summary>
/// Initializes a new instance of the <see cref="FilterTemplateContentConverter"/> class.
/// Unit tests can use this to pass in an app for the <see cref="ResourceLocator"/>.
/// </summary>
/// <param name="app">The app.</param>
public FilterTemplateContentConverter(Application app) { _resourceLocator = new ResourceLocator(app); }
/// <summary>
/// Initializes a new instance of the <see cref="FilterTemplateContentConverter"/> class.
/// The 'real' application uses this.
/// </summary>
public FilterTemplateContentConverter()
{
_resourceLocator = new ResourceLocator();
}
public virtual object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
var key = value as string;
return _resourceLocator.GetResource(key ?? DEFAULT_CONTENT);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); }
}