Cross-thread issue not resolved despite the usage of Invoke() - multithreading

My C# app has lots of forms to perform various tasks. To keep things simple, I have a static class FormsCollection where the instances of each of the other forms are kept, so that they are shown and hidden from one place.
Now i was getting that classic debug time "Cross-thread" error. I tried to fix it the following way:
public class FormsCollection : Control // inherited from Control only to be
// able to call "this.Invoke"
{
public delegate void ShowFormDelegate(Form form);
public static Main mainForm;
// and many other forms...
public void ShowForm(Form form)
{
if (form.InvokeRequired)
{
ShowFormDelegate delegateFunc = new ShowFormDelegate(ShowForm);
this.Invoke(delegateFunc, new object[] { form });
}
else
{
previousForm = currentForm;
currentForm.Hide();
currentForm = form;
currentForm.Show();
}
}
}
Inside the user/caller forms, i simply make an object of FormsCollection and call the ShowForm method (almost a 100 such calls):
FormsCollection f = new FormsCollection();
f.ShowForm(FormsCollection.mainForm);
And after all this ordeal, what i get is that the same error appears at the very same spot as before! What an irony! :)
What am i doing wrong? Please help me out....

I got extremely hard-to-find answer to this problem from this slightly irrelevant page. Following is the updated code for any struggling programmers looking for a work around to this problem:
public void Show(Form nextForm)
{
Thread thread = new Thread(
new ThreadStart(() =>
{
PreviousForm.BeginInvoke(
new Action(() =>
{
PreviousForm = CurrentForm;
CurrentForm = nextForm;
PreviousForm.Hide();
CurrentForm.Show();
}
));
}
));
thread.Start();
}
This seems to have resolved the cross-thread problem that i was facing despite several work-arounds. It is working as yet without raising any exceptions and I have tested almost all the scenarios of my app going back and forth from form to form.

Related

Binding a ReactiveCommand prevents a ViewModel from being garbage collected

When I bind a "back button" to a the router in ReactiveUI, my ViewModel is no longer garbage collected (my view too). Is this a bug, or is this me doing something dumb?
Here is my MeetingPageViewModel:
public class MeetingPageViewModel : ReactiveObject, IRoutableViewModel
{
public MeetingPageViewModel(IScreen hs, IMeetingRef mRef)
{
HostScreen = hs;
}
public IScreen HostScreen { get; private set; }
public string UrlPathSegment
{
get { return "/meeting"; }
}
}
Here is my MeetingPage.xaml.cs file:
public sealed partial class MeetingPage : Page, IViewFor<MeetingPageViewModel>
{
public MeetingPage()
{
this.InitializeComponent();
// ** Comment this out and both the View and VM will get garbage collected.
this.BindCommand(ViewModel, x => x.HostScreen.Router.NavigateBack, y => y.backButton);
// Test that goes back right away to make sure the Execute
// wasn't what was causing the problem.
this.Loaded += (s, a) => ViewModel.HostScreen.Router.NavigateBack.Execute(null);
}
public MeetingPageViewModel ViewModel
{
get { return (MeetingPageViewModel)GetValue(ViewModelProperty); }
set { SetValue(ViewModelProperty, value); }
}
public static readonly DependencyProperty ViewModelProperty =
DependencyProperty.Register("ViewModel", typeof(MeetingPageViewModel), typeof(MeetingPage), new PropertyMetadata(null));
object IViewFor.ViewModel
{
get { return ViewModel; }
set { ViewModel = (MeetingPageViewModel)value; }
}
}
I then run, and to see what is up, I use VS 2013 Pro, and turn on the memory analyzer. I also (as a test) put in forced GC collection of all generations and a wait for finalizers. When that line is uncommented above, when all is done, there are three instances of MeetingPage and MeetingPageViewModel. If I remove the BindCommand line, there are no instances.
I was under the impression that these would go away on their own. Is the problem the HostScreen object or the Router that refers to an object that lives longer than this VM? And that pins things down?
If so, what is the recommended away of hooking up the back button? Using Splat and DI? Many thanks!
Following up on the idea I had at the end, I can solve this in the following way. In my App.xaml.cs, I make sure to declare the RoutingState to the dependency injector:
var r = new RoutingState();
Locator.CurrentMutable.RegisterConstant(r, typeof(RoutingState));
then, in the ctor of each view (the .xaml.cs code) with a back button for my Windows Store app, I no longer use the code above, but replace it with:
var router = Locator.Current.GetService<RoutingState>();
backButton.Click += (s, args) => router.NavigateBack.Execute(null);
After doing that I can visit the page as many times as I want and never do I see the instances remaining in the analyzer.
I'll wait to mark this as an answer to give real experts some time to suggest another (better?) approach.

construct GUI with event dispatch thread and make assignment

I'd like to do the following without making the variable gui final:
public class MainClass
{
GUIClass gui;
Runnable r = new Runnable()
{
public void run()
{
// this won't work!
gui = new GUIClass();
}
};
SwingUtilities.invokeLater(r);
Controller c = new Controller(gui);
}
How can I achieve that? I want to construct the gui via the EDT. At the same time I want to assign that new instance to the variable gui. But this won't work without making gui final. I don't want to use final because it's not possible in my context. Anyone any idea how this could be solved? The code above is of course executed within the main method. But for some reasons I couldn't post it here as an error occured.
For all those who should be interested in this issue someday, here's the solution:
I made a mistake. Actually you should differentiate between constructing the GUI-Object and making it visible. So here is the way to do that:
public class MainClass
{
final GUIClass gui = new GUIClass();
Runnable r = new Runnable()
{
public void run()
{
gui.pack();
gui.setVisible(true);
}
};
SwingUtilities.invokeLater(r);
Controller c = new Controller(gui);
}

WinForms Thread-safe Controls

I spend a lot of time working with Windows Forms controls but from a background worker thread - I suppose this is good practice really since you don't want your form to be locking up when people click buttons. To be honest, with just about everything GUI related action I normally do in a background worker thread, so the interface is nice an responsive to the user (Wish more people would do that!).
So my question is... every time I have to interact with controls I have to "Invoke" them, with something like:
if (control.InvokeRequired)
{
//
}
Standard practice right? However, this leads me to some terribly messy code, because just about every control type I have, I need a MethodInvoker delegate or something. It's adding thousands of lines of code to my protects, and its terribly time consuming.
I currently have hundreds of "property setting" methods like:
private void Safe_SetLableText(Label control, string text)
{
if (control.InvokeRequired)
{
control.Invoke((MethodInvoker)delegate
{
control.Text = text;
});
}
else
{
control.Text = text;
}
}
So, is there some other technique, or way to do this, or some way to being able to always alter a property of a control, no matter what the control is and no matter what thread im in?
something like: (pseudocode)
BackgroundWorker.RunWorkerAsync();
private void thing_to_do()
{
// We are in a background thread now
DoSomeDatabaseWorkThatTakesALongTime();
InvokeAnyControls();
// Do some stuff...
controlX.Text = "123"
controlY.Height = 300;
controlZ.text = ControlA.text;
RestoreAnyControls();
}
You could wrap your InvokeRequired code with a delegate, like so:
public static void Invoke2<TControl>(this TControl c, Action<TControl> code) where TControl : Control {
if( c.InvokeRequired ) c.Invoke( delegate() { code(c); } );
else code(c);
}
Then use it like so:
private void Safe_SetLableText(Label control, string text) {
control.Invoke2( c => c.Text = text );
}
Of course you might want better names than Invoke2, but I hope the idea sits will with you. Note that the lambda-expression syntax is a C# 3.0 feature, but the Action<T> delegate is part of .NET 2.0, so this will compile against the .NET Framework 2.0 so long as you're VS2008 or later.
I'm posting an answer to my own question because I think it will add value to the community.
1) I wanted to "simplify" my code, and one if the most important finds was that that the:
control.InvokeRequired
really isnt needed... its pretty much a given. Importantly, you CAN rely on the fact that the control will need to be invoked if you are in a background (or non-UI) thread.
2) The invocation travels "UP" the control tree, so if you have:
Form > Control > Control inside Control > etc > etc
You only need to invoke "Form" (top most), and then you can alter the properties of the child elements.
So here is my clean and simple solution to working with background workers (or non-UI threads). I have just tested this now and it works great.
public partial class Form1: Form
{
public Form1()
{
BackgroundWorker bgw = new BackgroundWorker();
bgw.DoWork += new DoWorkEventHandler(this.bgDoWork);
bgw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(this.bgComplete);
bgw.RunWorkerAsync();
}
private void bgComplete(object sender, EventArgs e)
{
// You are not in the UI thread now, so you can Invoke without error
this.Invoke((MethodInvoker)delegate
{
// Now you can change any property an any control within this form.
// Remember "this" refers to Form1.
this.label1.Text = "test123";
this.label2.Text = "test456";
this.label3.Text = this.label4.Text;
// You can set progress bars too, not just label text
}
}
private void bgDoWork(object sender, DoWorkEventArgs e)
{
// Do something that takes a long time
}
}
As you are already using the Background worker why don't you 'misuse' OnProgressChanged?
private void thing_to_do()
{
// We are in a background thread now
DoSomeDatabaseWorkThatTakesALongTime();
BackgroundWorker.ReportProgress(1, "state");
DoSomeMoreDatabaseWorkThatTakesALongTime();
BackgroundWorker.ReportProgress(2, YourObjectHere);
}
void OnProgressChanged(ProgressChangedEventArgs progressArgs)
{
switch(progressArgs.ProgressPercentage)
{
case 1:
// Do some stuff...
controlX.Text = "123"
controlY.Height = 300;
controlZ.text = ControlA.text;
break;
case 2:
// other stuff
YourObject obj = (YourObject) progressArgs.UserState;
// wahtever...
break;
default:
break;
}
}

Having trouble with AsyncTask using a recursive method

I've been reading about AsyncTasks and Hanlders and Loopers but I still can't figure out where I'm going wrong in my code. I'm trying to run code that will look over a Tic Tac Toe grid and determine the best move for the computer. I want this code to run in the background 'cause it can take some time and then I can update the UI level with a textbox that says something like "I'm Thinking". I've tried this a bunch of different ways, none with success.
private class PostTask extends AsyncTask<String, Integer, String> {
private Board _b;
private Welcome.Player _opp;
private int _depth;
#Override
protected void onPreExecute() {
super.onPreExecute();
}
protected void SetVars(Board b, Player p, int depth){
_b = b;
_opp = p;
_depth = depth;
}
#Override
protected String doInBackground(String... params) {
Looper.prepare();
try{
_bestMove = _b.GetBestMove(_opp,_depth);
}
catch(Exception err){
_bestMove = -1;
}
return "All done";
}
#Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
if(_bestMove == -1){
TextView tv = (TextView) findViewById(R.id.tv_Score);
tv.setText("Had and error, couldn't make a move.");
}
FollowUpComputerMove(this);
}
The above code will work for exactly 5 moves and then it crashes. When I watch in the debugger I see new theads being created named Thread<#> AsyncTask #1. Once I get to five of those AsyncTasks it goes back to try and grab the first AsyncTask and crashes. When it crashes I'm shown the ThreadPoolExecutor.class file.
I've also read that I shouldn't be using both the AsyncTask and the Looper objects together so I've tried taking the Loooper.prepare() statement out, but then my AsyncTask fails immediately with the error message:
Can't create handler inside thread that has not called Looper.prepare() - AsyncTask inside a dialog
I've read repeatedly that you shouldn't be trying to update the UI from an AsyncTask and that often the above error is because of that, but GetBestMove isn't updating the UI thread. When I trace through to see where the error comes, it fails when calling a constructor saying it can't find the class.
Can anyone point me in the right direction? My end goal is to use one main thread and only one background thread, and just keep re-using the background thread whenever the computer needs to make a move. I know that the recursive method GetBestMove works when I run this program in a single-thread manner. But the screen freezes for too long on some moves as the method is being run. Thank you so much.
-NifflerX
Apologies for answering my own question, but the issue I was facing had nothing to do with recursion. The class I was calling was extending the class Activity, and while trying to call that from an AsyncTask the program was erroring out. When I removed the extends Activity from the class definition it started working again. Sorry for the post.
-NifflerX

Garbage collecting issue with Custom viewbinding in mono touch and mvvmcross

I have a custom calendar control for which there is an custom viewbinding. In this viewbinding we hook up some events which are not decoupled correct and therefor is the garbage collecting not completed. In the following is our custom view binding. As you can see the event is hooked up in the constructor and decoupled in the OnSelectedDate event is triggered(the user selects an date). Therefore if you choose a date the event is decouple correct and garbage collected but if you just go back, the event is still hooked up and no garbage collecting is performed. I thought about trigger the event with null values and and thereby decoulpe the event. But I think there must be some more clever way to achieve this.
namespace CmsApp.Core.Binders
{
public class CalendarViewBinding:MvxBaseTargetBinding
{
private CalendarView _calendarView;
private DateTime _currentValue;
public CalendarViewBinding(CalendarView calendarView)
{
_calendarView = calendarView;
_calendarView.OnDateSelected+=OnDateSelected;
}
protected override void Dispose(bool isDisposing)
{
if(_calendarView!=null)
{
_calendarView.OnDateSelected -= OnDateSelected;
_calendarView = null;
}
base.Dispose(isDisposing);
}
private void OnDateSelected(object sender, SelectedDateEventArgs args)
{
_currentValue = args.SelectedDate;
this.FireValueChanged(_currentValue);
_calendarView.OnDateSelected -= OnDateSelected;
}
public override void SetValue(object value)
{
var date = (DateTime)value;
_currentValue = date;
_calendarView.SelectedDate = _currentValue;
}
public override Type TargetType
{
get
{
return typeof(DateTime);
}
}
public override MvxBindingMode DefaultMode
{
get
{
return MvxBindingMode.TwoWay;
}
}
}
}
Any help is appreciated :)
It looks to me like your binding is almost correct.
The only issue I can see is that it unsubscribes from the event too often - you can't call _calendarView.OnDateSelected -= OnDateSelected; twice - but I don't think this is the problem you are seeing.
I currently would guess that the problem is not in the code you are using:
either there's a bug in the binding code in the underlying framework you are using
or something is a bug/issue in the way you are using this binding
or your memory leak has nothing to do with this binding
It's not easy to test this from the limited code posted here, but it would be simpler if you could produce a simple app that reproduces the leak you are seeing. Share that and you might be able to get more feedback.
If you believe my guesses are wrong, then the only thing I can suggest is that you switch to WeakReferences inside your binding - but this feels like a sticking plaster rather than a cure.
Just adding a link to when to release objects in mono touch / mvvmcross

Resources