简体   繁体   English

在值转换器中选择ItemTemplate

[英]Select ItemTemplate in value converter

I'm trying to have multiple ItemTemplates in a listview based on each items property. 我试图在基于每个项目属性的列表视图中有多个ItemTemplates。 But I keep getting {"Error HRESULT E_FAIL has been returned from a call to a COM component."} in my value converter: 但是我在值转换器中不断收到{“对COM组件的调用已返回错误HRESULT E_FAIL。”}:

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: XAML:

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

Any ideas how I can solve this? 有什么想法可以解决这个问题吗?

The usual way to do this is by writing a DataTemplateSelector and assigning an instance of it to ContentControl.ContentTemplateSelector . 通常的方法是编写一个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#: 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;
    }
}

But I keep getting {"Error HRESULT E_FAIL has been returned from a call to a COM component."} in my value converter. 但是我在值转换器中不断收到{“对COM组件的调用已返回错误HRESULT E_FAIL。”}。

This error usually happens when a reference to a style or an event handler that dose not exist or is not within the context of the XAML. 当对样式或事件处理程序的引用不存在或不在XAML上下文中时,通常会发生此错误。

You posted only the code of your converter and part of your xaml code, I can't 100% reproduce your data model and your xaml, but from your code, I think in your converter, you would like to return the specific DataTemplate , but you actually return a KeyValuePair<object, object> , resources are defined in ResourceDictionary follow the "key-value" parttern, for more information, you can refer to ResourceDictionary and XAML resource references . 您仅发布了转换器的代码和xaml代码的一部分,我无法100%复制数据模型和xaml,但是从您的代码中,我认为在转换器中,您想返回特定的DataTemplate ,但是您实际上返回了一个KeyValuePair<object, object> ,资源在ResourceDictionary中定义,并遵循“键值”部分,有关更多信息,您可以参考ResourceDictionary和XAML资源引用

Here I wrote a sample, again I didn't 100% reproduce your xaml and data model: 在这里,我写了一个示例,再次我没有100%复制您的xaml和数据模型:

MainPage.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>

code behind: 后面的代码:

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 });
}

My EquipmentType class is quite simple: 我的EquipmentType类非常简单:

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

and EquipmentTemplateConverter is like this: 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();
    }
}

Since you are using Application.Resources property in your converter, I just put the DataTemplate in the App.xaml for test: 由于您在转换器中使用Application.Resources属性 ,因此我只将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>

But I agree with @Ed Plunkett, using DataTemplateSelector is a more common way to do this work. 但是我同意@Ed Plunkett的观点,使用DataTemplateSelector是完成这项工作的更常见方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM