【问题标题】:Using generics in XAML: WPF在 XAML 中使用泛型:WPF
【发布时间】:2022-12-23 14:09:54
【问题描述】:

我正在尝试在我的代码中使用 x:TypeArguments,以便我可以在 XAML 中使用泛型。它是如何被使用的一个例子是:

<ComboBoxItem>
    <local:CustomKeyValuePair x:TypeArguments="x:String, x:String"
                              Key="Label To Show 01"
                              Value="Content To Show 01" />
</ComboBoxItem>

但是,我收到了错误

错误 MC6022:只有根标记可以指定属性“x:TypeArguments”。第 34 行第 43 位。

我还尝试在文件顶部使用 xmlns:x="http://schemas.microsoft.com/netfx/2009/xaml/presentation" 而不是 http://schemas.microsoft.com/winfx/2006/xaml,但这给了我一个不同的错误

错误 MC3072:XML 命名空间“http://schemas.microsoft.com/netfx/2009/xaml/presentation”中不存在属性“Class”。第 1 行位置 9。

有什么办法可以在 WPF 中实现吗?


MCVE 所需代码

自定义键值对.cs

namespace GenericXamlMvce;

public record CustomKeyValuePair<K, V>
{
    public CustomKeyValuePair() { }

    public CustomKeyValuePair(K key, V value)
    {
        Key = key;
        Value = value;
    }

    public K Key { get; init; }

    public V Value { get; init; }

    public void Deconstruct(out K key, out V value)
    {
        key = Key;
        value = Value;
    }
}

主窗口.xaml

<Window x:Class="GenericXamlMvce.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:GenericXamlMvce"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>

        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>

        <TextBlock Grid.Column="0"
                               Grid.Row="0"
                               Text="Image: "
                               VerticalAlignment="Center"
                               Margin="5 0 2 0" />

        <ComboBox x:Name="DemoSelector"
                  Grid.Column="1"
                  Grid.Row="0"
                  SelectedIndex="0"
                  Margin="0 5 5 5"
                  DisplayMemberPath="Key"
                  SelectedValuePath="Value">
            <ComboBoxItem>
                <local:CustomKeyValuePair x:TypeArguments="x:String, x:String"
                                  Key="Label To Show 01"
                                  Value="Content To Show 01" />
            </ComboBoxItem>

            <ComboBoxItem>
                <local:CustomKeyValuePair x:TypeArguments="x:String, x:String"
                                          Key="Label To Show 02"
                                          Value="Content To Show 02" />
            </ComboBoxItem>
        </ComboBox>

        <TextBlock Grid.Column="0"
                   Grid.Row="1"
                   Grid.ColumnSpan="2"
                   Margin="10"
                   FontSize="20"
                   FontWeight="Bold"
                   Text="{Binding ElementName=DemoSelector, Path=SelectedValue}" />
    </Grid>
</Window>

【问题讨论】:

  • 不相关的注释:属性语法比标记语法更简洁:&lt;local:CustomKeyValuePair x:TypeArguments="x:String, x:String" Key="Label To Show 01" Value="Content To Show 01"/&gt;

标签: c# wpf xaml generics


【解决方案1】:

有什么办法可以在 WPF 中实现吗?

不,恐怕不会。

错误消息是正确的,因为只有根元素(例如 for example 窗口)可以指定 x:TypeArguments 属性。

为了能够在 XAML 中实例化和使用您的泛型 CustomKeyValuePair&lt;K, V&gt; 类型,您必须为类型参数的每个组合创建它的非泛型子类,例如:

public class StringIntCustomKeyValuePair : CustomKeyValuePair<string, int> { }

XAML:

<local:StringIntCustomKeyValuePair />

【讨论】:

  • 太可惜了。谢谢你的回答
【解决方案2】:

(翻译)

如果您愿意牺牲一些性能,请尝试反射。

XAML:

<Window x:Class="GenericXamlMvce.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:GenericXamlMvce"
        xmlns:s="clr-namespace:System;assembly=netstandard"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>

        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>

        <TextBlock Grid.Column="0"
                               Grid.Row="0"
                               Text="Image: "
                               VerticalAlignment="Center"
                               Margin="5 0 2 0" />

        <ComboBox x:Name="DemoSelector"
                  Grid.Column="1"
                  Grid.Row="0"
                  SelectedIndex="0"
                  Margin="0 5 5 5"
                  DisplayMemberPath="Key"
                  SelectedValuePath="Value">
            <ComboBoxItem>
                <local:CustomKeyValuePair K="{x:Type s:String}" 
                                          V="{x:Type s:String}" 
                                          Key="Label To Show 01"
                                          Value="Content To Show 01" />
            </ComboBoxItem>

            <ComboBoxItem>
                <local:CustomKeyValuePair K="{x:Type s:String}" 
                                          V="{x:Type s:String}" 
                                          Key="Label To Show 02"
                                          Value="Content To Show 02" />
            </ComboBoxItem>
        </ComboBox>

        <TextBlock Grid.Column="0"
                   Grid.Row="1"
                   Grid.ColumnSpan="2"
                   Margin="10"
                   FontSize="20"
                   FontWeight="Bold"
                   Text="{Binding ElementName=DemoSelector, Path=SelectedValue}" />
    </Grid>
</Window>

C#:

public record CustomKeyValuePair
{
    public CustomKeyValuePair()
    {
        KeyValuePair = Create(K, V, Key, Value);
    }

    public object Key { get; init; }
    public object Value { get; init; }

    public Type K { get; init; }
    public Type V { get; init; }

    public CustomKeyValuePairBase KeyValuePair { get; init; }

    public static CustomKeyValuePairBase Create(Type t, Type v, object key, object value)
    {
        if (t == null || v == null)
        {
            return null;
        }
        var type = typeof(CustomKeyValuePair<,>).MakeGenericType(t, v);
        var cctor = type.GetConstructor(new Type[] { t, v });
        return (CustomKeyValuePairBase)cctor.Invoke(new object[] { key, value });
    }
}

public record CustomKeyValuePairBase
{

}

public record CustomKeyValuePair<K, V> : CustomKeyValuePairBase
{
    public CustomKeyValuePair() { }

    public CustomKeyValuePair(K key, V value)
    {
        Key = key;
        Value = value;
    }

    public K Key { get; init; }

    public V Value { get; init; }

    public void Deconstruct(out K key, out V value)
    {
        key = Key;
        value = Value;
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-04
    • 2011-11-26
    相关资源
    最近更新 更多