我有一个定制的标记扩展"ThemeExtension“来提供来自我的DefaultTheme.xaml ResourceDictionary的"SolidColorBrush”。
调用示例:BorderBrush="{extensions:Theme Key= FooKeyValue}"
它在运行时运行时没有任何问题,但有时它在设计时开始崩溃,我无法再进行开发了。设计师崩溃了。重建,清洁解决方案,操作系统重新启动不再有帮助。如果我在XAML代码中更改了一些值,它就是为1张绘图而工作的!在那之后它又坠毁了!
预览
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://dzone.com/articles/extend-wpf-add-your-own-keywor (下载项目示例http://raasiel.typepad.com/MyXamlExtensions.zip)
如果我运行这个例子,我也会得到这个异常!因此,也许这是VisualStudio的一个问题。
发布于 2020-05-28 00:11:40
感谢Michael,因为他为我指明了正确的方向
如您所见(https://referencesource.microsoft.com/#PresentationFramework/src/Framework/System/Windows/Setter.cs,123),在Setter
中只允许DynamicResourceExtension
作为MarkupExtension
。
因此,为了处理这个*错误消息:
MarkupExtension
更改为DynamicResourceExtension
foo
资源密钥(只是为了绕过ArgumentNullException
;参见https://referencesource.microsoft.com/#PresentationFramework/src/Framework/System/Windows/DynamicResourceExtension.cs,43)[MarkupExtensionReturnType(typeof(SolidColorBrush))]
public class ThemeExtension : DynamicResourceExtension
{
...
public ThemeExtension() : base("foo")
{
}
...
}
https://stackoverflow.com/questions/52946703
复制