代码之家  ›  专栏  ›  技术社区  ›  Dominic Jonas

MarkupExtension对Setter.Value无效。唯一受支持的MarkupExtension类型是DynamicResourceExtension和BindingBase或派生类型

  •  0
  • Dominic Jonas  · 技术社区  · 7 年前

    我有一个自定义标记扩展名“ThemeExtension”,从我的DefaultTheme.xaml ResourceDictionary中提供“solidcolorbush”。

    调用示例: BorderBrush="{extensions:Theme Key= FooKeyValue}"

    预览

    preview

    XAML堆栈跟踪

    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)
    

    主题扩展.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} is not valid for Setter.Value. The only supported MarkupExtension types are DynamicResourceExtension and BindingBase or derived types

    VS2010 Custom MarkupExtension


    以下网站是“标记扩展”的一个示例:

    https://dzone.com/articles/extend-wpf-add-your-own-keywor (下载项目示例 http://raasiel.typepad.com/MyXamlExtensions.zip )

    如果我运行这个示例,我也会得到这个注释异常!所以这可能是VisualStudio的问题。

    0 回复  |  直到 7 年前