I'm developing an SCVMM 2012 console Add-In.
The SDK documentation can be found here: http://msdn.microsoft.com/en-us/library/jj860311.aspx
But the documentation has no info on threading or how the add-in gets executed at all.
Now here's what I have:
public class SomeAddIn : ViewAddInBase
{
private bool gotServerInfo = false;
private bool gotConnectionString = false;
public override FrameworkElement CreateViewControl()
{
GetServerInfo();
GetConnectionString();
if(gotServerInfo && gotConnectionString)
{
return GetGoodFrameworkElement(); //do some stuff to fill FrameworkElement
}
MessageBox.Show("Can't connect to DB, returning empty screen...");
return new FrameworkElement();
}
private void GetServerInfo()
{
PowerShellContext.ExecuteScript<ServerConnection>("Get-SCVMMServer localhost",
(items, error) =>
{
// code to set server info here
if (error == null)
{
gotServerInfo = true;
MessageBox.Show("Got settings from server.");
}
else{//Error}
});
}
private void GetConnectionString()
{
//PowerShell connect to database, get connection string
gotConnectionString = true; //if got string
}
}
Looks all good, but the problem is that powershell commands take time to execute and the "return new FrameworkElement();" gets executed first before gotServerInfo and gotConnectionString get set to true.
My guess is that VMM starts multiple threads for my methods and the execution of those is not sequential anymore. How do I get VMM to execute my methods in the right order?
What I've tried to do:
1) use threads for my methods, set priority to high, set current
thread priority to low or even as background, yet this doesn't help.
Thread.Join doesn't work either.
2) move my methods to "public override void OnLoad() or
OnShow(). The CreateViewControl() gets executed first anyway.
Any ideas?
Not a solution to the problem occurring during initialization, but I moved on to MVVM (WPF) and a separate threading model. After you get the basic interface up, it's up to you what you want to do and how to synchronize everything. VMM latter acts as a usual WPF application giving you one main thread for the interface. Use ThreadPool class for dispatching background tasks - found it's the easiest way to do it.
Related
I know you don't understand the question title. Let me tell you the whole scenario.
I have a class named as Processor. Processor can get notifiable steps or send notification to other application API depending on some condition. Like as below:
Method: SendOrStartProcess(Operation operation)
Method Implementation:
If(operation.steps.any(o=>o.canProcess)){
_service.notify(operations); //This is fine
}
else{
var totalSteps = await _service.getAdjustableSteps(); //It returns the adjustable steps and will invoke event which is subscribed by another class named as GetAdjustableStepsEnd. It can be invoked immediately or after some time.
//Set totalSteps in operationsc.steps and save in database and that's it.
}
Now, I have another class named as "OperationHandler" which subscirbed the GetAdjustableStepsEnd event.
public OperationHandler(IUnityContainer container)
{
_agent.GetAdjustableStepsEnd += GetAdjustableStepsEnd ;
}
public async void GetAdjustableStepsEnd (object sender, GetAdjustableStepsEndEventArgs e)
{
// Here i will call again the above method _processor.SendOrStartProcess(e.Operations);
}
//Now the problem is if event invokes after some time then it is fine because meanwhile i set the status in database. But if it invoked just after the getAdjustableSteps then i call SendOrStartProcess again and it sends getAdjustableSteps again because record is not set in the database. How to overcome this situation. I can not put lock on it because this is used by many clients.
I have recently made a Class Library (dll) for my other project to program a Bluetooth device via serial port (COM). The library is used to transfer firmware via COM port. It works fine until the requirement comes, which requires a WPF window to show the progress of programming. I have successfully created the progress bar using standard WPF app template. However, the standard WPF does not allow me to generate dll. After searching here, I found this link that teaches you how to add a WPF window to existing Class Library project. Also, someone teaches you how to show the window from here. Everything look good until I tried, there is nothing shows up when I call the method ProgrammBluetooth() from LabVIEW.
My main method, which is in a separate .cs file:
namespace BTMProg
{
public class BTMProgrammer
{
private bool _uut1Status = false;
private string _uut1Message = "";
public bool UUT1Status
{
get { return _uut1Status; }
set { _uut1Status = value; }
}
public string UUT1Message
{
get { return _uut1Message; }
set { _uut1Message = value; }
}
public void ProgramBluetooth (string ioPort, string firmwareFile)
{
List<UUT> uutList = new List<UUT>();
uutList.Add(new UUT(ioPort, "UUT1", 1));
Thread thread = new Thread(() =>
{
var wn = new MainWindow(uutList, firmwareFile);
wn.ShowDialog();
wn.Closed += (s, e) => wn.Dispatcher.InvokeShutdown();
Dispatcher.Run();
if (wn.TaskList[0].Result.ToUpper().Contains("SUCCESS"))
{
_uut1Status = true;
_uut1Message = wn.TaskList[0].Result;
}
else
{
_uut1Status = false;
_uut1Message = wn.TaskList[0].Result;
}
});
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
}
}
}
My WPF code in MainWindow.xaml.cs:
ProgrammingViewModel _pvm = new ProgrammingViewModel();
private List<string> _viewModeList = new List<string>();
private List<Task<string>> _taskList = new List<Task<string>>();
public List<Task<string>> TaskList {
get => _taskList;
set => _taskList = value;
}
public MainWindow(List<UUT> uutList, string firmwareFile)
{
InitializeComponent();
foreach (var uut in uutList)
{
_viewModeList.Add(uut.UutName);
}
_pvm.AddProcessViewModels(_viewModeList);
ProgressBarView.DataContext = _pvm.ProcessModels;
StartProgramming(uutList, firmwareFile);
Application.Current.MainWindow.Close();
}
The issue before was that if I don't use dispatcher to create a new thread, an exception saying "The calling thread must be STA, because many UI components require this...." thrown. After I use the new thread, no error but the window does not show up as expected. What could be the problem? Thanks.
The ShowDialog function will stop execution of the thread until the window closes, meaning the rest of that code may not run and the dispatcher may not be started. You should try the Show method instead, which returns as soon as the window is shown.
Also, what is going on with these lines in the constructor of the window?
StartProgramming(uutList, firmwareFile);
Application.Current.MainWindow.Close();
Whatever that first line does, it needs to return and not do a bunch of work if you want the window to finish getting constructed. The second line makes no sense at all. Why are you closing the main window of the application? Did you even set and open a window associated with that property at some point?
I suspect one or more of these things is preventing the thread from ever reaching the point where it can show the window.
We have built a huge winforms project, already in progress for multiple years.
Sometimes, our users get an exception which looks like this one.
The resolution of this problem seems to be:
don't acces UI components from a background thread
.
But since our project is a very big project with a lot of different threads, we don't succeed in finding all these.
Is there a way to check (with some tool or debugging option) which components are called from a background thread?
To clarify:
I created a sample winforms project with a single Form, containing two Button
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
button1.Text = "Clicked!";
}
private void button2_Click(object sender, EventArgs e)
{
Task.Run(() =>
{
button2.BackColor = Color.Red; //this does not throw an exception
//button2.Text = "Clicked"; //this throws an exception when uncommented
});
}
}
The background color of button2 is set to red when the button is clicked. This happens in a background thread (which is considered bad behavior). However, it doesn't (immediately) throw an exception. I would like a way to detect this as 'bad behavior'. Preferably by scanning my code, but if it's only possible by debugging, (so pausing as soon as a UI component is accessed from a background thread) it's also fine.
I've got 2 recommendations to use together, the first is a Visual Studio Plugin called DebugSingleThread.
You can freeze all the threads and work on one at a time (obviously the non-main-UI threads) and see each threads access to controls. Tedious I know but not so bad with the second method.
The second method is to get the steps in order to reproduce the problem. If you know the steps to reproduce it, it will be easier to see whats causing it. To do this I made this User Action Log project on Github.
It will record every action a user makes, you can read about it here on SO: User Activity Logging, Telemetry (and Variables in Global Exception Handlers).
I'd recommend you also log the Thread ID, then when you have been able to reproduce the problem, go to the end of the log and work out the exact steps. Its not as painful as it seems and its great for getting application telemetry.
You might be able to customise this project, eg trap a DataSource_Completed event or add a dummy DataSource property that sets the real Grids DataSource property and raises an INotifyPropertyChanged event - and if its a non-main thread ID then Debugger.Break();.
My gut feeling is you're changing a control's (eg a grid) data source in a background thread (for that non-freeze feel) and thats causing a problem with synchronisation. This is what happened to the other DevExpress customer who experienced this. Its discussed here in a different thread to the one you referenced.
Is your app set to ignore cross threading intentionally?
Cross-thread operations should be blowing up all the time in winforms. It checks for them like crazy in just about every method. for a starting point check out https://referencesource.microsoft.com/#System.Windows.Forms/winforms/Managed/System/WinForms/Control.cs.
Somewhere in your app, somebody might have put this line of code:
Control.CheckForIllegalCrossThreadCalls = False;
Comment that out and run the app, then follow the exceptions.
(Usually you can fix the problem by wrapping the update in an invoke, e.g., in a worker thread if you see textbox1.text=SomeString; change it to `textbox.invoke(()=>{textbox1.text=SomeString;});.
You may also have to add checking for InvokeRequired, use BeginInvoke to avoid deadlocks, and return values from invoke, those are all separate topics.
this is assuming even a moderate refactor is out of the question which for even a medium sized enterprise app is almost always the case.
Note: it's not possible to guarantee successful discovery of this case thru static analysis (that is, without running the app). unless you can solve the halting problem ... https://cs.stackexchange.com/questions/63403/is-the-halting-problem-decidable-for-pure-programs-on-an-ideal-computer etc...
I did this to search for that specific situation but of course, need to adjust it to your needs, but the purpose of this is to give you at least a possibility.
I called this method SearchForThreads but since it's just an example, you can call it whatever you want.
The main idea here is perhaps adding this Method call to a base class and call it on the constructor, makes it somewhat more flexible.
Then use reflection to invoke this method on all classes deriving from this base, and throw an exception or something if it finds this situation in any class.
There's one pre req, that is the usage of Framework 4.5.
This version of the framework added the CompilerServices attribute that gives us details about the Method's caller.
The documentation for this is here
With it we can open up the source file and dig into it.
What i did was just search for the situation you specified in your question, using rudimentary text search.
But it can give you an insight about how to do this on your solution, since i know very little about your solution, i can only work with the code you put on your post.
public static void SearchForThreads(
[System.Runtime.CompilerServices.CallerMemberName] string memberName = "",
[System.Runtime.CompilerServices.CallerFilePath] string sourceFilePath = "",
[System.Runtime.CompilerServices.CallerLineNumber] int sourceLineNumber = 0)
{
var startKey = "this.Controls.Add(";
var endKey = ")";
List<string> components = new List<string>();
var designerPath = sourceFilePath.Replace(".cs", ".Designer.cs");
if (File.Exists(designerPath))
{
var designerText = File.ReadAllText(designerPath);
var initSearchPos = designerText.IndexOf(startKey) + startKey.Length;
do
{
var endSearchPos = designerText.IndexOf(endKey, initSearchPos);
var componentName = designerText.Substring(initSearchPos, (endSearchPos - initSearchPos));
componentName = componentName.Replace("this.", "");
if (!components.Contains(componentName))
components.Add(componentName);
} while ((initSearchPos = designerText.IndexOf(startKey, initSearchPos) + startKey.Length) > startKey.Length);
}
if (components.Any())
{
var classText = File.ReadAllText(sourceFilePath);
var ThreadPos = classText.IndexOf("Task.Run");
if (ThreadPos > -1)
{
do
{
var endThreadPos = classText.IndexOf("}", ThreadPos);
if (endThreadPos > -1)
{
foreach (var component in components)
{
var search = classText.IndexOf(component, ThreadPos);
if (search > -1 && search < endThreadPos)
{
Console.WriteLine($"Found a call to UI thread component at pos: {search}");
}
}
}
}
while ((ThreadPos = classText.IndexOf("Task.Run", ++ThreadPos)) < classText.Length && ThreadPos > 0);
}
}
}
I hope it helps you out.
You can get the Line number if you split the text so you can output it, but i didn't want to go through the trouble, since i don't know what would work for you.
string[] lines = classText.Replace("\r","").Split('\n');
Try that:
public static void Main(string[] args)
{
// Add the event handler for handling UI thread exceptions to the event.
Application.ThreadException += new ThreadExceptionEventHandler(exception handler);
// Set the unhandled exception mode to force all Windows Forms errors to go through the handler.
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
// Add the event handler for handling non-UI thread exceptions to the event.
AppDomain.CurrentDomain.UnhandledException += // add the handler here
// Runs the application.
Application.Run(new ......);
}
Then you can log the message and the call stack and that should give you enough information to fix the issue.
I recommend you update your GUI to handle this situation automatically for your convenience. You instead use a set of inherited controls.
The general principle here is to override the property Set methods in a way to make them Thread Safe. So, in each overridden property, instead of a straight update of the base control, there's a check to see if an invoke is required (meaning we're on a separate thread the the GUI). Then, the Invoke call updates the property on the GUI thread, instead of the secondary thread.
So, if the inherited controls are used, the form code that is trying to update GUI elements from a secondary thread can be left as is.
Here is the textbox and button ones. You would add more of them as needed and add other properties as needed. Rather than putting code on individual forms.
You don't need to go into the designer, you can instead do a find/replace on the designer files only. For example, in ALL designer.cs files, you would replace System.Windows.Forms.TextBox with ThreadSafeControls.TextBoxBackgroundThread and System.Windows.Forms.Button with ThreadSafeControls.ButtonBackgroundThread.
Other controls can be created with the same principle, based on which control types & properties are being updated from the background thread.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace ThreadSafeControls
{
class TextBoxBackgroundThread : System.Windows.Forms.TextBox
{
public override string Text
{
get
{
return base.Text;
}
set
{
if (this.InvokeRequired)
this.Invoke((MethodInvoker)delegate { base.Text = value; });
else
base.Text = value;
}
}
public override System.Drawing.Color ForeColor
{
get
{
return base.ForeColor;
}
set
{
if (this.InvokeRequired)
this.Invoke((MethodInvoker)delegate { base.ForeColor = value; });
else
base.ForeColor = value;
}
}
public override System.Drawing.Color BackColor
{
get
{
return base.BackColor;
}
set
{
if (this.InvokeRequired)
this.Invoke((MethodInvoker)delegate { base.BackColor = value; });
else
base.BackColor = value;
}
}
}
class ButtonBackgroundThread : System.Windows.Forms.Button
{
public override string Text
{
get
{
return base.Text;
}
set
{
if (this.InvokeRequired)
this.Invoke((MethodInvoker)delegate { base.Text = value; });
else
base.Text = value;
}
}
public override System.Drawing.Color ForeColor
{
get
{
return base.ForeColor;
}
set
{
if (this.InvokeRequired)
this.Invoke((MethodInvoker)delegate { base.ForeColor = value; });
else
base.ForeColor = value;
}
}
public override System.Drawing.Color BackColor
{
get
{
return base.BackColor;
}
set
{
if (this.InvokeRequired)
this.Invoke((MethodInvoker)delegate { base.BackColor = value; });
else
base.BackColor = value;
}
}
}
}
so after more than a week of trying to solve it on my own I officially give up and turn to your help. Basically, it should not be so complicated so I have no idea why it does not work. I have a WPF app which contains a Main Window called surprise surpise...: Main_Window.
That window contain a user control called 'pageTransitionControl' that change its content according to what the client want to see. the 'pageTransitionControl' is there to support multiple animations and so on... Anyway, among all of the user controls, i have a preety havy uc called ucBanks. before it shows, the ucBanks load a lot of data, manipulating it and display it on a very beautiful and smart charts. the problem is it takes some time to load it, approximately 6-7 seconds so i need the UI to show 'Loading' animation during that time (another user control called 'ucSpinner').
I'm Trying to load the ucBanks on a different thread to avoid freezing the application and it works great: the ucSpinner is showed immidiatlly and the ucBanks is loading on the background but when i change the content of the 'pageTransitionControl' i get this error:
"The calling thread cannot access this object because a different thread owns it".
I think i tried basically everything but i must missing somthing or doing somthing wrong.
This is where it all start, the btn_click event that load ucBanks:
ShowSpinner();
Thread.Sleep(100);
Thread newThread = new Thread(new ThreadStart(LoadUc));
newThread.SetApartmentState(ApartmentState.STA);
newThread.IsBackground = true;
newThread.Start();
This is the ShowSpinner method:
private void ShowSpinner()
{
ucSpinner.Opacity = 1;
}
and this is the LoadUc method:
private void LoadUc()
{
ucOsh ucOshx = new ucOsh();
Utils.LoadUc(ucOshx, null, PageTransitions.PageTransitionType.GrowAndFade, true, this, null, true);
}
With the LoadUc i called static class called 'Utils' holding the 'LoadUc' method:
public static void LoadUc(System.Windows.Controls.UserControl ucParent, System.Windows.Controls.UserControl ucChild, PageTransitions.PageTransitionType tranType, bool removeChildrens = true, System.Windows.Window w = null, List<Plist.Plist> lst = null, bool hideMenu = false)
{
MainWindow win = null;
if (w != null) { win = (MainWindow)w; }
else { win = (MainWindow)System.Windows.Window.GetWindow(ucChild); }
win.Dispatcher.Invoke(
System.Windows.Threading.DispatcherPriority.ContextIdle, (System.Action)delegate
{
win.pageTransitionControl.TransitionType = tranType;
win.pageTransitionControl.PARAMS = lst;
win.pageTransitionControl.Tag = ucParent.ToString();
win.pageTransitionControl.pages.Push(ucParent);
win.pageTransitionControl.Content = ucParent; ----------->>>>This is where i get the error!!!
});
}
I understand that the main window is locked inside another thread but i cant see any other option to load it without freezing the entire app.
Does anyone have a suloution to my problem? SA :-) ?
What I have tried:
i tried working with background-worker, i chaned all of the settings of the dispatcher, loaded the user control inside and outside the threads...
I'm suddenly getting a strange error while debugging. Up to now the variable in the watch windows has been showing correctly. Now I am always getting this error message in the watch windows:
The function evaluation requires all threads to run
I am not able to check any variable anymore. I am not explicitly working with threads. What can I do to get it working again?
I already disabled, as mentioned in some forums, the function: "Enable property Evaluation and other implicit function Calls" in the option window of the debugger. But without success, and it gives me this error:
Error Implicit Function evaluation disabled by the user
From the msdn forum:
This isn't an error in and of itself, but more of a feature of your debugger.
Some properties require code to be executed in order for the property to be read, but if this requires cross-thread interaction, then other threads may have to run as well. The debugger doesn't do this automatically, but certainly can, with your permission.
Just click the little evaluate icon and it will run your code and evaluate the property.
For further details on this behaviour check this excelent article
I ran into this issue when just trying to get items from a table called "AGENCY" using Entity Framework:
var agencies = db.AGENCY.OrderBy(e => e.FULLNAME);
Hovering over agencies in debug mode, clicking to expand the options, and clicking Results would give the dreaded "The function evaluation requires all threads to run" with a "Do Not Enter" icon at the end that, on which, clicking did nothing.
2 possible solutions:
Add .ToList() at the end:
var agencies = db.AGENCY_TABLE.OrderBy(e => e.FULLNAME).ToList();
List<AGENCY_TABLE> agencies = db.AGENCY_TABLE.OrderBy(e => e.FULLNAME).ToList();
Credit goes to Hp93 for helping me come to this solution. In the comments on MUG4N's answer where I found this solution, it also mentions trying .Any() instead of .ToList(), but this gives a Boolean instead of a <T>, like <AGENCY> is, so it probably wouldn't help.
Workaround - try a different path in the debug options. I found that I could click on the "Non-Public Members" > "_internalQuery" > ObjectQuery > Results View and get my values that way.
MUG4N has indeed provided a correct answer however if you hover over the line of code in debug, you may be looking at something like the below. If so, click the little re-evaluate icon highlighted in the image below...
NB: I obtained this image by pinning, normally the re-evaluate icone are in the middle of the window and not down the left hand column.
You should make thread safe call because accessing Windows form controls are not Thread safe in multithreading.
This is my simple code which makes Thread safe call and sets Progress bar.
public partial class Form1 : Form
{// This delegate enables asynchronous calls for setting
// the text property on a TextBox control.
delegate void StringArgReturningVoidDelegate(string text);
private Thread demoThread = null;
public int Progresscount = 0;
static EventWaitHandle waithandler = new AutoResetEvent(false);
public Form1()
{
InitializeComponent();
}
public static bool CheckForInternetConnection()
{
try
{
using (var client = new WebClient())
{
using (var stream = client.OpenRead("http://www.google.com"))
{
return true;
}
}
}
catch
{
return false;
}
}
public void Progressincrement()
{
waithandler.WaitOne();
while (CheckForInternetConnection()==true)
{
if (Progresscount==100)
{
break;
}
SetLabel("Connected");
Progresscount += 1;
SetProgress(Progresscount.ToString());
Thread.Sleep(TimeSpan.FromSeconds(1));
}
if (Progresscount <100)
{
Startthread();
}
SetLabel("Completed");
}
public void Startthread ()
{
this.demoThread= new Thread(new ThreadStart(Progressincrement));
this.demoThread.Start();
SetLabel("Waiting for connection");
while (CheckForInternetConnection() == false) ;
waithandler.Set();
}
private void SetLabel(string text)
{
// InvokeRequired required compares the thread ID of the
// calling thread to the thread ID of the creating thread.
// If these threads are different, it returns true.
if (this.label1.InvokeRequired)
{
StringArgReturningVoidDelegate d = new StringArgReturningVoidDelegate(SetLabel);
this.Invoke(d, new object[] { text });
}
else
{
this.label1.Text = text;
}
}
private void SetProgress(string Value)
{
// InvokeRequired required compares the thread ID of the
// calling thread to the thread ID of the creating thread.
// If these threads are different, it returns true.
if (this.progressBar1.InvokeRequired)
{
StringArgReturningVoidDelegate d = new StringArgReturningVoidDelegate(SetProgress);
this.Invoke(d, new object[] {Value});
}
else
{
this.progressBar1.Value = Convert.ToInt32(Value);
}
}
private void Form1_Load(object sender, EventArgs e)
{
Startthread();
}
private void button1_Click(object sender, EventArgs e)
{
MessageBox.Show("Responsive");
}
}
For more information MSDN
This isn't an error, but more of a feature of your debugger.
The debugger doesn't do this automatically, but certainly can, with users permission. Just click the little space icon and it will run the code and evaluate the property.
I use the next workaround to pass:
var OtherThreadField = "";
Invoke(new MethodInvoker(delegate
{
OtherThreadField = ExecuteNeededMEthod();
}));
Now i have a value for OtherThreadField.
I faced the same issue and solved .The Issue arise due to username and password ,in SQL connection there is user and password but in code there no user and password. so I enable the user and the password and the issue solved
For me, this happened when trying to break on a line that accesses a complex object instance contained by a Settings Class.
A breakpoint on the following if results in Settings.Default.FindSettings with the value being "The function evaluation requires all threads to run." If I press the force eval button, it is null. Stepping with the force eval button click or not enters the if block and initializes the object. If I remove the breakpoint and add a new breakpoint following the if block, the Settings.Default.FindSettings deserializes properly with the expected values.
if (Settings.Default.FindSettings == null)
{
Settings.Default.FindSettings = new FindSettings();
}
After trial and error, I added the following code before the above if block to access the settings prior to breaking. This seems to reliably fix the problem. I do not need it in production so I wrap in conditional compiler directive. I have a comment in the code instead of a non-descript discard:
#if DEBUG
var _ = Settings.Default.FindSettings;
#endif
I am not sure if the above line would be optimized out in production since it has side effects. As I only need it while debugging, I have not checked.