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?
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.
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.
`
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'
Related
Right. So moving from WPF to UWP, I'm trying to use x:Bind to get compile-time benefits. Simple scenarios work fine; however I have found a number of issues that I was not able to solve. They are all related, so I thought I'd post them in one place:
I haven't been able to make Intellisense work with x:Bind. I have set DataContext (as well as d:DataContext just as we do in WPF) both in XAML and in the constructor, but it won't show members no matter what. Has anyone done this successfully?
Then I read somewhere that in UWP, DataContext is always set to Page's code-behind (really??) and that I need to define a ViewModel type property in the code-behind and then use that property in x:Bind. Is this correct? I tried it and it works but gives rise to the next question.
If I define a property of ViewModel type in Page's code-behind, Any sub-properties that raise PropertyChanged notifications do not update the UI. For example, if the code-behind property is named Game (of type GameVM) and there is a public property in GameVM named Player (of type GamePlayer), and in turn GamePlayer contains a property named Name, the x:Bind path will look like {x:Bind Path=Game.Player.Name}. But if I do this, any change notifications raised from within Name property do not update Page's UI.
One alternate I tried was to listen to PropertyChanged at each level and then bubble it up the hierarchy, but that hasn't worked. Even if it does, doing this seems a bit too much work. In WPF sub-properties like Game.Player.Name work properly without having to doing property change bubbling. Or am I missing something?
Right. After playing with it for a few days and searching numerous references, here are my findings:
{x:Bind} lacks design-time support. The feature is on the wishlist though. You may want to upvote it there.
(The new version of Visual Studio 15.4.4 does support Intellisense in {x:Bind}in the required way.)
{x:Bind} uses code-behind as its DataContext. So you need to define a public property of your ViewModel type in the code-behind and then use it in your {x:Bind} path.
As pointed out by IInspectable, the default mode for {x:Bind} is OneTime, unlike {Binding} which uses OneWay or TwoWay in almost all cases. So you need to explicitly specify Mode in your binding. People coming from WPF should take special care of it.
Sub-properties that implement notification change work perfectly fine in {x:Bind}. There is no need of bubbling these notifications upwards in the property hierarchy. The problem I was facing (#3 in the question) was because my sub-property was of type List<T>. I changed it to ObservableCollection<T> and it started working.
Hope this works somebody down the road.
Well as a beginner, the only question I can answer for you is the first one. Intellisense does not work inside the {x:Bind}. The members are never shown there in UWP for some unknown reasons. As for the next two questions of yours, I am still working on them.
I ran into the same challenge that you have seen. In my experience, in order to create the compile-time binding and have it update with custom objects as properties, the Page class seems to need to know about the data context and custom objects... all you need to do is reference them in the code behind, and then bind to them in the XAML. This creates the code generation objects it needs.
For example, I have a viewmodel, CustomerViewModel that is bound in XAML. That viewmodel also has a property of type IGuest. In order to use the guest object and have it update properly, I came up with this in the code behind...
CustomerViewModel vm
{
get
{
return (CustomerViewModel)DataContext;
}
}
IGuest g
{
get
{
return vm.CurrentGuest;
}
}
public CartGuestControl()
{
this.InitializeComponent();
}
You don't need to assign any of the UI data contexts from the code behind... simply reference the datacontext that is bound in XAML. When binding to any straight viewmodel properties, I use {x:Bind Path=vm.IsEditing, Mode=OneWay}. For binding to any of the guest properties, it looks like this, {x:Bind Path=g.FirstName, Mode=TwoWay}. You could do something like this for your Player object.
I have run into times where x:Bind simply won't do what I expect it to do no matter what I try. This can usually be solved by breaking things out into smaller user controls with more specific data contexts or by using "regular" Binding.
I was recently working with a lot of bindings to my configuration settings in XAML. Storing column widths/control sizes/window positions and the like. So I was wondering if there was an easy way to create and bind to "settings/configuration" values to XAML?
Right now I just create a setting in the project, shove a bindable property into the XAML's DataContext and go from there. But my settings count is getting pretty crazy and managing them is getting painful (boring, repetitive, and annoying).
In an ideal world I'd like a system where I can do something like this:
<Window State={Binding {Settings Name="MyWindowState", DefaultValue="Normal"}}/>
If the "MyWindowState" setting doesn't exist, it would be created automatically and stored somewhere. And if the MyWindowState setting changes, all the bindings that use it would also be notified and updated accordingly. And the DefaultValue would be used if the setting retrieval failed.
Does something akin to this exist already, or can it be achieved with the standard WPF XAML?
I am planning on working on something that can do this, but if a proven solution already exists I would love to at least look at it/hear it out.
From what I understand Telerik's persistance framework can do something like this, except on a control to control basis (there is no global "settings" I can bind to), at least on first glance.
Yes, it's quite possible. If you have an application properties file, you can access it like this:
Height="{Binding MainWindowHeight, Mode=TwoWay, Source={x:Static p:Settings.Default}}"
where MainWindowHeight is a setting (in my case, an int). You'll also need to include this in the top of your XAML file, in the Window or UserControl tag:
xmlns:p="clr-namespace:APPLICATION_NAME.Properties"
where APPLICATION_NAME is the name of your application.
EDIT: The binding can be have any mode, I just use TwoWay so I don't have to have any actual code to update it. For the positioning of my windows, it works out nicely that way.
EDIT: Also, this can't dynamically create settings. I would use an XML file in your application, make a class to handle that, and then bind to a method of the class to get/dynamically create the values.
You can do this with an attached property:
<Window loc:WindowState.Name="MyWindowState" />
In the OnNameChanged event handler of your attached property you will have access to the Window instance that the WindowState.Name property was set on and access to the value ("MyWindowState" in this example) that was set. There you start listening (e.g. using PropertyChangedEventManager) to changes of all properties of your Window instance that are part of your window state that you want to persist.
May be you can use WPF's theming option. You can store settings of your controls (width, color...) in a theme file, which is nothing but an xml file. You may store this xml somewhere and load it at runtime. You can update this xml when the application exits with the changes. And load it when the application opens next.
In my C# WPF .NET 4.0 application, I have a listbox containing user control items. What I want is to call some functions from these user controls to the parent form.
Item user controls have binding to the listbox via view model class.
What do you propose.
Thank you,
You can bind a command to your user control the same way as it would be a parent view. Then you can process this command in the appropriate view model.
I'm not entirely clear on what you're trying to do, but it sounds like you have a bunch of user controls and you want those controls to be able to call methods on the containing Window instance.
From inside your controls, you can use the following to get hold of the Window instance:
Window parentWindow = Window.GetWindow(this);
Note though that you can't do this from the control's constructors, because during the constructor the control won't yet have a parent window and the above will return null. The best place to do this would be from the control's Initialized or Loaded events.
I have a simple winform app with textbox.
I didnt assigned any context menu to text field and "it uses" standard one. I desire to add some new items to textbox's standard context menu. But I cant obtain it for modification, if be more clearly I didnt know how to obtain HMENU native object.
ContextMenu property of my textbox equals null so I suppose that menu appers within textbox defaul windProc routing. It there a way to get the default context menu or get a copy of it?
Thanks in advance!
Depending on any plug-ins you're using, it may be easier, and more understandable, to create a custom control that derives from TextBox and defines a "default" contextual menu. Then, change all TextBoxes in your solution to be your custom control instead. Failing that, if you have a common window ancestor, set up some initialization code that assigns a given ContextMenu to all controls in the form's hierarchy of type TextBox. Instead of plugging in to low-level Windows hooks, you're using what the framework gives you to accomplish the same end, and your posterity doesn't have to know how Windows handles contextual menus at a message-passing level in order to alter this behavior.
I have an mdi child form as a dockable content in my application and I want to disable/enable a listbox in it from the parent form depending on a certain event. I thought this would be simple as:
_child.listBox1.Enabled = false;
But it doesn't seem to disable it. _child is an object reference of the mdi child form btw. Why does it not work and how can I fix this?
_child probably refers to a different instance of the child form.
Make sure that _child refers to the same instance that you called Show() on.
Can't you create a function on your MDI child which would disable the listbox, you could call from the MDI parent?
I guess that here listBox1 is private (which is the default if you have constructed your form using VS designer)
Although it works, exposing the control of a form as a public property is considered a bad design practice.
Suppose that at some point in the future, you will have to change the internal ListBox into some other type, such as ListView, in order to add some functionality.
In this scenario, if you create a method called DisableList on the form, you will only have to change one place in code, to update the way the list should be disabled.
But if you choose the method of writing code such as _client.listbox1.Enabled = false;, you will have to go through all the pieces of code that touch the ListBox, and update them.
A very important principal in design is to avoid exposing the internal implementation details of class to those that have to use it. In this case, you will benefit if the parent form won't have to know that the list is implemented as a ListBox.