If Winforms window can only be accessed from GUI thread can I assume that private static member variable in my user control can be used safely without mutex?
Related
I'm using HwndSource in a WPF window, which is not the main window, in order to hook a window procedure (WndProc) to receive some messages:
WinSource = HwndSource.FromHwnd(new WindowInteropHelper(this).Handle);
WinSource.AddHook(new HwndSourceHook(WndProc));
HwndSource implements IDisposable. MSDN is not clear about when/should I dispose it. The docs of HwndSource.FromHwnd explains the technique above:
You can use this method to return an HwndSource for a window that is not explicitly an interoperation window. The procedure for this is:
Create a WindowInteropHelper instance (providing the main Window as a constructor parameter).
Get the value of the Handle property from that WindowInteropHelper instance.
Pass that HWND value as a parameter to FromHwnd.
And then:
This technique can be useful if you then want to add general AddHook message processing to the window. However, whenever you create an HwndSource, you are also responsible for destroying it. This is true even if the Application object for an application HwndSource is disposed.
(the emphasis is mine)
However, at the HwndSource class doc, we see:
Object Lifetime
An HwndSource is a regular common language runtime (CLR) object, and its lifetime is managed by the garbage collector. Because the HwndSource represents an unmanaged resource, HwndSource implements IDisposable. [...] Calling Dispose explicitly from the interoperating code might be necessary for certain interoperation scenarios.
And regarding the hook:
The actual hooks are held by a weak reference. Therefore, make sure that you manage the lifetime of your hook delegate.
I can't give a full answer to this, but based on recent experience I can say that you should not dispose the HwndSource object too soon - specifically, not at all until the window it refers to is closed.
I was just debugging a scenario that was done like this:
using(var source = HwndSource.FromHwnd(window.HWnd()))
{
source.AddHook(hook);
}
The result of this was that the window became nonfunctional (no longer processing messages) right after the source was disposed.
Looking briefly into the reference source for FromHwnd(), it seems that it will always return you the same object for the same window. I think this is why you cannot dispose source just because your own code is done with it. Apparently HwndSource.Dispose() doesn't just clean up the HWndSource object, but some of the unmanaged window itself.
Having noticed this, now I also see the HWndSource documentation says:
Synchronously calling Dispose immediately destroys the Win32 window
which seems to be what I've observed.
i am trying to call a function in Form1 from WPF window and i am getting the following error
"Reference to a non-shared member requires an object reference."
also getting the same error when trying to access the Public variables in Form1 from wpf window.
is it not possiable to do it?
So according to the MSDN this error, this is a problem with trying to reference instance variables as if they are static.
If your class is Form1, you cannot access methods or variables that are not static by calling Form1.Method(). This won't work ever, not just in WPF. This is pretty basic stuff, you might want to read up more on VB. Check out Shared and Static documentation.
To access, for example, the method Show() on Form1, you must instantiate (create an instance of an object), and call the method on your object. Like this.
Dim frm As New Form1()
frm.Show()
I'd like to load Xaml from code running in a background thread.
I understand I would have to sync with the dispatcher. However, it fails (throws an exception).
Why?
Here is the code
public MainWindow()
{
InitializeComponent();
Thread thread = new Thread(new ThreadStart(delegate
{
Dispatcher.Invoke(new Action(delegate
{
Content = XamlReader.Parse(
"<Button xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'
Content='Hello World'/>");
}));
}));
thread.Start();
}
As Pavlo mentioned, you need to also set your content within the Dispatcher.
However, I will say - this is fairly useless.
Remember, when you call Dispatcher.Invoke or BeginInvoke, you're explicitly saying to run that code on the UI thread. By starting a background thread that does nothing but invoke back to the UI thread, you're effectively doing the same work on the UI thread, with the disadvantage of extra overhead being added to the system as well as harder debugging. In this case, you should just load the file directly.
This seems like a bad idea for a couple reasons. Are you expecting to get XAML fragments from a database or some other storage and you can't create the instances of these controls in C#? You could just create a Button directly.
Are you able to allow the data to drive your visualization? A good example of this is having a collection of ICommand objects (CommandViewModel, RelayCommand, etc) and a CommandView that you want to use to represent your command? In this case, it could be a <Button> with a binding to the CommandViewModel Title or Content property.
You're background thread could then be used to drive the population of data (collections, properties) and you're UI would be designed to flexibly accommodate the expected data patterns.
my issue is the following:
I have a windows form in which I've placed a LayoutPanel, when the forms Loads, multiple controls like: textboxes and labels are being added to the LayoutPanel.
Then on a button click, I need to process the data entered by the user on those dynamically created controls. For that purpouse I use a Backgroundworker which is supposed to take those controls and read their data.
My issue es that the Backgroundworker doesn't allows me to access the control from the DoWork Method, but I need to do it that way because I'll be reporting the progress of the operations.
Here are portions of my code to clarify the concept:
private void frmMyForm_Load(object sender, EventArgs e)
{
//I add multiple controls, this one is just for example
LayoutPanel1.add(TextBox1);
....
}
private void bgwBackground_DoWork(object sender, DoWorkEventArgs e)
{
foreach (Control controlOut in LayoutPanel1.Controls)
{
//do some stuff, this one is just for example
string myString = controlOut.Name; //-> Here is the error, cant access controls from different Thread.
}
}
Setting text is simple just using a delegate, but how about getting the entire parent control to manipulate the child controls (just for getting info, I don't want to set any data, just need to Get Name, Text, stuff like that).
Hope I made myself clear, thank you all.
You can only access Windows Forms controls from the GUI thread. If you want to manipulate them from another thread, you will need to use the Control.Invoke method to pass in a delegate to execute on the GUI thread. In your situation, you should be able to do this:
private void bgwBackground_DoWork(object sender, DoWorkEventArgs e)
{
foreach (Control controlOut in LayoutPanel1.Controls)
{
this.Invoke(new MethodInvoker(delegate {
// Execute the following code on the GUI thread.
string myString = controlOut.Name;
}));
}
}
I like to define an extension method that allows me to use the cleaner lambda syntax:
// Extension method.
internal static void Invoke(this Control control, Action action) {
control.Invoke(action);
}
// Code elsewhere.
this.Invoke(() => {
string myString = controlOut.Name;
});
As you are already aware, accessing control values from any thread other than the UI thread is a big no-no. I'd say one reasonable implementation is to use a .NET synchronization mechanism, such as a WaitHandle, to suspend your background thread while the UI thread updates a thread-safe data structure of your choice.
The idea is that your background thread notifies the UI thread (via the delegate mechanism you are already familiar with) that it needs information, then waits. When the UI is finished populating the shared variable with information, it resets the WaitHandle, and the background worker resumes.
Without writing out and testing all the code, let me give you a few resources:
WaitHandle.WaitOne documentation with example usage: http://msdn.microsoft.com/en-us/library/kzy257t0.aspx
My own favorite method of invoking an event on the UI thread: http://www.notesoncode.com/articles/2009/01/24/PowerfulExtensionMethodsPart1.aspx
I have a windows form that contains many controls e.g timers, gridviews, and binding sources etc, and all of these expose a dispose function. Do I have to call their dispose function in this
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
// do I have to write something here ???
base.Dispose(disposing);
}
also what does components.Dispose() exactly do?
thanks
Generally when you add controls onto your forms via the toolbox in Visual Studio, the controls will automatically be Disposed for you (in the protected override void Dispose method).
The only time you do need to manually dispose objects is when you manually create other disposable objects that implement the IDisposable interface, things like file handles (Stream, StreamReader...), GDI objects (Bitmap, Brush) and unmanaged resources. Manually releasing objects of this type ensure you follow good coding practice by releasing the resources you create.
No, the form will call Dispose for you.
What is Dispose for? This is taken from here IDispose
Use the Dispose method of this
interface to explicitly release
unmanaged resources in conjunction
with the garbage collector. The
consumer of an object can call this
method when the object is no longer
needed
The base.Dispose call invokes the System.Windows.Forms.Form.Dispose, which disposes menus and other form controls. The call ends up in System.Windows.Forms.Control.Dispose, which recursively disposes all child controls.
I guess you don't need to worry as long as your control is reachable from the form, either directly or transitively.