WinForm Automatically Close After Time Expires? - winforms

In Framework 4.0, I have a WinForm that is opened from another form, displays some stuff and a progress bar, and then sits there. I would like to close that "pop up" form after n secods if the user does not close it manually. What's the smartest way to do that?
Thanks.

Start a timer with the desired interval and then when it ticks the first time, close the form.
Something like this
private Timer _timer;
public PopupForm()
{
InitializeComponent();
_timer = new Timer();
_timer.Interval = 5000; // interval in milliseconds here.
_timer.Tick += (s, e) => this.Close();
_timer.Start();
}
Actually the smartest way would probably putting this in its own StartCountdown() method that takes the time as a parameter. Logic like this normally shouldn't be in a constructor strictly speaking...

Related

WPF Synchronous animation and UI thread deadlock

I'm writing a 3D wpf application using Viewport3D. When user push a button, I must start DoubleAnimation on AxisAngleRotation3D, but it must be done synchronous. I can't do it on animation.Completed, because this animation run the next one and the next one recursively.
ButtonHandler must work on UI thread, because to calculate animation I hardly use Viewport3D.
So I must in UI thread start synchronous animation and after it finished continoue work.
I tried this code, but it cause deadlock:
AxisAngleRotation3D axis;
DoubleAnimation animation;
DependencyProperty dp;
var worker = new Thread(() =>
{
Dispatcher.CurrentDispatcher.InvokeShutdown();
Dispatcher.Run();
});
worker.SetApartmentState(ApartmentState.STA);
worker.Start();
AutoResetEvent animationDone = new AutoResetEvent(false);
EventHandler handler = null;
handler = (sender, args) =>
{
animation.Completed -= handler; // remove self
animationDone.Set(); // signal completion
};
animation.Completed += handler;
Dispatcher.CurrentDispatcher.Invoke(new Action(() =>
{
axis.BeginAnimation(dp, animation);
}));
animationDone.WaitOne();
Ok, it's just an idea. Why don't you create this animations in few steps. First start first batch of animation and then, when they'll finish run another set of animations. You could synchronize it with some kind of timer.
You can first create list of animations and objects to run in each step and then just invoke them.

WPF Current time without using dispatcher

I'd like to know is there any other option to show current time without using DispatcherTimer?
Unfortunately app need's to run in slow PC's and DispatcherTimer continuously increasing memory usage. I check that in WPF Performance Profiling Tool and that's true - CPU usage with 1sec timespan is ~5-15%.
And becouse im using class to get time value and show that on label, it would be great if method to show could run without xaml-generated controls.
Thanks!
#EDIT:
DispatcherTimer dispatcherTimer = new DispatcherTimer();
dispatcherTimer.Tick += new EventHandler(dispatcherTimer_Tick);
dispatcherTimer.Interval = new TimeSpan(0, 0, 0);
dispatcherTimer.Start();
and when tick:
private void dispatcherTimer_Tick(object sender, EventArgs e)
{
lbl.Content = DateTime.Now.ToString("F");
// lbl is static label which i create once and show i several windows.
}
Your interval is zero, meaning...ouch. Why is it necessary to update the UI more than 10 times a second? No human being will be able to process the changes if they are that frequent. By default WPF only updates the screen 60 times a second, so your interval should be at least 1000/60 = 16.6 ms. However, I'd argue that something as high as 250ms could be good enough.

detect long touch (WPF and Microsoft Surface)

Is there any way I can detect a long touch over a TextBlock (or a Label)?
It is possible to do that in an awaitable fashion. Create a timer with specific interval. Start it when user tapped and return the method when timer elapsed. If user release the hand, return the method with false flag.
public static Task<bool> TouchHold(this FrameworkElement element, TimeSpan duration)
{
DispatcherTimer timer = new DispatcherTimer();
TaskCompletionSource<bool> task = new TaskCompletionSource<bool>();
timer.Interval = duration;
MouseButtonEventHandler touchUpHandler = delegate
{
timer.Stop();
if (task.Task.Status == TaskStatus.Running)
{
task.SetResult(false);
}
};
element.PreviewMouseUp += touchUpHandler;
timer.Tick += delegate
{
element.PreviewMouseUp -= touchUpHandler;
timer.Stop();
task.SetResult(true);
};
timer.Start();
return task.Task;
}
For more information, read this post.
As far as I know there is no built in way so you would have to do something like this
• Capture the start time on the TouchDown event of the control
• Compare this to the release time in the TouchUup event
• If the two are different by X then run your long touch code
There might be a few things you have to code around but that is the basic idea
There is an event called TouchAndHoldGesture and PreviewTouchHoldGesture
Long touch, or press and hold as I think it's formally named, can be detected through the right click event.
It may be that, if you are using a Surface Window, that the right click event is disabled.
There is a ContactHoldGesture event on all Surface controls that you can use. But, and I say this as the guy responsible for creating this feature during my time at Microsoft, this event is very poorly designed and should not be used. It doesn't tell you when the system has decided that a finger has moved too much to count as a "hold" and it doesn't give you information needed to draw an animation telling the user that a "hold" is underway. Your much better off doing what #Kevin suggested and building your own implementation.

When does a PhoneApplicationPage get disposed?

For example, if I have a page like this:
public partial class Page1 : PhoneApplicationPage
{
DispatcherTimer timer = new DispatcherTimer();
public Page1()
{
InitializeComponent();
timer.Interval = TimeSpan.FromSeconds(5);
timer.Tick += new EventHandler(timer_Tick);
timer.Start();
}
void timer_Tick(object sender, EventArgs e)
{
MessageBox.Show("timer tick");
}
}
In the app, I navigate to this page, it will pop up a message box every 5 seconds.
Then I press the "Back" button on the phone and navigate back to the previous page.
But the weird thing is that it still pops up a message box every 5 seconds.
I know I can stop the timer in the OnNavigatedFrom method, but why is this happening?
Isn't a page disposed after you press the back button on it?
Thanks
It will get disposed by the GC when nothing is keeping it awake. This DispatcherTimer keeps it awake, even though it was created by the page. My guess in the past has been that the DispatcherTimer is being referenced by the Dispatcher itself, and so can't clean up, or something along those lines.
To demonstrate add a finalize method
#if DEBUG
~MyPage() {
System.Diagnostics.Debug.WriteLine("Killing MyPage");
}
#endif
Then add a button somewhere on the main page to force a GC.Collect()
If you shut down the timer in OnNavigatedFrom your page will get cleaned up, if you do not, it will not.
I haven't tested this yet with Mango to see if it is smarter, but with the 7.0 tools I had to do a bit of work to get around this.
I think Because the dispatcher timer has long life time than the page ,and a good habbit is stop or cancel the eventhandler, so the page has the memory leak.I studying the gc,it's a little diffcult topic.....

WPF Best point to update a progress bar from BackgroundWorker

I have a task that takes a long time to execute. In order to inform the user of the progress, I have a progress bar that I update inside DoWork.
Can anybody tell me if this is the best way to update the progress bar? I have heard that there is a ReportProgress event handler but I am confused because I'm unsure of the purpose of ReportProgress.
Since the Background worker works in a separate thread, you'll run into problems if you try to access UI objects. Calling the ReportProgress method on the worker from inside the DoWork handler raises the ProgressChanged event. That event should be handled in the UI thread so as to easily access the control.
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += DoWorkHandler;
worker.WorkerReportsProgress = true;
worker.ProgressChanged += (s, e) =>
{ myProgressBar.Value = e.ProgressPercentage; };
worker.RunWorkerAsync();
...
public void DoWorkHandler(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
while (working)
{
// Do Stuff
worker.ReportProgress(progressPercentage);
}
}
The ProgressChanged event is what you are looking for. However, make sure you create the BackgroundWorker like below so it actually raises this event when ReportProgress is called.
BackgroundWorker bw = new BackgroundWorker() { WorkerReportsProgress = true };
bw.ProgressChanged += ... ;
ReportProgress is what you would use to update the progress of your task, including things like the UI--in your case, a proggress bar.
You should check out the MSDN docs, located here.
basically, you create a handler for the ReportProgress event, then in your DoWorkEventHandler, you call the ReportProgress like so:
worker.ReportProgress((i * 10));

Resources