Passing parameters to timer event - c#

I am trying to create an animation that moves some images across the canvas in my applications layout.
The canvas is named layout which belongs to the main window and the timer is calling the event Animation.Clouds(layout, 1). When attempting this I am getting an error regarding the object is owned by another thread. This has left me to believe that the cause is the timer not being able to pass the context of layout, causing the error.
How would I solve this issue and pass layout to the timer in order for the animation to work?

use DispatcherTimer instead, it fire a tick in dispatcher thread it is created

The problem is that you can ONLY update a UI element, when you are on the UI thread. The Timer event gets invoke on a different thread.
In Windows.Forms you can use BeginInvoke. I'm sure WPF has something similar.

Related

C# wpf redrawing canvas depeding on Timer event

I'm trying to redraw a canvas on a Timer event. When the event is fired, the application crashes with an exception.
Picture of code of main procedure
Picture of code handling the timer event
Intead of the Timer class use the DispatcherTimer, It executes the tick on the original thread so it can access the UI
Please try to use the DispatcherTimer instead of the normal timer or you have to invoke to main thread for the hole event handler (OnTimedEvent)
You may use this Link

Using a timer to call a method of a form control C#, threading issues

I am building a custom control for a few of my forms which is an "indictor light"; an edit control that just changed color.
I would like to set a timer and see what the "light" looks like when it switches from state to state.
I have been reviewing this link C# Elapsed Timer MSDN
Though this does not work for me. I think the issue has to do with the Timer executing on another Thread meaning I cannot interact with the this (this.editControl.[...]) within the OnTimedEvent method.
Is there a simple Timer I could use to just call a method of a forms controls every second or so?
Use the Timer control (the System.Windows.Forms.Timer class). You can find it in the Toolbox when on a designer canvas.
Set the Interval property to 1000 (1 second) and make sure its Enabled. The Tick event fires at every interval and is raised in the UI thread.

WPF CrossThreadException in App.Xaml with BackgroundWorker

I have this in my App.Xaml:
public App()
{
_backgroundWorker = new BackgroundWorker();
_backgroundWorker.DoWork += new DoWorkEventHandler(DoBackgroundWork);
_backgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(BackgroundCompleted);
_backgroundWorker.RunWorkerAsync();
_splashView = new SplashView();
_splashView.Show();
}
The DoBackgroundWork method performs some database setup, and then the BackgroundCompleted event closes the _splashView and shows _mainView.
However, modifying anything in the _splashView from BackgroundCompleted causes a cross thread exception, which is what I though background workers were designed to fix. I'm guessing this has something to do with the way backgroundworker's work in App.Xaml. Maybe this is a bad way to do a splash screen?
The background worker uses the SynchronizationContext. This is going from memory, but I don't think it has been initialised in the App constructor.
Before you construct the BW check SynchronizationContext.Current is not null.
Also check SynchronizationContext.Current is the same before construction of BW and in the completed method.
If it's not, you'll need to move the code later in the process...
App.OnStartUp should be fine
Maybe this is a bad way to do a splash screen?
Unless I've misinterpreted your question, I don't think there's a need to do this to show a splash screen. Just select the image and in the Properties window click the BuildAction dropdown and select SplashScreen. Also, I think you can simplify your process by eliminating the BackgroundWorker, unless your data function takes a long time. I believe you added it to accomodate the showing/hiding of the splash screen.
There is no guarantee which thread the event handler of OnWorkCompleted will be used for execution.
See similar question BackgroundWorker OnWorkCompleted throws cross-thread exception
You have to use the Invoke or BeginInvoke methods to modify visual elements from a background thread. You can call this directly on the object whose properties you are modifying or use the Dispatcher.
EDIT: As per conversation with Adam
The SynchronizationContext has the desired effect for the OnWorkCompleted event handler to be run on the initial thread (not the BackgroundWorker's). http://msdn.microsoft.com/en-us/magazine/gg598924.aspx. (See Figure 2)
If the BackgroundWorker is created and run prior to the SynchronizationContext initialization, then the OnWorkCompleted will execute on possibly the same thread as the BackgroundWorker.
Thanks Adam.

Is there a Form event that gets called right before anything is drawn to the screen?

I've tried overriding the OnLoad event, but the form is getting drawn before this method finishes. I am calling the base.OnLoad method. But, the form is partially getting drawn (artifacts are seen) during the event. I notice this because I'm hitting the database and it is taking some time. In the event, I'm getting some data and binding it to the form's controls. Please don't tell me to use a separate thread. For simplicity, I would rather just show a busy cursor while the data is being loaded.
UPDATE:
Ok, I think you guys/gals have convinced me. I'll use a separate thread. I wasn't aware of the BackgroundWorker and it was very easy to implement. Now my form is loading quickly. And then, all of a sudden my combo boxes are populated. But, I'd like prevent the user from clicking on the combos before they're populated. What is the best way/standard way of doing this using Winforms? Is there a way to turn off input events in the form until the background worker is finished?
I would recommend that you cover the form with a Loading label before you start loading.
You should be able to solve the problem by placing your loading in the constructor code before the call to IntializeComponent(). At this point, the controls on the form have not yet been created (because this is what InitializeComponent does).
However, the form is also not yet visible in this phase. If you want to show a blank form, then I think a possible solution (I haven't tried that, but I think it should work) would be to call this.Show() (to display the form) and Application.DoEvents() to let WinForms process events and display the form.
You could try doing your expensive operations in the form's constructor, so that when it's time to show the form, it already has the data it needs to render. Also look into SuspendLayout/ResumeLayout methods.
But none of these solutions will be as graceful as using a different thread to perform expensive operations.
I am not sure if this will help or not, but the Move event is called before Load.
The Shown event is good for this. Your form will be completely displayed, then the Shown event is fired. This will give the user a clean screen without partially drawn fields while you load your data.
In your Shown event handler, turn on the hourglass, do your work and then turn off the hourglass.
The ComboBox has a BeginUpdate() and EndUpdate() that can be called when adding large amounts of data or slow data to the control. SuspendLayout() and 'ResumeLayout()` on the form may also help with your redraw issues.
You can also disable the control, if all you want is to prevent the user from clicking it. If you disable the form itself, all contained controls will also be disabled.
If you're using background threads, you'll have to make sure you call these from the main UI thread before starting the thread, and again from the main UI thread when the background worker is complete.

What's the best way to initiate a UI update after n seconds have elapsed?

My C# WinForms UI has some parameters that the user can adjust using sliders. Many parts of the UI can interactively update based on the slider values. However, some parts require a longer calculation that requires some overhead to set up. I would like to only initiate this update process once the user has stopped moving the sliders for, say, 2 seconds. What's the best way to do this?
The Reactive Framework would be perfect for that. If you have C# 3.5, you could use it.
Observable.FromEvent<ScrollEventArgs>(vScrollBar1, "Scroll")
.Throttle(TimeSpan.FromSeconds(2)) // Wait for two second alter all Scroll event ended
.ObserveOnWindowsForms() // Make the lambda expression run on the UI thread
.Subscribe(
e =>
{
// Update your stuff
labelControl1.Text = e.EventArgs.NewValue.ToString();
});
You can get rid of the ObserveOnWindowsForms call if you don't want to make your UI to hang while running the lamda, but make sure that you properly access your UI component to avoid cross-threading exception.
You could use a Timer control that resets the UI if any anything has changes after 2 seconds.
The timer would also check a variable that is flagged after every change, so only when the flag has not changes and timer times out, the UI is upated.
I would have a private instance member referencing a thread timer. When the timer hits 2 seconds, the event containing the calculations would fire. All sliders would have an change listener that would set the timer to 0 and start the timer.
You need to use this timer: System.Windows.Forms.Timer. Why? It executes on the UI thread meaning you don't have to use InvokeRequired or BeginInvoke to execute your UI updating code on the UI thread.

Categories