C# 不同线程上的wpf屏幕冻结';随机';
我有一个问题,我已经有一个多星期了,我不知道为什么 我有一个等待屏幕,我把它放在另一个线程中,这样它就可以加载并显示它自己,即使代码正在做大量的工作(当我在同一个线程中做任何事情时,屏幕都不会显示它自己,我想这是因为代码忙于做其他事情) 然而,它并不总是在某些时候冻结,而且只在平板电脑上冻结,它在我的电脑上运行良好(至少我在电脑上测试时没有注意到它冻结) 我尝试过“破解”其中的一些解决方法,例如在等待屏幕上放置一个取消按钮,这样它就可以关闭,但无法单击(如果它冻结且没有响应) 有一次,我还认为这是一个问题,因为我会在线程启动之前关闭它,所以我做了一个布尔值,如果线程仍在加载或未加载,则会显示它,如果线程仍在加载,并且我尝试关闭它,我会添加一个事件列表器,以便在线程完成启动时关闭它 不管怎么说,这是代码,我希望这里有人能帮我C# 不同线程上的wpf屏幕冻结';随机';,c#,wpf,multithreading,wpftoolkit,C#,Wpf,Multithreading,Wpftoolkit,我有一个问题,我已经有一个多星期了,我不知道为什么 我有一个等待屏幕,我把它放在另一个线程中,这样它就可以加载并显示它自己,即使代码正在做大量的工作(当我在同一个线程中做任何事情时,屏幕都不会显示它自己,我想这是因为代码忙于做其他事情) 然而,它并不总是在某些时候冻结,而且只在平板电脑上冻结,它在我的电脑上运行良好(至少我在电脑上测试时没有注意到它冻结) 我尝试过“破解”其中的一些解决方法,例如在等待屏幕上放置一个取消按钮,这样它就可以关闭,但无法单击(如果它冻结且没有响应) 有一次,我还认为这
public partial class WaitWindow : Window
{
//private static WaitWindow ww = new WaitWindow();
private static Thread thread;
private static event ThreadStartingEvent started;
private delegate void ThreadStartingEvent(object sender, EventArgs e);
public static bool disposable = false;
private static bool startingThread;
private static bool StartingThread
{
get
{
return startingThread;
}
set
{
startingThread = value;
if (!startingThread && started != null)
{
started(null, new EventArgs());
}
}
}
// To refresh the UI immediately
private delegate void RefreshDelegate();
private static void Refresh(DependencyObject obj)
{
obj.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Render,
(RefreshDelegate)delegate { });
}
public WaitWindow()
{
InitializeComponent();
}
public static void BeginDisplay()
{
if (thread == null)
{
startingThread = true;
thread = new Thread(() =>
{
WaitWindow ww = new WaitWindow();
ww.Show();
ww.Closed += (sender2, e2) =>
ww.Dispatcher.InvokeShutdown();
System.Windows.Threading.Dispatcher.Run();
});
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
startingThread = false;
}
}
public static void EndDisplay()
{
if (startingThread)
{
started += new ThreadStartingEvent(WaitWindow_started);
}
if (thread != null)
{
disposable = false;
thread.Abort();
thread = null;
}
}
static void WaitWindow_started(object sender, EventArgs e)
{
thread.Abort();
thread = null;
started = null;
}
private void button1_Click(object sender, RoutedEventArgs e)
{
if (disposable)
{
disposable = false;
thread.Abort();
thread = null;
}
}
}
以及xaml代码:
<Window x:Class="WpfApplication1.WaitWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
Title="WaitWindow" WindowStyle="None" ResizeMode="NoResize" WindowStartupLocation="CenterScreen"
Background="Transparent" AllowsTransparency="True"
Width="1024" Height="640">
<Grid>
<xctk:BusyIndicator Name="BusyBar" IsBusy="True" BusyContent="Even geduld a.u.b.">
</xctk:BusyIndicator>
<Button Name="button1" Width="28" HorizontalAlignment="Left" Margin="550,271,0,0" Height="28" VerticalAlignment="Top" Click="button1_Click">X</Button>
</Grid>
</Window>
X
可能需要一些额外的信息:当我执行可能需要一些时间的任务(从远程数据库获取数据)时,我调用begindplay()
,当代码完成时,我调用EndDisplay()
这对我来说似乎很明显,但我想提一下也没什么坏处
编辑:
我可能应该提到我正在使用.net framework 3.5,如果您正在执行后台异步任务,则需要创建同步上下文。也许这就是问题的原因
// Create a thread
Thread newWindowThread = new Thread(new ThreadStart( () =>
{
// Create our context, and install it:
SynchronizationContext.SetSynchronizationContext(
new DispatcherSynchronizationContext(
Dispatcher.CurrentDispatcher));
Window1 tempWindow = new Window1();
// When the window closes, shut down the dispatcher
tempWindow.Closed += (s,e) =>
Dispatcher.CurrentDispatcher.BeginInvokeShutdown(DispatcherPriority.Background);
tempWindow.Show();
// Start the Dispatcher Processing
System.Windows.Threading.Dispatcher.Run();
}));
// Set the apartment state
newWindowThread.SetApartmentState(ApartmentState.STA);
// Make the thread a background thread
newWindowThread.IsBackground = true;
// Start the thread
newWindowThread.Start();
这段代码是从中截取的,值得一读。通常,您会将锁定UI的处理移到后台线程,并将主线程保留在空闲状态,以供通过
Dispatcher.Invoke()
返回的所有UI更新使用,因此这里的实现非常不同
我首先想到的是使用
Thread.Abort()
,我很确定MSDN文档基本上说不要使用它,除非你的线程没有其他停止方法。特别是,如果您中止了线程,那么关闭打开的窗口将剩下什么。这可能是您的问题吗?我认为您的代码中没有问题。也许你正在使用的平板电脑的CPU很弱,而且很忙?作为补充说明,通过使用Window.ShowDialog()
,您可以真正简化代码,这样您就不需要Dispatcher.Run()
(或关机)。另外,与其中止线程,不如保留一个对窗口的引用,然后调用它。我不太擅长跨线程,我如何使它能够从主线程(不是创建它的线程?)执行ww.Close()。只需将窗口保存为成员,然后调用\u win.Dispatcher.InvokeAsync(()=>\u win.Close());
@EliArbel我在这里只是冒险,假设.net framework 3.5没有InovekAsync方法,因为我收到一个错误,说它不存在。另外,我没有提到我正在使用.NET3.5Use\u-win.Dispatcher.BeginInvoke(新操作(()=>\u-win.Close())代码>无,而是在消息pumpDispatcher.Run()完成时让它关闭。简而言之,遵循@jamesworld回答的代码。