在值转换器中选择ItemTemplate

时间:2016-05-19 17:04:12

标签: c# xaml uwp

我试图在listview中根据每个items属性设置多个ItemTemplates。但我继续得到{"错误HRESULT E_FAIL已从调用COM组件返回。"}在我的值转换器中:

public class EquipmentTemplateConverter : IValueConverter
{
    public object Convert(object value, Type type, object parameter, string language)
    {
        switch ((EquipmentType) (int) value)
        {
            case EquipmentType.Normal:
                return Application.Current.Resources.FirstOrDefault(r => r.Key.ToString() == "EquipmentNormalTemplate");
            case EquipmentType.Upgrade:
                return Application.Current.Resources.FirstOrDefault(r => r.Key.ToString() == "EquipmentUpgradeTemplate");
            default:
                throw new ArgumentOutOfRangeException(nameof(value), value, null);
        }
    }

    public object ConvertBack(object value, Type type, object parameter, string language)
    {
        throw new NotImplementedException();
    }
}

XAML:

    <DataTemplate x:Key="EquipmentTemplate" >
        <Grid>
            <ContentControl DataContext="{Binding}" Content="{Binding}" x:Name="TheContentControl" ContentTemplate="{Binding Equipment.Type, Converter={StaticResource EquipmentTemplateConverter } }" />
        </Grid>
    </DataTemplate>

我有什么想法可以解决这个问题吗?

2 个答案:

答案 0 :(得分:1)

通常的方法是编写DataTemplateSelector并将其实例分配给ContentControl.ContentTemplateSelector

<DataTemplate x:Key="EquipmentTemplate" >
    <DataTemplate.Resources>
        <local:EquipmentTemplateSelector x:Key="EquipmentTemplateSelector" />
    </DataTemplate.Resources>
    <Grid>
        <ContentControl 
            DataContext="{Binding}" 
            Content="{Binding}" 
            x:Name="TheContentControl" 
            ContentTemplateSelector="{StaticResource EquipmentTemplateSelector}" 
            />
    </Grid>
</DataTemplate>

C#:

public class EquipmentTemplateSelector : DataTemplateSelector
{
    public override DataTemplate SelectTemplate(object item, DependencyObject container)
    {
        //  container is the container. Cast it to something you can call
        //  FindResource() on. Put in a breakpoint and use the watch window. 
        //  I'm at work with Windows 7. Shouldn't be too hard.
        var whatever = container as SomethingOrOther;

        Object resKey = null;

        //  ************************************
        //  Do stuff here to pick a resource key
        //  ************************************

        //  Application.Current.Resources is ONE resource dictionary.
        //  Use FindResource to find any resource in scope. 
        return whatever.FindResource(resKey) as DataTemplate;
    }
}

答案 1 :(得分:0)

  

但我一直得到{“错误HRESULT E_FAIL已从调用COM组件返回。”}在我的值转换器中。

当对样式或事件处理程序的引用不存在或不在XAML的上下文中时,通常会发生此错误。

您只发布了转换器的代码和部分xaml代码,我无法100%重现您的数据模型和您的xaml,但是从您的代码中,我认为在您的转换器中,您希望返回具体的DataTemplate,但实际上您返回KeyValuePair<object, object>,资源在ResourceDictionary中定义,请点击“键值”部分,有关详细信息,请参阅ResourceDictionary and XAML resource references。< / p>

在这里我写了一个样本,我再没有100%重现你的xaml和数据模型:

MainPage.xaml中:

<Page.Resources>
    <local:EquipmentTemplateConverter x:Key="EquipmentTemplateConverter" />
</Page.Resources>

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <ListView ItemsSource="{x:Bind list}">
        <ListView.ItemTemplate>
            <DataTemplate>
                <ContentControl DataContext="{Binding}" Content="{Binding}" ContentTemplate="{Binding Count, Converter={StaticResource EquipmentTemplateConverter}}" />
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
</Grid>
代码背后的代码:

private ObservableCollection<EquipmentType> list = new ObservableCollection<EquipmentType>();

public MainPage()
{
    this.InitializeComponent();
}

protected override void OnNavigatedTo(NavigationEventArgs e)
{
    list.Add(new EquipmentType { Count = 0 });
    list.Add(new EquipmentType { Count = 1 });
    list.Add(new EquipmentType { Count = 0 });
    list.Add(new EquipmentType { Count = 0 });
    list.Add(new EquipmentType { Count = 1 });
    list.Add(new EquipmentType { Count = 1 });
}

我的EquipmentType课很简单:

public class EquipmentType
{
    public int Count { get; set; }
}

EquipmentTemplateConverter是这样的:

public class EquipmentTemplateConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, string language)
    {
        switch ((int)value)
        {
            case 0:
                var a = Application.Current.Resources.FirstOrDefault(r => r.Key.ToString() == "EquipmentNormalTemplate");
                return a.Value;

            case 1:
                var b = Application.Current.Resources.FirstOrDefault(r => r.Key.ToString() == "EquipmentUpgradeTemplate");
                return b.Value;

            default:
                throw new ArgumentOutOfRangeException(nameof(value), value, null);
        }
    }

    public object ConvertBack(object value, Type targetType, object parameter, string language)
    {
        throw new NotImplementedException();
    }
}

由于您在转换器中使用Application.Resources property,我只需将DataTemplate放入App.xaml进行测试:

<Application.Resources>
    <DataTemplate x:Key="EquipmentNormalTemplate">
        <Grid>
            <TextBlock Text="This is EquipmentNormalTemplate." />
        </Grid>
    </DataTemplate>
    <DataTemplate x:Key="EquipmentUpgradeTemplate">
        <Grid>
            <TextBlock Text="This is EquipmentUpgradeTemplate." />
        </Grid>
    </DataTemplate>
</Application.Resources>

但我同意@Ed Plunkett,使用DataTemplateSelector是一种更常用的方式来完成这项工作。