Code Execution in Form Stops - c#

I'm writing an application which is supposed to communicate with a windows mobile 6.5 device. When the device is plugged in, the activeHandler callback is returned.
The problem that I'm having is that code execution stops at the
lblStatus.Text = "someString";
line. No Exception is thrown, the code execution is justed stopped and the gui gets the focus. I've tried the same thing with using the invoke method on the label property which yielded the same result. If calling non form code in that method, everything runs fine.
public partial class MyClass: Form
{
public MyClass()
{
ActiveHandler active = new ActiveHandler(ActiveSync_Active);
sync.addHandler(active)
}
private void ActiveSync_Active() {
lblStatus.Text = "someString";
//Some code
}
}
Edit:
The invoke call that didn't work
private delegate void StatusLabelChange(string str);
private void ChangeStatusLabelText(string str)
{
lblStatus.Text = str;
}
private void ActiveSync_Active() {
lblStatus.Invoke(new StatusLabelChange(ChangeStatusLabelText), new object[] {"asd"});
}

Try BeginInvoke too, since that'll push it async.

Related

Problems with loading screen in separate Thread

I have an old application in Windows Forms, which in many places do some searches on database. Sometimes it takes a lot of time, so I decided to create a loading screen in wpf to show the user that something is loading in separate thread. Basically it's just a full transparent window with loading indicator(a turning circle). Everything works fine on My host computer and on my Virtual Machine, but when I'm trying to deploy it to our demo environments its like - it starts loading the indicator is shown and after few seconds it dissapear and application stops responding like forever. My first thought was that it's the problem with GPU acceleration, that it can't process transparency, but it's being shown for few seconds so it can't be the problem. So most likely I did something bad. Below You can see my code, do You notice something which might be wrong/cause deadlock or something ?
public class LoadingManager
{
public LoadingManager()
{ }
public LoadingManager(string LoadingText)
{
loadingText = LoadingText;
}
private string loadingText = "Please wait ..";
private Thread thread;
private bool ThreadReadyToAbort = false;
private BusyIndicatorView loadingWindow;
public void BeginLoading()
{
this.thread = new Thread(this.RunThread);
this.thread.IsBackground = true;
this.thread.SetApartmentState(ApartmentState.STA);
this.thread.Start();
}
public void EndLoading()
{
if (this.loadingWindow != null)
{
this.loadingWindow.Dispatcher.BeginInvoke(DispatcherPriority.Normal, (Action)(() =>
{ this.loadingWindow.Close(); }));
while (!this.ThreadReadyToAbort) { }; // I also tried to remove this while but it didn't help
}
this.thread.Abort();
}
public void RunThread()
{
this.loadingWindow = new BusyIndicatorView();
loadingWindow.tbLoadingCaption.Text = loadingText;
this.loadingWindow.Closing += new System.ComponentModel.CancelEventHandler(waitingWindow_Closed);
this.loadingWindow.ShowDialog();
}
void waitingWindow_Closed(object sender, System.ComponentModel.CancelEventArgs e)
{
Dispatcher.CurrentDispatcher.InvokeShutdown();
this.ThreadReadyToAbort = true;
}
EDIT.
I noticed that on this machines it usually(sometimes it also fails at first click) works when i click search for the first time. If i click another time it's showing for a second than dissapearing and application stops responding. So it seems like Thread is not beeing shutdown, Dispatcher shutdown failed ? But no exceptions are thrown ...
Your BeginLoading method can be called more than once before it has finished, and so can create more than one wpf window. This messes up all kinds of references. Also do not abort the thread, let it decide for itself. Here are the two changes:
public void BeginLoading()
{
this.thread = new Thread(this.RunThread);
this.thread.IsBackground = true;
this.thread.SetApartmentState(ApartmentState.STA);
this.thread.Start();
while (this.loadingWindow == null) { } // <--- Add this line
}
public void EndLoading()
{
if (this.loadingWindow != null)
{
this.loadingWindow.Dispatcher.BeginInvoke(DispatcherPriority.Normal, (Action)(() =>
{ this.loadingWindow.Close(); }));
while (!this.ThreadReadyToAbort) { };
}
//this.thread.Abort(); // <-- Remove this line
}
Also if this is all just for a busy screen, I would say there has to be a better and safer way than this. For academic purposes this is an interesting problem, but not production code, especially if some junior developer could fiddle with this in the future.
Edit: Still crashing on my machine if I reduce the delay between repeated callds to BeginLoading and EndLoading. It may be related to how the wpf window closes asynchronously. I removed the Closed event handler and just used a boolean flag to indicated that the window 'isLoaded' or not, and I have not seen any problems with this:
public class LoadingManager2
{
public LoadingManager2()
{ }
public LoadingManager2(string LoadingText)
{
loadingText = LoadingText;
}
private string loadingText = "Please wait ..";
private Thread thread;
private MyWindow loadingWindow;
private bool isLoaded = false;
public void BeginLoading()
{
this.thread = new Thread(this.RunThread);
this.thread.IsBackground = true;
this.thread.SetApartmentState(ApartmentState.STA);
this.thread.Start();
while (!this.isLoaded) { };
}
public void RunThread()
{
this.loadingWindow = new MyWindow();
this.isLoaded = true;
this.loadingWindow.ShowDialog();
}
public void EndLoading()
{
this.loadingWindow.Dispatcher.BeginInvoke(DispatcherPriority.Normal, (Action)(() =>
{
this.loadingWindow.Close();
this.isLoaded = false;
}));
while (this.isLoaded) { };
}
}

telerik's radcontrols cause cross thread exception

I am using Telerik's radcontrols for winforms.
Here is a program that can reproduce my problem:
public partial class RadForm1 : Telerik.WinControls.UI.RadForm
{
public RadForm1()
{
InitializeComponent();
}
private void radButton1_Click(object sender, EventArgs e)
{
RadMessageBox.SetThemeName("Office2010Black");
RadMessageBox.Show("Hello World");
//MessageBox.Show("hello world");
run();
}
public void run()
{
var thread = new Thread(() => run2());
thread.IsBackground = true;
thread.Start();
}
public void run2()
{
//MessageBox.Show("hello");
RadMessageBox.Show("Hello");
}
}
Whenever try using Telerik's messagebox I am getting a cross thread exception. However if I use the standard winform messagebox instead then it will work absolutely fine.
Maybe i am missing something here.
UPDATE:
for anyone else having the same problem this is the link to offical reply Click here
The winform MessageBox class is specifically designed to be able to be called from a non-UI thread.
The RadMessageBox simply wasn't. It was designed under the assumption that it would be called from the UI thread.

C# Winforms - Splash Screen Hanging on Form_Load

OK guys, I have this Class that shows a "Loading..." Splash Screen. It works great when I call it on Initialize() but not on Form_Load. Instead of showing at the beginning of Form_Load, it shows after all tables are filled and then just hangs there (no lock).
class innerLoad
{
//Delegate for cross thread call to close
private delegate void CloseDelegate();
//The type of form to be displayed as the splash screen.
private static frmLoading splashForm;
static public void ShowSplashScreen()
{
// Make sure it is only launched once.
if (splashForm != null)
return;
Thread thread = new Thread(new ThreadStart(innerLoad.ShowForm));
thread.IsBackground = true;
//Thread.Sleep(100);
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
}
//volatile static public bool isOpen = false;
static private void ShowForm()
{
splashForm = new frmLoading();
splashForm.ShowDialog();
splashForm.Dispose();
}
static public void CloseForm()
{
try
{
if (splashForm == null)
return;
splashForm.Invoke(new CloseDelegate(innerLoad.CloseFormInternal));
}
catch
{
}
}
static private void CloseFormInternal()
{
splashForm.Close();
splashForm = null;
}
}
And here is the Form_Load Code:
private void frmPayGen_Load(object sender, EventArgs e)
{
//th1 = new Thread(LoadingForm);
//th1.Start();
//Thread.Sleep(500);
innerLoad.ShowSplashScreen();
fill();
innerLoad.CloseForm();
//Thread.Sleep(500);
}
I appreciate your help and I love this site... helps me a lot :D
If you set a breakpoint at the start of your Form Load event, and use F11 to step through, you eventually see this exception:
Exceptions in a Form Load event are basically ignored. If an exception is thrown, nothing after the line where the exception was thrown runs, but the Windows Form doesn't crash either. Taking away this line of code should make things work as you wish.

How do I invoke a method in another thread?

I have the following classes:
using System;
using System.Windows.Forms;
namespace FastEyeControl
{
public partial class ConnectView : Form, IConnectView
{
private IConnectPresenter m_Presenter;
public ConnectView()
{
InitializeComponent();
m_Presenter = new ConnectPresenter(this);
}
public string Hostname
{
get
{
return m_Hostname.Text;
}
}
public int Port
{
get
{
return Convert.ToInt32(m_Port.Text);
}
}
public void ShowMessage(string message)
{
MessageBox.Show(message,
"Success",
MessageBoxButtons.OK,
MessageBoxIcon.Information);
}
public void ShowError(string message)
{
MessageBox.Show(message,
"ERROR!",
MessageBoxButtons.OK,
MessageBoxIcon.Error);
}
private void m_ConnectButton_Click(object sender, EventArgs e)
{
m_Presenter.ConnectButtonPressed();
}
}
}
The presenter class:
using System;
using System.Collections.Generic;
namespace FastEyeControl
{
public class ConnectPresenter : IConnectPresenter
{
private IConnectView m_View;
private IConnectModel m_Model;
public ConnectPresenter(IConnectView view)
{
m_View = view;
m_Model = FastEyeClient.Instance;
}
public void ConnectButtonPressed()
{
m_Model.Connect(m_View.Hostname, m_View.Port);
}
private void ConnectionComplete(object sender, ConnectionEventArgs e)
{
// Code here indicating whether connection was successful and informing the view.
// i.e...
if (e.IsConnected)
{
m_View.ShowMessage("Successfully connected.");
}
else
{
m_View.ShowError("Unable to connect.");
}
}
}
}
The model code runs in another thread. The problem is that when I call m_Model.Connect(), I'm calling code that's usually running in another thread within the main thread still (the UI thread). This is not a database connection. This is a TCP/IP connection to a server. If I set a variable within the model, then I am doing this from the UI thread which is not thread safe.
I know that with user controls, they have InvokeRequired and Invoke/BeginInvoke operations that will handle this situation. But that is for user controls only. I know you can't just interrupt another thread in the middle of its execution and tell it to call another method instead. I basically want the non-UI thread to call the Connect code somehow.
Just as a test, I tried using a delegate (fire off an event whenever I want to connect) and when I look in the debugger, the Connect code is still running in the UI thread.
I need a multi-threaded event queue essentially. What's the best way to achieve what I want to do here? Thanks!
public void ConnectButtonPressed()
{
var threadedTask = () => m_Model.Connect(m_View.Hostname, m_View.Port);
threadedTask.BeginInvoke(null,null);
}
This will, no question, use a background thread from the ThreadPool to do the work. Maybe you had tried to call the delegate directly, or called Invoke() on it; that will execute the delegate synchronously.
Now, BeginInvoke is simple to set up, but it has its limitations; you cannot cancel execution of the background thread, and if it throws an exception you cannot catch it in the invoking thread.
You can use BackgroundWorker.

Ensuring that all callbacks were completed before sending a new request through a DuplexChannel using WCF

I am experiencing some issues when using a Callback in a WCF project.
First, the server invokes some function Foo on the client which then forwards the request to a Windows Forms GUI:
GUI CLASS
delegate void DoForward();
public void ForwardToGui() {
if (this.cmdSomeButton.InvokeRequired) {
DoForward d = new DoForward(ForwardToGui);
this.Invoke(d);
}
else {
Process(); // sets result variable in callback class as soon as done
}
}
}
CALLBACK CLASS
object _m = new object();
private int _result;
public int result {
get { return _result; }
set {
_result = value;
lock(_m) {
Monitor.PulseAll(_m);
}
}
}
[OperationContract]
public int Foo() {
result = 0;
Program.Gui.ForwardToGui();
lock(_m) {
Monitor.Wait(_m, 30000);
}
return result;
}
The problem now is that the user should be able to cancel the process, which doesn't work properly:
SERVER INTERFACE
[OperationContract]
void Cleanup();
GUI CLASS
private void Gui_FormClosed(object sender, EventArgs e) {
Program.callbackclass.nextAction = -1;
// so that the monitor pulses and Foo() returns
Program.server.Cleanup();
}
The problem with this is that Cleanup() hangs. However, when I close the form when Process() is not running, it works properly.
The source seems to be that the Cleanup() is called before the monitor pulses etc and therefore a new request is sent to the server before the last request from the server has not yet been responded.
How can I solve this problem? How can I ensure before calling Cleanup() that no Foo() is currently being executed?
The first warning I'm seeing is that you're calling Invoke instead of
BeginInvoke
Invoke waits until the action has been completed on the other thread before returning, which can result in a deadlock in some situations.

Categories