On my MainPage.xaml, I sometimes need to add a UserControl to the main Panel (a Canvas). That UserControl, when clicked, needs to access a routine from MainPage.xaml - it's parent's parent - which will either make the UserControl itself Visibility = Collapsed or removed all together from MainPage.xaml.
Right now in the code behind of that UserControl I am doing
Dim c = VisualTreeHelper.GetParent(Me)
Dim mp As MainPage = VisualTreeHelper.GetParent(c)
mp.MyRoutine(3)
This is working, but it makes me wonder if there is a more straight-forward way to do this or a more preferred way. Any ideas?
A more general way of navigating the visual tree is available via Linq To VisualTree, with this small framework you can perform all sorts of queries on your visual tree. Your example of getting parent would be as simple as:
var parent = me.Ancestors().First();
Or, if you want to find the first parent of a given type ...
var parent = me.Ancestors<MainPage>().Cast<MainPage>().First()
In general, I'd avoid this type of dependency. It dramatically reduces the usefulness and flexibility of your UserControl.
Instead, it might be better to push the dependency into the UserControl during construction (or even runtime). You could pass in a delegate referencing MyRoutine, or an interface the main page implements.
This way, the UserControl's dependency would be obvious (since it's part of the API), and it would be possible to use it with other applications/pages later.
That being said, if you decide to keep the above, I would make one change at a minimum. Instead of just expecting the parent's parent to always be "MainWindow", I would recursively check parents until you get to the MainWindow (or nothing) in a method on your class. This would, at a minimum, allow you the flexibility of moving your UserControl around in the hierarchy without breaking it.
The general way that I navigate the visual tree is with my own VisualTreeEnumeration code. However as I state in the blog there are other various utilities to do the same. Whatever you use you end up with an enumerable set of ancestors. However the most most flexiable approach would be to hunt for the MainPage type:-
(Note C#)
MainPage mp = this.Ancestors().OfType<MainPage>().FirstOrDefault();
Not sure what this would look like VB.
Related
My question is what is the ideal way to initialize child window in WPF, MVVM way?
I have a WPF window , let's call it as ParentWindow having its view Model class - ParentWindowViewModel. On click of a button on the ParentWindow UI , I launch a new WPF window - ChildWindow like below
ChildWindow r = new ChildWindow ();
r.ShowDialog();
r.WindowStartupLocation = WindowStartupLocation.CenterScreen;
Now, the ChildWindow has its own viewModel like - ChildWindowViewModel. The Child Window has the datacontext set in its xaml as
<Window.DataContext>
<viewModel:ChildWindowViewModel/>
</Window.DataContext>
On Click of button in the ParentWindow, When i Launch the Child Window, I need to pass certain values to the Child Window, which will be used to initialize the Child Window. Without these values the child window cannot be initialized.Every time I click the button to Launch the child window, the values being passed to child window will differ based on some other selected items in the Parent Window.
I would do something like this (without error checking):
in ParentWindow.xaml.cs
private void Some_Event_In_Parent_Window()
{
ParentWindowViewModel pvm = DataContext as ParentWindowViewModel;
ChildWindow cw = new ChildWindow(pvm.Element1, pvm.Element2);
}
int ChildWindow.xaml.cs
public ChildWindow(bool elem1, string elem2)
{
InitializeComponents();
DataContext = new ChildWindowViewModel(elem1, elem2);
}
If you are dealing with minimal elements that need to be transferred between windows/VM's, and it is mainly about sending some form of "state" or "value", then there isnt too much issue with initializing the Viewmodel in the code behind. Remember that the <viewmodel:ChildWindowViewModel/> is equivalent to DataContext = new ChildWindowViewModel() in your code behind. While yes, you can create spaghetti code, or confusing dependencies by not adhering to patterns; you can also over engineer the crap of something that did not require the effort and can be just as confusing.
I find that there is an obsession with keeping your code behind empty (i have the same obsession). Remember, that the Code behind is there for a reason, and you CAN use it. Sometimes it isnt worth over-complicating your code base by implementing some big pattern if you have a single one off requirement that can be handled in code behind with some added comments.
Aside from Event Handlers, I utilize the Code Behind for these main use cases:
There is an adjustment needed to the UI that is too complicated to handle in the XAML alone. Example: I need a weird string concatenation and logic of some inputted text fields.
There is some minimal state or data needed to be transferred between Views. (Like your requirement)
There is some sort of logic that needs to happen that is UI specific and not related to the underlying data or ViewModel. (This is rare, and almost always a small one off).
In terms of "is this ideal" for MVVM; it depends on your definition of ideal.
Can this be handled by some other design pattern? Probably...? But is it worth it.
Does implementing said pattern add bloat or overhead that only solves a small problem? Maybe. That is for you to decide.
Are you going to be repeating this implementation more than once? If so you may have some bad design to rethink.
Does implementing this solution of using Code behind solve your issue in a speedy way, that is moderately maintainable and readable? If so, then I wouldnt see a problem.
Ideal is not always defined by rules. It is also specific to your needs and requirements.
It isnt always easy to determine where your use case should be handled. View, ViewModel, maybe a Service, or a Singleton state class.
If your use case is this one window, Code behind is fine (In my opinion). If you are doing this for 20 windows, you may want a Service to maintain the state somehow. Think of it more - if your code is SOLID and DRY
Given a FrameworkElement, how do I traverse the DataConext "up" in C# code behind (not binding)? For example: A customer has multiple addresses, if I click on a button on the Address layout I would like to find the Customer. I have read the MSDN article on the VisualTree and the LogicalTree but I'm struggling to put it all together.
Please send codez :)
Well ideally your DataContext instances are all part of a hierarchy that have a parent and child relationship. That way you can always move up the parent chain. This is the advantage of a ViewModel approach where the base class implementation maintains a parent reference and automatically sets it up when adding children. When this is not the case...
Use the following static method to move up the chain...
VisualTreeHelper.GetParent
...note that the method expects a DependencyObject which is a base class of the FrameworkElement.
I'm trying to create a function that adds usercontrols to my mainform. I want this function to be available from the usercontrols themselves as well, so I'm making it static.
My problem is that when it's static I can't use this.Controls.Add(ucontrol);, I tried to change it to ActiveForm.Controls.Add(ucontrol); but then ActiveForm is NULL and has no Controls property (throws an exception).
UPDATE #1: I ended up doing something like this inside the usercontrol:
MainForm ref_to_mainform_to_gain_access_to_functions = (MainForm)Parent;
ref_to_mainform_to_gain_access_to_functions.DisplayControl(ucontrol);
maybe it's even better, but I still assume it's possible to have access to the mainform from a static method?
UPDATE #2:
Application.OpenForms["FormName"]
worked from static method.
I still try to find out if that usercontrol entire purpose is serve as a menu with buttons that shows other usercontrols onclick, is it still a 'design-crime' to call a function on mainform (a function that shows usercontrols) from a user control? (like I did in 'update #1')
By adding controls from a user control to its parent you are breaking the separation of concerns principle and you are tightly coupling both controls/forms. As suggested by Hans Passant you should use events. Please refer to:
best practices to call methods in the parent form and access gui elements in parent form in c#
I don't know if this should go on Programmers, but I thought it was relevant here.
Being a skilled WPF programmer myself, I often wonder what people were thinking when they designed WPF in terms of naming conventions.
Why would you sometimes have a property called Children for accessing the children of the control, and then sometimes have an equivalent property, just called Controls instead? What were they thinking here?
Another example is the Popup control. Instead of a Content property, it has a Child property. Why would you do that? To me that's just confusing.
So I'm wondering if there's a logical reason for it, which would probably also help me understand what the properties are called next time I need to do some speed-programming.
If there's no reason behind it, then all I can say is WAT.
I've never seen a Controls property; as for Child versus Content: Content can be any object, data for example, whereas a Child has to be some FrameworkElement in the hierarchy of the controls. To me that makes perfect sense.
i am working on MVVM and using commanding in silverlight(DelegateEvent and ICommand)
I want something like this ,(say) i have 2 usercontrols , parent and child .
Parent is hosting the child , both have thier own viewmodels .
On parent i have a button and it executes a simple command , on execute of that command i want to update text in the child control's textbox . also we should be able to change something in child which can propagate to the parent .
Is events the best answer for this or i can have commands to update child/notify parent in some way.
There are several ways to go about this.
First, it is completely appropriate to have ViewModels that are composed of other ViewModels, as long as you are OK with them being coupled in that way. When you do that, they can just talk to each other using regular method calls.
Next, you can decouple a bit and use events. Nothing wrong with that. There is still an Observer -> Observable coupling, but they are less dependent upon each other.
Next, you can completely decouple and use something like an EventAggregator (Prism has a good one you can use). Shoot a Publish a message. The other subscribes. They don't know about each other at all.
I have used commands for this as well... but for ViewModel to ViewModel communication, I find this to be a bit awkward.
You should probably start with most obvious implementation where parent viewmodel simply holds a reference to a child viewmodel, and child viewmodel holds a reference to a parent viewmodel. Then when a command is executed on parent viewmodel it simply sets a value on a child viewmodel to which textbox is bound to.
Adding a layer of abstraction between parent and child (e.g. events) adds a level of complexity and as a result it should be justified. If the value this indirection provides is higher than the cost of increased complexity of the code (e.g. it's now less clear what happens when command on a parent is executed, you will have to solve a problem how child gets subscribed to parent's event without obtaining the actual reference to it and vice-versa, adding additional dependencies between parent a child will require adding additional events, which pollutes the actual logic with all the plumbing, etc.) then certainly events (or something like PropertyObserver) might be a next logic step.
This seems like an ideal situation for using an EventAggregator like the one in the Composite Application Guidance / Prism.
In this model, you can set up a MessageBus in the root of the application (or other common area).
// in App.xaml.cs
public static IEventAggregator MessageBus = new EventAggregator();
Then set up a common Messages library
// in Messages.cs
public class SimpleCommand: CompositePresentationEvent<SimpleObject> { }
Where SimpleObject is a class or variable that contains all the info necessary to process this event.
// in control with button
App.MessageBus.GetEvent<Messages.SimpleCommand>().Publish(SimpleObject);
// anywhere in your app that you "care" about this
App.MessageBus.GetEvent<Messages.SimpleCommand>().Subscribe(ProcessingMethod);
Where ProcessingMethod is a method that takes a SimpleObject as a parameter.
Then you can spout off messages from anywhere and process them anywhere - across viewmodels, controls, etc. You can even pass MessageBuses between components if you are dynamically loading parts of the app. Works well.