I have a custom markup extensions "ThemeExtension" to provide "SolidColorBrush" from my DefaultTheme.xaml ResourceDictionary.
Calling example: BorderBrush="{extensions:Theme Key= FooKeyValue}"
It is working without any problems on runtime, but SOMETIMES it starting to crash during design time and I can't develop anymore. The designer is crashed. Rebuild, Clean Solution, OS Restart is NOT helping anymore. If I change some value inside of the XAML code it is working for exactly for 1 drawing! And after that it crashes again!
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
}
Related VStudio Developer Community post
Related post with no solution
On the following website is an example of a "Markup Extension":
https://dzone.com/articles/extend-wpf-add-your-own-keywor (Download project example http://raasiel.typepad.com/MyXamlExtensions.zip)
If I run this example, I get also this annyoing exception! So maybe it is a problem with VisualStudio.
this
fromProvideValue
? I'm not sure if it's the cause of the problem, but it seems really odd for a markup extension to return its self rather than an instance of some other object that it translated. β StranderStacktrace
for more details. Returnthis
was a solution approach on a msdn forum. And it helped for some weeks. But know the problems starts again. Returnnull
instead ofthis
gives the same error. Btw. I have tried to debug theXAML exception
(https://mcmap.net/q/1913593/-how-can-i-debug-xaml-designer-issues) and thetarget
was always!= null
. β AcceleratorDynamicResourceExtension
! πππππ β Accelerator