MarkupExtension недопустимо для Setter.Value.Единственными поддерживаемыми типами MarkupExtension являются DynamicResourceExtension и BindingBase или производные типы. - PullRequest
0 голосов
/ 23 октября 2018

У меня есть пользовательские расширения разметки «ThemeExtension» для предоставления «SolidColorBrush» из моего DefaultTheme.xaml ResourceDictionary.

Пример вызова: BorderBrush="{extensions:Theme Key= FooKeyValue}"

Он работает без проблем во время выполнения, но ИНОГДА он начинает падать во время проектирования, и я больше не могу разрабатывать.Дизайнер разбился.Перестройте, Чистое решение, перезагрузка ОС больше не помогает.Если я изменю какое-то значение внутри кода XAML, оно будет работать ровно для одного рисунка!И после этого снова происходит сбой!

Предварительный просмотр

preview

XAML Stacktrace

bei System.Windows.Setter.Seal()
bei System.Windows.SetterBaseCollection.Seal()
bei System.Windows.Style.Seal()
bei System.Windows.StyleHelper.UpdateStyleCache(FrameworkElement fe, FrameworkContentElement fce, Style oldStyle, Style newStyle, Style& styleCache)
bei System.Windows.FrameworkElement.OnStyleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
bei System.Windows.DependencyObject.OnPropertyChanged(DependencyPropertyChangedEventArgs e)
bei System.Windows.FrameworkElement.OnPropertyChanged(DependencyPropertyChangedEventArgs e)
bei System.Windows.DependencyObject.NotifyPropertyChange(DependencyPropertyChangedEventArgs args)
bei System.Windows.DependencyObject.UpdateEffectiveValue(EntryIndex entryIndex, DependencyProperty dp, PropertyMetadata metadata, EffectiveValueEntry oldEntry, EffectiveValueEntry& newEntry, Boolean coerceWithDeferredReference, Boolean coerceWithCurrentValue, OperationType operationType)
bei System.Windows.DependencyObject.InvalidateProperty(DependencyProperty dp, Boolean preserveCurrentValue)
bei System.Windows.FrameworkElement.UpdateStyleProperty()
bei System.Windows.FrameworkElement.OnInitialized(EventArgs e)
bei System.Windows.Controls.Primitives.Selector.OnInitialized(EventArgs e)
bei System.Windows.FrameworkElement.TryFireInitialized()
bei System.Windows.FrameworkElement.EndInit()
bei System.Windows.Controls.ItemsControl.EndInit()
bei MS.Internal.Xaml.Runtime.ClrObjectRuntime.InitializationGuard(XamlType xamlType, Object obj, Boolean begin)

ThemeExtension.cs

[MarkupExtensionReturnType(typeof(Color))]
public class ThemeColorExtension : ThemeExtension
{
    internal override object ModifyThemeValue(object value)
    {
        if (value is SolidColorBrush solidColorBrush)
            return solidColorBrush.Color;
        return value;
    }
}

[MarkupExtensionReturnType(typeof(SolidColorBrush))]
public class ThemeExtension : MarkupExtension
{
    // ##############################################################################################################################
    // Properties
    // ##############################################################################################################################

    #region Properties

    // ##########################################################################################
    // Public Properties
    // ##########################################################################################

    /// <summary>
    /// The Key in the Resource Theme file
    /// </summary>
    public string Key { get; set; }

    // ##########################################################################################
    // Private Properties
    // ##########################################################################################

    private static readonly List<ThemeExtension> _Cache = new List<ThemeExtension>();
    private static readonly ResourceDictionary _DefaultTheme;
    private static ResourceDictionary _CurrentTheme;

    private PropertyInfo _Property { get; set; }
    private DependencyProperty _DependencyProperty { get; set; }
    private WeakReference _TargetReference { get; set; }

    #endregion

    // ##############################################################################################################################
    // Constructor
    // ##############################################################################################################################

    #region Constructor

    static ThemeExtension()
    {
        _DefaultTheme = new ResourceDictionary
        {
            Source = new Uri("/HtPlcFramework;component/Themes/DefaultTheme.xaml", UriKind.Relative)
        };
        _CurrentTheme = _DefaultTheme;

        NavigationService.Navigated += _OnNavigated;
    }

    public ThemeExtension() { }

    #endregion

    // ##############################################################################################################################
    // public methods
    // ##############################################################################################################################

    #region public methods

    /// <summary>
    /// https://social.msdn.microsoft.com/Forums/vstudio/en-US/931d7bff-90b6-4a70-bb0b-3a097e1301a1/net-40-breaking-change-using-a-markup-extension-as-value-of-property-setter-in-xaml-style?forum=wpf
    /// </summary>
    /// <param name="serviceProvider"></param>
    /// <returns></returns>
    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        IProvideValueTarget target = serviceProvider.GetService(typeof(IProvideValueTarget)) as IProvideValueTarget;
        if (target == null)
            return this;

        if (target.TargetObject != null && target.TargetProperty != null)
        {
            _TargetReference = new WeakReference(target.TargetObject);
            if (target.TargetProperty.GetType() == typeof(PropertyInfo))
            {
                _Property = (PropertyInfo)target.TargetProperty;
            }
            else if (target.TargetProperty is DependencyProperty)
            {
                _DependencyProperty = (DependencyProperty)target.TargetProperty;
            }
        }

        if (!_Cache.Contains(this))
            _Cache.Add(this);

        return ModifyThemeValue(_ReadThemeKey(Key));
    }

    /// <summary>
    /// Change the Theme set
    /// </summary>
    /// <param name="themeUri">Default is: new Uri("/HtPlcFramework;component/Themes/DefaultTheme.xaml", UriKind.Relative)</param>
    public static void ChangeTheme(Uri themeUri)
    {
        _CurrentTheme = new ResourceDictionary { Source = themeUri };

        foreach (ThemeExtension reference in _Cache)
        {
            reference._UpdateTheme();
        }
    }

    /// <summary>
    /// Get the current theme entry. Can be null!
    /// </summary>
    /// <param name="key"></param>
    /// <returns></returns>
    public static object ReadThemeKey(string key) => _ReadThemeKey(key);

    internal virtual object ModifyThemeValue(object value)
    {
        return value;
    }

    #endregion

    // ##############################################################################################################################
    // private methods
    // ##############################################################################################################################

    #region private methods

    private static void _OnNavigated(object sender, string layer)
    {
        _Cache.RemoveAll(ti => !ti._TargetReference.IsAlive);
    }

    private static object _ReadThemeKey(string key)
    {
        try
        {
            return _CurrentTheme[key] ?? _DefaultTheme[key];
        }
        catch (Exception)
        {
            Trace.WriteLine($"The key '{key}' was not found in {_CurrentTheme.Source}!");
            return null;
        }
    }

    private void _UpdateTheme()
    {
        if (_TargetReference.IsAlive)
        {
            if (_Property != null)
                _Property.GetSetMethod().Invoke(_TargetReference.Target, new object[] { _ReadThemeKey(Key) });
            else if (_DependencyProperty != null)
            {
                DependencyObject dependencyObject = _TargetReference.Target as DependencyObject;
                dependencyObject?.SetValue(_DependencyProperty, _ReadThemeKey(Key));
            }
        }
        else
        {
            _Cache.Remove(this);
        }
    }

    #endregion

} 

Связанное сообщение сообщества разработчиков VStudio

https://developercommunity.visualstudio.com/content/problem/364029/foomarkupextension-is-not-valid-for-settervalue-th.html

Связанное сообщение без решения

{0} недопустимо для Setter.Значение.Единственными поддерживаемыми типами MarkupExtension являются DynamicResourceExtension и BindingBase или производные типы

VS2010 Custom MarkupExtension


На следующем веб-сайте приведен пример «Разметка»Расширение ":

https://dzone.com/articles/extend-wpf-add-your-own-keywor (Загрузить пример проекта http://raasiel.typepad.com/MyXamlExtensions.zip)

Если я запусту этот пример, я получу также это исключение, вызывающее раздражение! Так что, возможно, это проблема VisualStudio.

...