相关文章推荐
Today we found a little strange problem in one of our WPF application and we are not exactly sure how to deal with it. When we run the software on one of our laptops the screen goes to sleep (turns black) after a while when there is no user interaction. It application itself is still busy downloading data from the internet and filling tables in a database. There is also a progress bar and a status bar.
If we wake the screen simply by moving the mouse the program is shown again but some parts of the window are not refreshed. The progress bar is still showing values even if the process is completed and the status bar is also wrong.
From this time on you can work with the program like nothing happened but progress bar and status bar will only be redrawn if you minimize the complete window to the task bar and maximize it again. Or if you start another action that will also use progress bar or status bar.
This strange behavior caused a lot of confusion because the displayed data seems to be wrong after the screen awakes from sleep and you need to minimize and maximize the window to see what is really going on.
What is wrong here? You need to handle the event Microsoft.Win32.SystemEvents.PowerModeChanged , see http://msdn.microsoft.com/en-us/library/microsoft.win32.systemevents(v=VS.100).aspx [ ^ ].
Look at this code sample: http://msdn.microsoft.com/en-us/library/hxkc1kwd.aspx [ ^ ].
For refreshing of the WPF Window try to call System.Windows.Window.UpdateLayout , see http://msdn.microsoft.com/en-us/library/system.windows.window.aspx [ ^ ].
Thank you for the interesting question again.
Good luck,
As you said , i tried a simple project just now:
///
/// Interaction logic for Window1.xaml
///

public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
this.Loaded += (o, e) => { this.TabControlMain.SelectedIndex = 0; };
SystemEvents.PowerModeChanged+=new PowerModeChangedEventHandler(SystemEvents_PowerModeChanged);
}

private void SystemEvents_PowerModeChanged(object sender, PowerModeChangedEventArgs e)
{
if (e.Mode == PowerModes.Suspend)
{
PrepareToSleep();
}
else
{
this.UpdateLayout();
}
}

private void PrepareToSleep()
{
this.TabControlMain.SelectedIndex = 1;
}
}

TabControlMain is a tabcontrol ,since the window loaded ,the selectedindex is 0,
when the computer went to sleep ,its selectedindex turned to 1,but after awaken, the UI didn't update ——after i minimized it and clicked it in the taskbar, then it appeared with selecting the tabcontrol's 1 index.

in other words, it seems that UpdateLayout doesn't work as I expected.

Thanks for your help.
OK, it looks like you have the PowerModeChanged event working. (Did you really check it up?)

Interesting. Well, selection can be a different problem; I don't know the reason, it can be even a bug. You can work around: in prepare to PrepareToSleep remember selection (I don't know why you set selection, is it just for experiment?) and restore it on awaken. By the way, you should use PowerModes.Resume, not "else".

Also, I advise you use logging to debug it and know what exactly happens (use System.Event log and log into system log); log all key points. You cannot physically debug events like PowerModeChanged under debugger, by obvious reasongs :-)

--SA
I changed the selected index is want to test whether the wpf application's UI would refresh after awaken or not.
yes ,PowerModeChanged it really worked, what doesn't work is the Window's UpdateLayout or maybe it works and not as expected.
Eealier I use Win32's API to get the Window's Sleep Message, PowerModeChanged worked same .
I will try to test as you advised.
what i want:
once the computer runs into Suspend(such as sleep) ,the tabcontrol changes its selectedindex (such as 1 ,the original one is 0).
After awaken I wanna see that the tabcontrol's selectdindex is 1(in Winfrom applicatin it is).
But the fact is that:
After awaken the selected index is still 0, when i minimize the application and resotre it with taskbar (or directly maximize the application),the selected index is 1.
You can capture the event System.Windows.Controls.TabControl.SelectionChanged, add event handler; in this event handler: get System.Diagnostics.StackTrace, dump it using all frames StackFrame into some text and log it text using System.EventLog. You will know what changes selection in what case.

Use this approach in other critical points, in the event handler of PowerModeChanges, etc.
--SA
OK, now it looks like we got some result on power events, and the problem is not specifically related just to those event; as you say there is a shift of selection on maximize or restore.

I'm starting to have a feeling you have a bug in TabControl events, not sure yet.

1) Can you reproduce the whole problem operating just with minimize/maximize/restore?
(For clear experiment, you can change windows state by timer, to avoid parasitic effects of keyboard/mouse.)

2) Is your window resizeable? It is very usual that a layout gets messed up and restored by a minimal resize. Is so, is there any abnormality on resize? (If not, I would make it resizeable temporarily, just to check up.)

3) Did you do the logging as I advised, especially on SelectionChanged?

4) Additional/Alternative: Can you fork off the project for the following: simplify the code down until it is gets minimal or the problem disappears?

You see, I think the problem is going out of the initial one. I'm almost sure if I make a simple project with TabControl and experiment with power status event, I won't see any problem. At the same time, I'm sure I would be able to fix the problem on your project as it is not if I did it myself (perhaps if it is not badly bloated so I would rather address its design, etc.). It's coming to a bug fixing, but that's going beyond quick answers. It's already gone beyond that; I think I passed to you all relevant techniques; and you confirmed they work -- you only need to sort out the mess.

What do you think? Any ideas?

--SA
It may not be a bug of tabcontrol ,
It is possibly a bug of WPF's rendering system as i guess,because when i used combobox it yielded the same result.

As I said,All works well on Winform Applications with exactly same code but not on WPF Applications.

If you could create a test project , I think the result will be same as I descriped.
yeah,the code i listed first is from a very simple project.
and what I want now is to find a way to let the WPF Application's UI refreshed if exists. Such as you mentioned the "Window's UpdateLayOut" method(Although it have not solve this problem, perhaps some other methods could),thanks a lot a lot for your help.
For whom is using the MaterialDesign libraries, it happens not only after going to sleep-mode but even after a simple screen-lock (Windows-L shortcut).
I solved adding this line to the Window element of the xaml file:
materialDesign:ShadowAssist.CacheMode= " {x:Null}"
Hope it helps.
  • Read the question carefully.
  • Understand that English isn't everyone's first language so be lenient of bad spelling and grammar.
  • If a question is poorly phrased then either ask for clarification, ignore it, or edit the question and fix the problem. Insults are not welcome.
  • Don't tell someone to read the manual. Chances are they have and don't get it. Provide an answer or move on to the next question. Let's work to help developers, not make them feel stupid.
  •  
    推荐文章