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.
Related
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'
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.
I've created user control which hosts datagridview and other controls.
Then I drop it onto a form.
How do I allow myself to customize grid's properties (like which columns are shown) in a target form?
I thought setting its modifier to public will suffice.
That should do it, then you can address the grid through your user control instance. Assuming you control is named "MyControl" and your grid within the control is named "MyGrid" then you should be able to use MyControl.MyGrid. to get to the properties.
You can add properties to your UserControl that helps you to change design of your Control from different forms.
Problem not solved in that general way I initially posed it.
As a quick hack I declared public properties for some of the grid properties I needed (like Columns collection)
Tnanx for your help, though.
I'm looking for an efficient manner in which to handle (methods and events of controls) dynamically created tab pages with dynamically created controls in them (same interface per tab page).
I want to be able to identify what tab page, a button's Click event came from and such behavior.
Would I be set by using a generic collection list in which to store the tab pages in? Where and in what am I looking to hold the references for each individual control, along with their methods and events? Am I also looking to hold the references for each individual control in generic collections lists? I'm hoping to avoid the User Control TabPage inheritance method. Is that going to end up being the most efficient route I'm going to have to take?
That's certainly possible, merely awkward. You can always get a reference to a control back from the Controls collection or the sender argument of an event. It's Parent property gives you the tab page. Etcetera.
Yes, a List<TabPage> would work. But also the TabControl.TabPages property.
Perhaps I'm missing something, but assuming you know the hierarchy of the controls, on click you can cast the sender as a button (as Hans suggested), and get it's parent
if(MyTabPage == (TabPage)((Button)sender).Parent)
OR get the parent's parent
if(MyTabPage == (TabPage)((Button)sender).Parent.Parent)
or however far up the hierarchy you need to go to get to the TabPage to figure out which tab you're on.
I read somewhere that setting DataContext = this in the constructor of a user control is bad practice (can't find where though). Why is this bad practice? What is the alternative?
In general, when someone uses your control they are going to want to set it's data context to their own view model class and bind the properties on your control to their view model.
If you start messing around with the data context internally within the control, and rely on it being set to 'this', either you will prevent their binding from working, or your control won't work as expected because you rely on it not being changed.
Say you have a user control that has a bunch on sub controls on it. What you could do instead is set the DataContext on the sub controls to be your user control class (or whatever you wanted). This would allow you to bind those sub controls to your user control's properties, while still allowing any users of your control to set it's data context to their view model and bind to the properties as well.