简体   繁体   English

XAML 设计器无法解析枚举类型,“base.enum”到“mocks.enum_”

[英]XAML Designer unable to resolve Enum types, 'base.enum' to 'mocks.enum_'

I have a C#/WPF MVVM program that uses a flagged enum to track the types of search mode the user is currently in and to manipulate the background colors of various controls depending on the given search modes.我有一个 C#/WPF MVVM 程序,它使用带标记的枚举来跟踪用户当前所处的搜索模式类型,并根据给定的搜索模式操纵各种控件的背景颜色。 I am using an enum-to-bool converter with a property to indicate if the enum should be treated as a flag.我正在使用带有属性的枚举到布尔转换器来指示枚举是否应被视为标志。

The enum枚举

namespace EnumNamespace.Enums
{
    /// <summary>
    /// Flag enabled enumeration values for the various search modes.
    /// </summary>
    [Flags]
    public enum ESearchMode
    {
        None = 0,
        RegionSearch = 1,
        ValueSearch = 2,
        CombinedSearch = RegionSearch | ValueSearch
    }
}

In my resource dictionary I have在我的资源词典中,我有

<pluginConverters:EnumToBoolConverter 
    x:Key="FlaggedEnumToBoolConverter"
    TreatAsFlag="True"
    Match="True"
    NoMatch="False"/>

Example use of my converter in XAML我的转换器在 XAML 中的使用示例

<TextBox.Resources>
    <Style
        TargetType="TextBox">

        <Style.Triggers>
            <DataTrigger
                Binding="{Binding ActiveSearchMode, 
                  UpdateSourceTrigger=PropertyChanged, 
                  Converter={StaticResource FlaggedEnumToBoolConverter}, 
                  ConverterParameter={x:Static enums:ESearchMode.ValueSearch}}"
                Value="True">

                <Setter
                    Property="Background"
                    Value="{StaticResource SearchBackgroundColor}" />

            </DataTrigger>
        </Style.Triggers>
    </Style>
</TextBox.Resources>

And finally, the converter itself最后,转换器本身

public abstract class EnumConverter<T> : IValueConverter
{
    /// <summary>
    /// When True uses the Enum.HasFlag() comparator.
    /// When False uses Equals() comparator.
    /// </summary>
    public bool TreatAsFlag { get; set; }
    /// <summary>
    /// Object to return if the enum matches.
    /// </summary>
    public T Match { get; set; }
    /// <summary>
    /// Object to return if the enum doesn't match
    /// </summary>
    public T NoMatch { get; set; }

    protected EnumConverter(T match, T noMatch)
    {
        Match = match;
        NoMatch = noMatch;
        TreatAsFlag = false;
    }

    public virtual object Convert(object value, Type targetType, object trueValue, CultureInfo culture)
    {
        //Ensure both types are valid.
        if (value != null && trueValue != null && value.GetType().IsEnum)
        {
            if (TreatAsFlag)
                return ((Enum) value).HasFlag((Enum) trueValue) ? Match : NoMatch;

            return Equals(value, trueValue) ? Match : NoMatch;
        }

        //Do not perform binding if input was invalid.
        return DependencyProperty.UnsetValue;
    }

    public virtual object ConvertBack(object value, Type targetType, object trueValue, CultureInfo culture)
    {
        //Refer to implementation since we need to know the base class type to convert back. (If we can)
        throw new NotImplementedException();
    }
}

/// <summary>
/// Allows conversion from enumerations to booleans.  Can only convert back for matches since non matches could be any enum.
/// Example: <converters:EnumToBoolConverter x:Key="TrueIfEnumMatches" Match="True" NoMatch="False"/>
/// </summary>
public class EnumToBoolConverter : EnumConverter<bool>
{
   public EnumToBoolConverter() : base(true, false) { }

   public override object ConvertBack(object value, Type targetType, object trueValue, CultureInfo culture)
    {
        //If being set to true then we know the enum to return.
        if (value is bool val && val)
            return trueValue;

        //Otherwise we can't go backwards since false could be any other enum.
        return Binding.DoNothing;
    }
}

My problem is the designer throws an argument exception and won't draw anymore.我的问题是设计者抛出一个参数异常并且不再绘制。 I can still run the program and the logic works great, but I can't view the designer, which is less than ideal for obvious reasons.我仍然可以运行该程序并且逻辑运行良好,但我无法查看设计器,由于显而易见的原因,这不太理想。 The designer window gives me the following error:设计器窗口给我以下错误:

The argument type, 'EnumNamespace.Enums.ESearchMode', is not the same as the enum type 'Mocks.EnumNamespace_Enums_ESearchMode_8_18537287'参数类型“EnumNamespace.Enums.ESearchMode”与枚举类型“Mocks.EnumNamespace_Enums_ESearchMode_8_18537287”不同

The stacktrace points me to my HasFlag check here:堆栈跟踪指向我的 HasFlag 检查:

return ((Enum) value).HasFlag((Enum) trueValue) ? Match : NoMatch;

This is the first time I have seen a 'Mocks._' type and assume it is part of the designer's background magic in order to process and show what's in the XAML.这是我第一次看到“Mocks._”类型,并假设它是设计者的背景魔法的一部分,以便处理和显示 XAML 中的内容。 I would assume there is information out there on the interwebs about how the designer runs its code to resolve types, but I have been unable to find anything that describes this particular issue.我假设互联网上有关于设计者如何运行其代码来解析类型的信息,但我一直无法找到任何描述此特定问题的信息。 I don't understand why the designer would be passing my actual enum type, but also it's mocked version as well.我不明白为什么设计师会传递我的实际枚举类型,但它也是模拟版本。 Is this an error or known limitation in the designer code?这是设计器代码中的错误或已知限制吗? Does it have to do with how I'm passing in the converter parameter?它与我传递转换器参数的方式有关吗? To add to the confusion, I am using this converter with flagged-enums in another view without any issues with the designer.更令人困惑的是,我在另一个视图中使用带有标记枚举的转换器,而设计器没有任何问题。

I would love for someone to point me to some information about Mocks and how the designer uses them as well as if anyone has any insights into why the designer isn't using the mocked version of my enum for both the bound property and the converter parameter.我希望有人能向我指出一些关于 Mocks 的信息以及设计者如何使用它们,以及是否有人对为什么设计者没有对绑定属性和转换器参数使用我的枚举的模拟版本有任何见解. If there is an obvious solution/workaround to my exception, I'd be open to that too.如果我的异常有明显的解决方案/解决方法,我也会对此持开放态度。

I haven't found a good document describing the designers use of mocks, but I have at least found a work around to my issue.我还没有找到描述设计师使用模拟的好文档,但我至少找到了解决我的问题的方法。

Using information found here I was able to debug the designer a bit a find that the bound value was being passed in as the 'Mocks.Enum_" and the converter parameter, 'trueValue', was correctly being passed as my enum type. This makes sense given I am passing a static reference to it. The fact that the bound variable is the cause of the problem suggests it is something to do with the design time data context I am assigning for this view. Setting my DataContext design instance使用此处找到的信息,我能够对设计器进行一些调试,发现绑定值作为“Mocks.Enum_”传入,并且转换器参数“trueValue”作为我的枚举类型正确传递。这使得鉴于我正在传递对它的静态引用。绑定变量是问题原因的事实表明它与我为此视图分配的设计时数据上下文有关。设置我的 DataContext 设计实例

IsDesignTimeCreatable=True

Seems to fix the issue without needing to make other code changes.似乎无需更改其他代码即可解决问题。

Alternatively, after reading the accepted solution on this question , I realized I could convert my Enum to its unsigned long value and do bitwise operations on it to check for my flag.或者,在阅读了关于这个问题的公认解决方案之后,我意识到我可以将我的 Enum 转换为其无符号长值并对其进行按位运算以检查我的标志。 My convert function now looks like this:我的转换函数现在看起来像这样:

public virtual object Convert(object value, Type targetType, object trueValue, CultureInfo culture)
{
    //Ensure both types are valid.
    if (value != null && trueValue != null && value.GetType().IsEnum)
    {
        if (TreatAsFlag)
        {
            // Due to the designer having issues sometimes resolving enums with using the 'HasFlag' function, we will convert our enums to ulongs to compare using bitwise operations 
            // Set our enums as ulong values so we can perform bitwise operations
            ulong setValues = System.Convert.ToUInt64(value);
            ulong setTrueValues = System.Convert.ToUInt64(trueValue);

            // Compare our value with the flag we are checking against
            return (setValues & setTrueValues) == setTrueValues;
        }

        return Equals(value, trueValue) ? Match : NoMatch;
    }

    //Do not perform binding if input was invalid.
    return DependencyProperty.UnsetValue;
}

Neither of these solutions explains why the designer isn't able to properly resolve my bound value to its actual enum type.这些解决方案都无法解释为什么设计者无法将我的绑定值正确解析为其实际枚举类型。

Still open to any other input on Mocks and the designer.仍然对 Mocks 和设计师的任何其他输入持开放态度。

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

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