Cannot access non-static method in static context? - c#

Given this code....
public class CalibrationViewModel : ViewModelBase
{
private FileSystemWatcher fsw;
public CalibrationViewModel(Calibration calibration)
{
fsw = new FileSystemWatcher
{
Path = #"C:\Users\user\Desktop\Path\ToFile\Test_1234.txt",
Filter = #"Test_1234.txt",
NotifyFilter = NotifyFilters.LastWrite
};
fsw.Changed += (o, e) =>
{
var lastLine = File.ReadAllLines(e.FullPath).Last();
Dispatcher.BeginInvoke((Action<string>) WriteLineToSamplesCollection, lastLine); //line that cites error
};
}
private void WriteLineToSamplesCollection(string line)
{
// do some work
}
}
Why am I getting the error, 'Cannot access non-static method BeginInvoke in static context'?
I have looked at several other examples on SE and most cite trying to use a field before the object is created as if they were trying to use a non-static field in a static manner, but I don't understand what it is about my code that is invoking the same error.
Lastly, what can I do to fix this specific issue/code?
Update: Fixed title to reflect issue with a 'method' and not a 'property'. I also added that the class implements ViewModelBase.

If this is WPF, System.Windows.Threading.Dispatcher does not have a static BeginInvoke() method.
If you want to call that statically (this is, without having a reference to the Dispatcher instance itself), you may use the static Dispatcher.CurrentDispatcher property:
Dispatcher.CurrentDispatcher.BeginInvoke(...etc);
Be aware though, that doing this from a background thread will NOT return a reference to the "UI Thread"'s Dispatcher, but instead create a NEW Dispatcher instance associated with the said Background Thread.
A more secure way to access the "UI Thread"'s Dispatcher is via the use of the System.Windows.Application.Current static property:
Application.Current.Dispatcher.BeginInvoke(...etc);

Change this:
Dispatcher.BeginInvoke
to this:
Dispatcher.CurrentDispatcher.BeginInvoke
the issue is BeginInvoke is an instance method and needs an instance to access it. However, your current syntax is trying to access BeginInvoke in a static manner off the class Dispatcher and that's what's causing this error:
Cannot access non-static method BeginInvoke in static context

It's because Dispatcher is a class not a property. Shouldn't you be making your CalibrationViewModel class a subclass of some other class which has a Dispatcher property?

Related

Could .net Timer event handler modify a non-static variable [duplicate]

This question already has answers here:
CS0120: An object reference is required for the nonstatic field, method, or property 'foo'
(9 answers)
Closed 4 years ago.
c# Timer (System.Timers.Timer) is used to periodically trigger an event within windows form application. I would like to call function (for example logger() function) within the even handler. logger() is not a static method.
The function assigned to ElapsedEventHandler is a static function and therefore cannot call non-static methods.
Code example:
public partial class MainForm : Form {
//...
private MyClass myClass;
//...
}
private void SomeButton_Click(object sender, EventArgs e) {
//...
System.Timers.Timer t = new System.Timers.Timer(5000);
t.Elapsed += new ElapsedEventHandler(OnTimerElapsed);
t.Enabled = true;
//...
}
static void OnTimerElapsed(object sender, ElapsedEventArgs e) {
//...
// here call myClass.doSomething();
//...
}
How would be the correct way to go about this task? I do know that static variables/methods are not possible to be used within the OnTimerElapsed() - that is clear. I mainly ask to check whether there is another way of calling OnTimerElapsed(), maybe a non-static method or another timer type or handler method? Or if there is a way to pass the instance of myClass to the OnTimerElapsed()
Edit: it would be preferable to keep the myClass non-static, that is why this question.
you cannot access non-static i.e. instance field with in static function , that is reason its not working.
If you want to access instance field with in static function then you need instance of object and then you can access that instance field.
Or make field static then you can access field
if you make
static var someNonStaticVariable = 1000; // for example
it will work but then you need locking around that variable or Interlocked (userful if you just want to perform increment/decrement or excahnge i.e. for numeric operation).

InvalidOperationException when trying to access a complex object from another thread

After I tried lots and lots of solutions I couldn't solve this problem by any means so I started to believe that there is no solution for this problem.
I have an object that contains complex attributes. E.g: List<SomeComplexObject>. I am running a method from this class on a worker thread to keep the GUI running until the worker thread finishes. When it finishes execution, I want to use the attributes of these objects to update GUI let's say I want to use List<SomeComplexObject> looping through this list and update the GUI. But each time I try to access this list the debugger throws an InvalidOperationException: The calling thread cannot access this object because a different thread owns it.
I tried to make all attributes of this class volatile but with no hope I also used Lazy<T> class approach to solve but the same problem occurs.
Class that contain the worker function:
public class MainModules
{
#region Attributes
public VIDEO video;
public string VideoPath
{
get;
set;
}
LowLevelModule lowLevelOutput;
//this list that I want to use to Update GUI
public volatile List<FaceRecognitionModule> faceModuleOutput;
//worker function running on different thread
public void RunMainModules()
{
//some complex work to set the class attributes
}
}
Thread creation in GUI class
private void RunMainModules_BtnClick(object sender, RoutedEventArgs e)
{
// MainModule = new MainModules(mainModuleObj, Inpath, lif, keyframefolderpath, trdbpath, labelspath, rrankspath, alignmatpath, 11, 10);
this.LazyMainModule = new Lazy<MainModules>(this.InitLazyMainModule);
MainModuleThread = new Thread(this.RunMainModules);
MainModuleThread.Start(MainModule);
}
public MainModules InitLazyMainModule()
{
return new MainModules(mainModuleObj, Inpath, lif, keyframefolderpath, trdbpath, labelspath, rrankspath, alignmatpath, 11, 10);
}
public void RunMainModules(Object obj)
{
//MainModules mm = obj as MainModules;
MainModules mm = LazyMainModule.Value;
mm.RunMainModules();
this.Dispatcher.Invoke((Action)(() =>
{
this.InitSpeechRec_Btn.IsEnabled = true;
}));
}
When I try to access faceModuleOutput in class MainModules from GUI I got InvalidOperationException.
Image img = new Image();
//InvalidOperationException occurs here
img.Source = LazyMainModule.Value.faceModuleOutput[0].keyframes[1].keyframe;
To brief this post:
I want to access an object instantiated by a background thread from main thread but it throws
InvalidOperationException : The calling thread cannot access this object because a different thread owns it.
A UI control needs to be created/modified from the GUI Thread. Doing otherwise is illegal.
It seems that the MainModuleThread is (at least) creating and modifying an Image . This should be done in the GUI Thread (the one that called RunMainModules_BtnClick)
You cannot modify or even access pretty much anything that relates to the UI thread from another thread. This can get pretty extreme/annoying sometimes because you can't even get the value in a textbox or check if a checkbox is checked or not. If you want to perform an action on an object owned by the UI thread you need to invoke the UI thread to do it.
UIObject.Dispatcher.Invoke(() => {
//[Perform your action in here]
});
Finally I found the solution ... Class BitmapImage is thread-affine so it can't be accessed by multiple threads you need first to make it opened for reading only closed for writing so the compiler can guarantee that no threads will modify it's content
So the solution ... :
//keyframe here is a BitmapImage so on creation we must call keyframe.Freeze()
LazyMainModule.Value.faceModuleOutput[0].keyframes[1].keyframe;
class KeyFrame:
public class KeyFrame
{
public volatile BitmapImage keyframe;
public volatile List<string> personsNames;
public volatile List<string> categories;
public KeyFrame(BitmapImage keyframe, List<string> personsNames, List<string> categories)
{
this.keyframe = keyframe;
//here we call Freeze funcition on creation to make it modifiable
this.keyframe.Freeze();
this.personsNames = personsNames;
this.categories = categories;
}
}

Is it possible to reference MainWindow.cs from another class?

I have a WPF/C# program with several classes, and the MainWindow.cs class has user controls which I'd like to update with the status of the computation occurring inside other classes. After googling around and borrowing from examples, I figured out how to set up an Event inside the other class, and invoking it when something changed. Then as long as the main class has a handler tied that event, I could appropriately update UI stuff (status bars, etc). Below is a stripped-down version of what I'm doing:
namespace Program
{
public partial class MainWindow : Window
{
public void SetUpHandler()
{
TestA.WorkerProgressThingie += new ProgressChangedEventHandler(TestA_ProgressChanged);
}
void TestA_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar1.Value = e.ProgressPercentage
}
}
public class TestA
{
public static event ProgressChangedEventHandler WorkerProgressThingie;
public static void SomeFunction()
{
int value = 0;
//...(some boring code that does something here)
ProgressChangedEventArgs e = new ProgressChangedEventArgs(value, null);
if (WorkerProgressThingie != null)
WorkerProgressThingie.Invoke(null, e)
}
}
}
Is there not a way to simply call the progressBar property from the other class? (i.e. MainWindow.progressBar.Value)?
What is the purpose of the "object sender" parameter when I invoke the event, and how is it supposed to be used normally? The examples I see always use 'null'.
Thanks!
1) Yes, you can access any part of any class if it is declared public. In this case, you could declare the progressBar control as public, and anything that has a reference to class MainWindow can fiddle with it. HOWEVER, this would be pretty poor practice. Instead, you could bind to some 'value' which updates in relation to the current progress of the activity and let the MainWindow class worry about how it represents that change (in this case by updating a ProgressBar),
2) object sender in all events is meant to be a reference to the object which raised the event, so the event consumer knows where the event came from. Using null is also poor practice IMO, and in general, an object which raises an event should do so like;
SomeEvent(this, someEventArgs);

Running a piece of code just once in a class

I need to attach an event handler to an object, and I placed this code on a button click event. However, I noticed that this will cause the same event to attach multiple times with each click.
Is there a way to run a piece of code on class creation? The class in question is a static class btw.
I can do something like:
if (bool == false)
{
attach event handler;
bool = true;
}
Just not sure if this is the right way to do it. Thanks.
There are static constructors, that are (in principle) only run once per class.
Something like this:
public static class MyStaticClass
{
public static int MyStaticProperty;
//no accessors required, as this is never explicitly invoked
static MyStaticClass() //no parameters either
{
MyStaticProperty = 100;
}
}
....
//writes: 100
Console.WriteLine(MyStaticClass.MyStaticProperty);
However, if a constructor won't do it, because you have some parameters that need to be set, or there are some prerequisite steps that need to be done, I would indeed recommend a private boolean check, as you have done.
You use a constructor - it will run on class creation.
Constructors are class methods that are executed when an object of a class or struct is created. They have the same name as the class or struct, and usually initialize the data members of the new object.
For static classes, use static constructors:
A static constructor is used to initialize any static data, or to perform a particular action that needs to be performed once only. It is called automatically before the first instance is created or any static members are referenced.
try
if(Button1.Click == null)
Button1.Click += new System.EventHandler(this.myEventHandler);

How to use ISynchronizeInvoke without a reference to the Form

I need to "send" a piece of code from another thread (Excel Interop) to the UI thread to execute. Normally you'd use Invoke on the Form, which implements the ISynchronizeInvoke interface:
public class MyForm : Form
{
...
private void Button_Click(object sender, EventArgs e)
{
SomeExcelWorkbook.OnBeforeClose += delegate(ref bool Cancel)
{
this.Invoke(someCode);
};
}
}
Unfortunately there is a layer of abstraction between the form code and the code that defines the event handler, and I don't have a reference to the form at that point:
public void CodeExecutedByUIThread()
{
ISynchronizeInvoke sync;
SomeExcelWorkbook.OnBeforeClose += delegate(ref bool Cancel)
{
sync.Invoke(someCode);
};
}
When entering CodeExecutedByUIThread, we are still in the UI thread, so in theory everything needed should be there. Unfortunately the Form is the only class implementing that interface, is it?
How can I get an ISynchronizeInvoke from within the UI thread? Apparently Thread.CurrentThread doesn't provide it...
Or is there a way to get a SynchronizationContext? How would I retrieve and use that?
Update: Oh, I see, getting the SynchronizationContext object looks as simple as SynchronizationContext.Current, which doesn't need any reference to a form. So I'll google little bit more about how to use that.
In general, I think that neither is possible.
This might seem like an obvious answer, but what we used in this case was to store both the SynchronizationContext and the reference to the Form (as an ISynchronizeInvoke) in a static class at application startup.
MainForm main = new MainForm();
EnvironmentService.UI = main;
EnvironmentService.UIContext = SynchronizationContext.Current;
Application.Run(main);

Categories

Resources