【问题标题】:Select ItemTemplate in value converter在值转换器中选择 ItemTemplate
【发布时间】:2016-05-20 14:37:04
【问题描述】:

我试图根据每个项目属性在列表视图中拥有多个 ItemTemplates。但我不断收到 {"Error HRESULT E_FAIL has been returned from a call to a COM component."} 在我的值转换器中:

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>

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

【问题讨论】:

    标签: c# xaml uwp


    【解决方案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;
        }
    }
    

    【讨论】:

    • 我在 Application.Current 中没有 MainWindow 属性,因为我正在制作 Windows 10 应用程序。
    【解决方案2】:

    但我在值转换器中不断收到 {"Error HRESULT E_FAIL has been returned from a call to a COM component."}。

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

    您仅发布了转换器的代码和部分 xaml 代码,我无法 100% 复制您的数据模型和 xaml,但是从您的代码中,我认为在您的转换器中,您希望返回特定的DataTemplate,但你实际上返回了一个KeyValuePair&lt;object, object&gt;,资源在ResourceDictionary中定义,遵循“key-value”部分,更多信息可以参考ResourceDictionary and XAML resource references

    我在这里写了一个示例,我再次没有 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 是完成这项工作的更常见方式。

    【讨论】:

      猜你喜欢
      • 2013-03-12
      • 2011-02-05
      • 1970-01-01
      • 2016-08-14
      • 1970-01-01
      • 2018-05-12
      • 2017-07-02
      • 2016-02-25
      • 1970-01-01
      相关资源
      最近更新 更多