0

I am converting my program from Winforms to WPF. With Winforms, it is easy to access a form from anywhere within code since the form seems to be static. However with WPF, I am finding this to be challenging. Example:

In WinForms, if I had a form with a text field, I could access it anywhere in code, and update the text field like so:

My.Forms.FormMain.txt_field.Value = "test"

In WPF, this same form is now a Window object and it seems the only way to call it globally is by using the following code:

Application.Current.MainWindow.txt_field.Value = "test"

The problem with using the Application.Current.MainWindow method is that this value is only available if the window is presented. My goal is to get a list of all of my Xaml Window objects and store them statically into global variables. This way if I need to update a property at a later time in code, I can easily do so.

So my question is, is this possible to accomplish in WPF?

Mike
  • 235
  • 3
  • 15
  • 2
    In WPF the pattern that is favored tends to be MVVM which allows you to bind your controls to just about anything. Is it not possible to instead change your text field to set its text from binding and instead of finding the active window then its controls, just set a property in a global view model and anything that depends on it will automatically change to display the value you've set? – Fabulous Jul 29 '18 at 20:41
  • Exactly, and you would probably bind to a "global" view model as shown here: https://stackoverflow.com/a/51537263/1136211 – Clemens Jul 29 '18 at 20:44
  • I've never seen the `My` namespace in WinForms. Is this perhaps a VB.NET thing? Is it autogenerated somehow? Also, what happens when you have multiple instances of `MyForm1` -- which one would `My.Forms.MyForm1` refer to? – Zev Spitz Jul 30 '18 at 18:26
  • Also note that this code -- `Application.Current.MainWindow.txt_field` will not compile, as the compiler doesn't know anything about `Application.Current.MainWindow` beyond that it inherits from the WPF `Window`. You have to explicitly cast it to your specific window type to use members defined in your window. – Zev Spitz Jul 30 '18 at 18:29

3 Answers3

0

There is a different way to implement WPF Window controls than WinForms, and that is through binding. To update the control's values, you have to set the Data Context of the Window with a view model. You have to implement a view model, which is a class file, implementing INotifyPropertyChanged interface. You have to declare properties here and notify the property changed event on their setter. Then bind those properties with your xaml controls. For details you can check 'Data Binding Overview' in WPF on msdn.

-1

I have never done this, but u can try with Properties. Something like

public string TexBoxValue 
{
  get {return txt_field.Value}
}`

But, i don't think this works with child window accessing parent window properties. Only other way around.

Other things u can do:

this way u can save your app important data and reused it after.

use Configuration Manager and store important in App.config file with Key - Value. You can also create your own XML file with some of your app settings with your own tags! It's easy and accessible from anywhere.

`

J.Memisevic
  • 429
  • 4
  • 11
-1

If I understand correctly, you are having trouble using Application.Current.MainWindow because it is typed as a WPF Window, which means you cannot refer to the controls on the window as members of the window.

The solution is to cast Application.Current.MainWindow to the type of the main window in your project (in the code below, MyMainWindow):

(Application.Current.MainWindow as MyMainWindow).txt_field.Value = "test'

The same applies to using windows via the Application.Current.Windows property, which holds a collection of all the open windows. Again, the Item property is typed as Window, so in order to use functionality defined in your windows, you have to cast them to the actual type of the window.

(Application.Current.Windows[0] as MyWindow).txt_field.Value = "test'
Zev Spitz
  • 13,950
  • 6
  • 64
  • 136
  • Not sure why this was marked down, but this is the closest answer I have seen that actually works. You are right about this only working if the window has already been created. WinForms seems to store all its Form data as static elements, so out of my own curiosity, I am wondering if the same can be achieved in WPF. But this solution will work with my MainWindow since the MainWindow is always created. It is a big help because I call the MainWindow throughout my code due to the nature of my program. – Mike Jul 30 '18 at 00:44
  • @Mike I thought the reason why you didn't want to use `Application.Current.MainWindow` was because you were trying to get to a non-main window. But I've just realized that while there is a `MainWindow` property on the `Application` object, it is only typed as `Window`. In order to refer to controls that are defined in your specific project, you have to cast it to the appropriate window type from your project. I've updated my answer accordingly. – Zev Spitz Jul 30 '18 at 00:52
  • @Mike I don't have enough experience with WinForms to say for certain, but the namespace you use in the question -- `My.Forms` -- seems like it is autogenerated based on the WinForms designer files. AFAIK there is no similar autogenerated namespace hierarchy in WPF, but as I said in my answer, you can cast the `MainWindow`, or any member of the `Windows` window collection, to the project-specific window type. – Zev Spitz Jul 30 '18 at 00:57
  • @Mike I seem to have completely missed the point of your question. Could you clarify why this doesn't help? – Zev Spitz Jul 30 '18 at 18:30
  • This does help for sure. I am just curious if Data Binding can also achieve what I need. The goal is to port over my WinForm project while keeping my static form variables intact. For example, FormMain.txt_field.Value = "test" in WinForm should translate to WPF. This way, I just set FormMain = (Application.Current.MainWindow as MyMainWindow) in a Module (or static class for C#). – Mike Jul 30 '18 at 19:16
  • @Mike Note that in VB.NET anything you put in a top-level `Module` will (in general) be globally available to the project, but in C# you'll have to explicitly `using static` of the class at the top of each file in order to do so. – Zev Spitz Jul 30 '18 at 19:50