我有LoadingScreen
分隔Thread
:
public partial class LoadingScreen : Window
{
#region Variables
private static Thread _thread;
private static LoadingScreen _loading;
private static bool _isIndeterminate;
#endregion
public LoadingScreen()
{
InitializeComponent();
}
#region Methods
public static void ShowSplash(bool isIndeterminate = false)
{
_isIndeterminate = isIndeterminate;
_thread = new Thread(OpenSplash)
{
IsBackground = true,
Name = "Loading"
};
_thread.SetApartmentState(ApartmentState.STA);
_thread.Start();
}
private static void OpenSplash()
{
_loading = new LoadingScreen();
_loading.ProgressBar.IsIndeterminate = _isIndeterminate;
_loading.ShowDialog();
_loading.Dispatcher.Invoke(new Action(Dispatcher.Run));
}
public static void CloseSplash()
{
if (_loading == null || _thread == null)
return;
_loading.Dispatcher.Invoke(new Action(() => { _loading.Close(); }));
_loading.Dispatcher.InvokeShutdown();
_loading = null;
}
public static void Update(int value, string description)
{
Update((double)value, description);
}
public static void Update(double value, string description)
{
if (_loading == null)
return;
_loading.Dispatcher.Invoke((Action)delegate
{
var da = new DoubleAnimation(value, new Duration(TimeSpan.FromMilliseconds(Math.Abs(_loading.ProgressBar.Value - value) * 12)))
{
EasingFunction = new PowerEase { Power = 3 }
};
_loading.ProgressBar.BeginAnimation(RangeBase.ValueProperty, da);
_loading.TextBlock.Text = description;
});
}
public static void Status(bool isIndeterminate)
{
if (_loading == null)
return;
_loading.Dispatcher.Invoke((Action)delegate
{
_loading.ProgressBar.IsIndeterminate = isIndeterminate;
});
}
#endregion
private void SplashScreen_OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
DragMove();
}
private void RestoreButton_OnClick(object sender, RoutedEventArgs e)
{
_loading.Dispatcher.Invoke((Action)delegate
{
if (_loading.MiddleRowDefinition.Height == new GridLength(1, GridUnitType.Star))
{
_loading.MiddleRowDefinition.Height = new GridLength(0);
_loading.RestoreButton.Content = "R";
_loading.Height = 69;
}
else
{
_loading.MiddleRowDefinition.Height = new GridLength(1, GridUnitType.Star);
_loading.RestoreButton.Content = "A"; //I removed my vector to test.
_loading.Height = 200;
}
});
}
private void MinimizeButton_OnClick(object sender, RoutedEventArgs e)
{
_loading.Dispatcher.Invoke((Action)delegate
{
_loading.WindowState = WindowState.Minimized;
});
}
}
的Xaml:
<Window x:Class="MySoftware.Util.LoadingScreen"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Bem Vindo" Height="200" Width="400" Topmost="True"
WindowStartupLocation="CenterScreen" WindowStyle="None" ResizeMode="NoResize"
MouseLeftButtonDown="SplashScreen_OnMouseLeftButtonDown">
<Window.Resources>
<Storyboard x:Key="ShowStoryBoard">
<DoubleAnimation Storyboard.TargetProperty="Opacity" From="0.0" To="1.0" Duration="0:0:5">
<DoubleAnimation.EasingFunction>
<BackEase Amplitude="2" EasingMode="EaseIn"/>
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
</Storyboard>
<Storyboard x:Key="HideStoryBoard">
<DoubleAnimation Storyboard.TargetProperty="Opacity" From="1" To="0" Duration="0:0:5">
<DoubleAnimation.EasingFunction>
<PowerEase Power="4" EasingMode="EaseIn"/>
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
</Storyboard>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="30"/>
<RowDefinition x:Name="MiddleRowDefinition"/>
<RowDefinition Height="21"/>
<RowDefinition Height="18"/>
</Grid.RowDefinitions>
<Grid.Background>
<RadialGradientBrush Center="0.5,1.3" GradientOrigin="0.5,1.1">
<RadialGradientBrush.RelativeTransform>
<TransformGroup>
<ScaleTransform CenterY="0.5" CenterX="0.5" ScaleY="0.75" ScaleX="0.8"/>
<SkewTransform CenterY="0.5" CenterX="0.5"/>
<RotateTransform CenterY="0.5" CenterX="0.5"/>
<TranslateTransform x:Name="TranslateTransform" X="-0.5"/>
</TransformGroup>
</RadialGradientBrush.RelativeTransform>
<GradientStop Color="#FFE2E1EE" Offset="0.1"/>
<GradientStop Color="#FF70A6C8" Offset="1"/>
</RadialGradientBrush>
</Grid.Background>
<StackPanel Grid.Row="0" Orientation="Horizontal" HorizontalAlignment="Right" Height="30">
<StackPanel.Resources>
<Style TargetType="{x:Type Button}" x:Key="WindowButtonStyle">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ButtonBase}">
<Border x:Name="Chrome" BorderBrush="{TemplateBinding BorderBrush}"
Margin="0" Background="{TemplateBinding Background}"
SnapsToDevicePixels="True">
<Viewbox MaxHeight="15" MaxWidth="15" Stretch="Uniform">
<ContentPresenter ContentTemplate="{TemplateBinding ContentTemplate}"
Content="{TemplateBinding Content}"
ContentStringFormat="{TemplateBinding ContentStringFormat}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
Margin="{TemplateBinding Padding}"
RecognizesAccessKey="True"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
</Viewbox>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<!--Default Values-->
<Setter Property="Background" Value="Transparent"/>
<Setter Property="FontSize" Value="16" />
<Setter Property="Foreground" Value="Black" />
<Setter Property="Margin" Value="0,0,5,0"/>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="#60FFFFFF" />
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Background" Value="#90FFFFFF" />
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Opacity" Value=".6"/>
<Setter Property="Effect" Value="{x:Null}"/>
</Trigger>
</Style.Triggers>
</Style>
</StackPanel.Resources>
<Button x:Name="MinimizeButton" Style="{StaticResource WindowButtonStyle}"
Content="--" Width="30" Margin="0" Height="30"
Click="MinimizeButton_OnClick"
ToolTip="Minimize" ToolTipService.Placement="Top"/>
<Button x:Name="RestoreButton" Style="{StaticResource WindowButtonStyle}"
Content="R" Width="30" Margin="0" Height="30"
Click="RestoreButton_OnClick"
ToolTip="Restore" ToolTipService.Placement="Top"/>
</StackPanel>
<Image Grid.Row="1" Stretch="Uniform" StretchDirection="DownOnly"
Margin="20"/>
<TextBlock Grid.Row="2" x:Name="TextBlock" Text="Loading..." HorizontalAlignment="Center" Foreground="#FF202020"
FontSize="16"/>
<ProgressBar Grid.Row="3" x:Name="ProgressBar" Margin="4" Height="10" Maximum="100"/>
</Grid>
当我将这个LoadingScreen
包含的两个按钮中的一个按下时,问题就发生了,我甚至没有点击,只是悬停,不到一秒钟之后,Dispatcher.Run()
会给我一个The calling thread cannot access this object because a different thread owns it.
{1}}
我测试了是否有自定义Style
和(out)内容(我删除了我的向量以简化此问题的代码),没有不同的结果。
我可以轻松拖动以移动Window
,但我无法悬停Buttons
。那很奇怪。在使用其他线程并运行Dispatcher
时错过了什么?
使用ShowDialog()
代替Show()
没有做任何事
删除Dispatcher.Run()
杀了我的应用程序的其他部分(没有其他任何东西出现,只是一个白色的屏幕)
删除STA
会导致应用程序崩溃(需要是STA)。
整个代码都可用。 该应用程序使用.net 4.0,我忘了说。
答案 0 :(得分:2)
所以这是由于工具提示。这就解释了为什么你必须在短时间内将鼠标悬停在它上面。我会把它添加到我的测试中,看看我能想出什么。
编辑:我认为问题是由于你开始你的线程的方式。你是从主窗口调用启动画面吗?如果是,您需要更改代码的顺序:
public static void ShowSplash(bool isIndeterminate = false)
{
_thread = new Thread(new ThreadStart(OpenSplash))
{
IsBackground = true,
Name = "Loading"
};
_thread.SetApartmentState(ApartmentState.STA);
_thread.Start();
}
private static void OpenSplash()
{
//Run on another thread.
_splash = new Splash();
_isIndeterminate = false;
_splash.Show();
System.Windows.Threading.Dispatcher.Run();
//_splash.Dispatcher.Invoke(new Action(Dispatcher.Run));
System.Windows.Threading.Dispatcher.Run(); //HERE!
_splash.Dispatcher.Invoke(() => { _splash.ProgressBar.IsIndeterminate = _isIndeterminate; });
}
在我的原始帖子中,我正在从App.xaml.cs文件创建窗口,此时没有调度程序正在运行,这就是它工作的原因。当从窗口调用它时,它是从主Windows调度程序线程调用的,用你设置线程的方式总是调用主窗口。当我这样设置时,我会得到与你相同的问题。通过更改线程创建,它将按预期工作。
有关详细信息,请参阅ShowSplash和OpenSplash方法中的更改
ORINGINAL POST :我尝试复制代码,但我无法让它失败。请参阅下面的代码,它是否适用于您的系统?
App.cs
public partial class App : Application
{
private static Splash _splash;
private static bool _isIndeterminate = false;
private static Thread _thread;
protected override void OnStartup(StartupEventArgs e)
{
ShowSplash(true);
Thread.Sleep(5000);
}
public static void ShowSplash(bool isIndeterminate = false)
{
_isIndeterminate = isIndeterminate;
_thread = new Thread(OpenSplash)
{
IsBackground = true,
Name = "Loading"
};
_thread.SetApartmentState(ApartmentState.STA);
_thread.Start();
}
private static void OpenSplash()
{
//Run on another thread.
_splash = new Splash();
_splash.Show();
_splash.ProgressBar.IsIndeterminate = _isIndeterminate;
//_splash.Dispatcher.Invoke(new Action(Dispatcher.Run));
System.Windows.Threading.Dispatcher.Run(); //HERE!
}
public static void CloseSplash()
{
if (_splash == null || _thread == null)
return;
_splash.Dispatcher.Invoke(new Action(() => { _splash.Close(); }));
_splash.Dispatcher.InvokeShutdown();
_splash = null;
}
public static void Update(int value, string description)
{
Update((double)value, description);
}
public static void Update(double value, string description)
{
if (_splash == null)
return;
_splash.Dispatcher.Invoke((Action)delegate
{
//It takes 120 ms to progress 10%.
var da = new DoubleAnimation(value, new Duration(TimeSpan.FromMilliseconds(Math.Abs(_splash.ProgressBar.Value - value) * 12)))
{
EasingFunction = new PowerEase { Power = 3 }
};
_splash.ProgressBar.BeginAnimation(RangeBase.ValueProperty, da);
_splash.textBlock.Text = description;
});
}
}
Splash.xaml.cs
public partial class Splash : Window
{
public Splash()
{
InitializeComponent();
}
private void Window_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
this.DragMove();
}
}
Splash xaml
<Window x:Class="SplashScreenWPF.Splash"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:SplashScreenWPF"
mc:Ignorable="d"
Title="Splash" Height="300" Width="300" MouseLeftButtonDown="Window_MouseLeftButtonDown">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="147*"/>
<ColumnDefinition Width="145*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="135*"/>
<RowDefinition Height="134*"/>
</Grid.RowDefinitions>
<Button Margin="30" Grid.Column="0" />
<Button Margin="30" Grid.Column="2" />
<TextBlock x:Name="textBlock" HorizontalAlignment="Left" Margin="30,66,0,0" Grid.Row="1" TextWrapping="Wrap" Text="TextBlock" VerticalAlignment="Top"/>
<ProgressBar x:Name="ProgressBar" Grid.Column="1" HorizontalAlignment="Left" Height="16" Margin="24,66,0,0" Grid.Row="1" VerticalAlignment="Top" Width="100"/>
</Grid>
答案 1 :(得分:0)
悬停发生在GUI线程中,您拥有的按钮逻辑位于不同的线程中;解决这个问题,你将解决问题。
将DragMove
操作调用回GUI线程。像这样:
public static void SafeOperationToGuiThread(Action operation)
{
System.Windows.Application.Current?.Dispatcher?.Invoke(operation);
}
称为
SafeOperationToGuiThread( DragMove );
如果你没有使用C#6(在VS 2015中),那么在显示的每个?
上进行健全性无效检查。