这个有点奇怪。 从wpf的主窗口(点击按钮),我正在创建另一个STA线程,我正在显示一个自定义窗口。此自定义窗口应用了一个使用shell中的WindowChrome类的样式。 调用Show()方法时出现异常。
无法访问Freezable'System.Windows.Shell.WindowChrome' 线程,因为它不能被冻结。
如果我删除WindowChrome设置器,一切正常。 我错过了什么?
我已经尝试将窗口镀铬标记为冻结,但是徒劳无功!
该来源的副本可用here。
更新 忘记提到在样式上添加x:Shared =“False”似乎解决了问题,但我不知道为什么!这会导致任何性能瓶颈吗?
MainWindow.xaml:
<Window x:Class="WpfApplication7.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication7"
Title="MainWindow"
Height="350"
Width="525" Style="{StaticResource ResourceKey=WindowStyle}">
<Grid>
<Button Content="Open another window please..."
Click="Button_Click" />
</Grid>
</Window>
MainWindow.xaml.cs:
using System.Threading;
using System.Windows;
namespace WpfApplication7
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
Thread windowThread = new Thread(new ThreadStart(() =>
{
Window customWindow = new BackgroundWindow();
customWindow.Closed += (s, a) => System.Windows.Threading.Dispatcher.CurrentDispatcher.BeginInvokeShutdown(System.Windows.Threading.DispatcherPriority.Background);
customWindow.Show();
System.Windows.Threading.Dispatcher.Run();
}));
windowThread.IsBackground = true;
windowThread.SetApartmentState(ApartmentState.STA);
windowThread.Start();
}
}
}
BackgroundWindow.xaml:
<Window x:Class="WpfApplication7.BackgroundWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication7"
Title="BackgroundWindow"
WindowStartupLocation="CenterScreen"
Style="{StaticResource ResourceKey=WindowStyle}">
</Window>
WindowStyle.xaml(与App.xaml合并
<!-- Setting x:Shared=False will solve the cross threaded exception -->
<Style x:Key="WindowStyle"
TargetType="{x:Type Window}">
<Setter Property="Padding"
Value="5,5,5,5" />
<Setter Property="BorderBrush"
Value="Black" />
<Setter Property="BorderThickness"
Value="1" />
<Setter Property="WindowChrome.WindowChrome">
<Setter.Value>
<WindowChrome CaptionHeight="44"
GlassFrameThickness="-1"
CornerRadius="0,0,0,0" />
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Window}">
<Border Background="{TemplateBinding Property=Background}"
BorderBrush="{TemplateBinding Property=BorderBrush}"
BorderThickness="{TemplateBinding Property=BorderThickness}">
<Grid Background="{TemplateBinding Property=Background}"
UseLayoutRounding="True"
SnapsToDevicePixels="True">
<Grid.RowDefinitions>
<!-- Window Controls -->
<RowDefinition Height="44" />
<!-- Content -->
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<DockPanel x:Name="PART_DragPanel"
Grid.Row="0"
Background="Black">
<Button x:Name="PART_CloseButton"
DockPanel.Dock="Right"
HorizontalAlignment="Right"
Margin="3,8,8,8"
WindowChrome.IsHitTestVisibleInChrome="True"
Width="20"
Height="20" />
<Button x:Name="PART_RestoreButton"
DockPanel.Dock="Right"
HorizontalAlignment="Right"
Margin="3,8,3,8"
Visibility="Collapsed"
WindowChrome.IsHitTestVisibleInChrome="True"
Width="20"
Height="20" />
<Button x:Name="PART_MinimizeButton"
DockPanel.Dock="Right"
HorizontalAlignment="Right"
Margin="3,8,3,8"
Visibility="Collapsed"
WindowChrome.IsHitTestVisibleInChrome="True"
Width="20"
Height="20" />
<TextBlock x:Name="PART_Title"
DockPanel.Dock="Left"
Margin="8,8,8,8"
Text="{TemplateBinding Property=Title}"
IsHitTestVisible="False"
WindowChrome.IsHitTestVisibleInChrome="True" />
</DockPanel>
<Border x:Name="contentBorder"
Grid.Row="1"
Padding="{TemplateBinding Property=Padding}">
<AdornerDecorator>
<ContentPresenter />
</AdornerDecorator>
</Border>
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="ResizeMode"
Value="CanMinimize">
<Setter TargetName="PART_MinimizeButton"
Property="Visibility"
Value="Visible" />
</Trigger>
<Trigger Property="ResizeMode"
Value="NoResize">
<Setter TargetName="PART_RestoreButton"
Property="Visibility"
Value="Collapsed" />
<Setter TargetName="PART_MinimizeButton"
Property="Visibility"
Value="Collapsed" />
</Trigger>
<Trigger Property="ResizeMode"
Value="CanResize">
<Setter TargetName="PART_RestoreButton"
Property="Visibility"
Value="Visible" />
<Setter TargetName="PART_MinimizeButton"
Property="Visibility"
Value="Visible" />
</Trigger>
<Trigger Property="ResizeMode"
Value="CanResizeWithGrip">
<Setter TargetName="PART_RestoreButton"
Property="Visibility"
Value="Visible" />
<Setter TargetName="PART_MinimizeButton"
Property="Visibility"
Value="Visible" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="ResizeMode"
Value="CanResize">
<Setter Property="WindowChrome.ResizeBorderThickness"
Value="5,5,5,5" />
</Trigger>
<Trigger Property="ResizeMode"
Value="CanResizeWithGrip">
<Setter Property="WindowChrome.ResizeBorderThickness"
Value="5,5,5,5" />
</Trigger>
<Trigger Property="ResizeMode"
Value="NoResize">
<Setter Property="WindowChrome.ResizeBorderThickness"
Value="0,0,0,0" />
</Trigger>
</Style.Triggers>
</Style>
答案 0 :(得分:2)
问题的根源在于你这样做:
<Setter Property="WindowChrome.WindowChrome">
<Setter.Value>
<WindowChrome CaptionHeight="44"
GlassFrameThickness="-1"
CornerRadius="0,0,0,0" />
</Setter.Value>
</Setter>
值(本例中为WindowChrome
实例)创建一次,并在构造时保留为样式。每次将样式应用于控件时,它都不会创建新实例。首先,您将样式应用于主窗口。此时,样式是从xaml创建的,因此创建了WindowChrome实例。当您从另一个线程将样式应用于背景窗口时 - 未重新创建样式,则使用已创建的Style
实例。我们注意到样式设置器包含在另一个线程中创建的值,该值是可冻结的但未冻结 - 因此它会因异常而失败,因为它被认为是危险的(并且无论如何都无法工作,因为您无法分配在另一个线程中创建的WindowChrome实例到你的BackgroundWindow,也不能克隆它。)
当您对样式应用x:Shared=False
时,会在每个请求上创建Style
的新实例,从而避免出现问题(因为对于每个Style实例也会创建新的WindowChrome实例)。另一种强迫新情况的方法是:
<WindowChrome x:Key="chrome" x:Shared="False"
CaptionHeight="44"
GlassFrameThickness="-1"
CornerRadius="0,0,0,0" />
<Style ...>
<Setter Property="WindowChrome.WindowChrome" Value="{DynamicResource chrome}"/>
</Style>
只有在没有其他办法时才使用多个UI线程,因为它们可能很棘手。