I have a custom WPF control that has a dependency property of type Pen
(used to style a dividing line within the control).
The default value of this property is supposed to be a system color -- and if this default value is used, the control must update when the user changes the system colors (in Windows settings).
So far, I have specified this default value as part of the default control style:
<Style TargetType="{x:Type my:Control}">
<Setter Property="DividerPen">
<Pen Brush="{DynamicResource {x:Static SystemColors.ActiveBorderBrushKey}}"
Thickness="1"/>
</Setter>
...
</Style>
This works fine as long as my control is only used by a single UI thread. However, when the control is used in multiple top-level windows that run in separate UI threads, the following exception occurs:
System.Windows.Markup.XamlParseException: Cannot access Freezable 'System.Windows.Media.Pen' across threads because it cannot be frozen.
---> System.InvalidOperationException: Cannot access Freezable 'System.Windows.Media.Pen' across threads because it cannot be frozen.
at System.Windows.StyleHelper.ProcessInstanceValuesHelper(ItemStructList`1& valueLookupList, DependencyObject target, Int32 childIndex, HybridDictionary instanceValues, Boolean apply)
at System.Windows.StyleHelper.ProcessInstanceValuesForChild(DependencyObject container, DependencyObject child, Int32 childIndex, HybridDictionary instanceValues, Boolean apply, FrugalStructList`1& childRecordFromChildIndex)
at System.Windows.StyleHelper.CreateInstanceData(UncommonField`1 dataField, DependencyObject container, FrameworkElement fe, FrameworkContentElement fce, Style newStyle, FrameworkTemplate newFrameworkTemplate)
...
Apparently, using a dynamic resource within the <Pen>
instance prevents the style from being frozen.
So far, I can think of two solutions:
1) Set x:Shared="False"
on the style. Every control instance gets its own copy of the default style, so it doesn't have to be frozen. However, the style has a few other setters (including a nontrivial template), so I'd prefer if those could be shared across multiple instances of my control.
2) Split the property of type Pen
into separate properties for brush, thickness, dash style etc. This would cause the {DynamicResource}
to be used directly in the style's setter, which then allows the style to be frozen. (though I'm not sure on the exact details of when a style is freezable)
This solution isn't desirable as I have multiple properties of type Pen, and each of those has quite a few properties that a user might want to customize. Also, I'd like to fix this exception without introducing breaking changes in the public API of my control.
Any other ideas? Is there some other way to specify this kind of default value for the DividerPen property?
Since there seems to be some confusion about what I mean by multiple UI threads, here's the code that opens a new window in its own thread:
public void OpenNewWindow()
{
Thread t = new Thread(new ThreadStart(Run));
t.SetApartmentState(ApartmentState.STA);
t.Start();
}
void Run()
{
var window = new Window();
window.Content = new MyUserControl();
window.Show();
// just for test purposes; a real multithreaded WPF app needs logic to shutdown the dispatcher when the window is closed
Dispatcher.Run();
}