Binding a command to a child window's datacontext - wpf

I have a window called MAINWINDOW that has a toolbar and a frame. Inside the frame is shown a Page called HOMEPAGE. This page has a treeview where menu options are shown. When the user clicks a node, the corresponding form (a Page) is shown inside a border in HOMEPAGE, using the Border.Content property. I have a button in the toolbar to search for customers and I need to bind this button's command property to a command which is defined inside the Customers page's viewmodel. This page is a child of the HOMEPAGE which in turn is a child of MAINWINDOW. Can you suggest a way to do this, that is to access a command defined in a child's child object?
Thank you.

That goes against the principles of MVVM.
ViewModels (and their corresponding Commands) are 1:1 to Views. Each ViewModel serves one View, and one View ONLY. It helps to think of the ViewModel as the codeBehind of the View, only that it can never access the View directly (thus it's completely decoupled from it).
Violating this principle (V to VM == 1:1), creates dependencies between ViewModels or between Views, which is a bad thing. It makes your application harder to maintain since each "module" is dependent on the implementation of other "modules".
What you should do is expose another Command on the ViewModel that serves the relevant View. That Command in turn could trigger what ever you want.

Related

How to set owner for dialog opened from a view model?

I have a parent view which shows a grid. In one of the columns there is a button on every row to show a child dialog to edit the object that each row of the grid is bound to. The button is bound to a command on the view model which shows the dialog. I use CommandParameter="{Binding}" to pass a reference to object to edit to the view model of the child dialog.
I want to the dialog to be centered relative to the window it opened from which I can do with dialog.WindowStartupLocation = WindowStartupLocation.CenterOwner but I need a reference to the parent window.
I can think of two solutions but I don't think either of them is clean.
If I wasn't using the command parameter already I could pass the window to parent view model like this CommandParameter="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}". I could use a multi binding and a converter to pass two parameters but is this good practice? I tend to think the view model shouldn't know any thing about views.
I can pass a reference to the parent window that host the parent view to it's view model in the view model's constructor. Again what I don't like is that the view model knows about windows which seems like a dependency in the wrong direction.
What I also don't like about either of these approaches is the parent view model needs to have knowledge of the child window it is creating.
I sawthis answer which shows how to use a service that the view model can use to open a window without having any knowledge of the window its creating which is great but I kind think of a clean way to pass the parent window without going through the view model.

WPF - modify window content from ViewModel

I have a WPF application. I'm trying to modify it to use the MVVM pattern.
Now, in the code behind of my main window, when I click a button, I change the "Content" of my window with a WebBrowser control :
Content = webBrowserWrapper.WebBrowser;
I would like to do it from a command in my ViewModel. How can I access the "Content" property of my window ?
If it's not possible, what is the simple way to modify the content of my window (maybe create a new window and navigate to it)
The principal behind MVVM is that UI is the concern of the View, and logic is the concern of the ViewModel.
You describe a concern of the View, which is properly handled within its codebehind. There is no need to involve the ViewModel in this action.
So, in other words... congrats. You're already there.

WPF/Prism best way to delete a selected item from a child view from a toolbar button in the Shell?

I'm using WPF/Prism and have a Shell with toolbar in it and a region with a view in it (The view lives in another module). The view has a treeview in it that is bound to a list of view models.
I have a toolbar button in the Shell I want to have delete the selected treeview item that is in the child region/view.
What is the best way to do this?
I thought about using a command but I'm not sure if there is a way to bind the toolbar button command that lives in the Shell to the view model in the child view (that contains the tree view). Is this possible/the best way to do this?
The alternatives like using event aggregator to publish the selected item seem plausible or some type of service to publish the selected treeview item to also seem possible.
Thanks.
You could define a static CompositeCommand in a static class as part of an infrastructure project/dll. Set the toolbar button command property to this command using {x:Static}, and in the viewmodel of the view containing the TreeView you define a local DelegateCommand that you register with the CompositeCommand.
But if the button in the toolbar only applies to this particular view from the module, it would make sense to also define the toolbar as a Prism region and insert the button as a view from the module.

Single Command to call different commands in different View Models

Putting my requirement in very easy steps. Searched a lot on web but got very confused.
I got a Main Window (.xaml)
I got a Menu control, with Save option (a user control)
I got 3 more user controls (.xaml) in the same Window inside the Tab Control (with 3 tabs).
Each user control has data entries and has its own View Model class with Save() methods to save the data (implemented ICommand and INotifiyPropertyChanged in view model).
Now, if I have save button in individual usercontrol (inside the tabs) it works fine (I used commands for achieving this). But, I need the, Save to work, just clicking the "Save" on the menu, which is also a usercontrol and is inside the Main Window. The Menu save should act like a common Save for all the 3 user controls.
So the Menu should be now smart to identify which is the active usercontrol (probably based on the tab changed event or something else) and accordingly fire the Save() method for that usercontrol in the ViewModel.
Have you considered using Event Aggregator to accomplish communication between parts of your application without tightly coupling them.

Different data contexts in a SL3 form

I wrote a custom Silverlight 3 control that uses a class as its data context (MVVM pattern). I want to place this control on another control (form) through XAML. The child control exposes a Dependency Property that when set through XAML, will make it show detailed info.
So an example is that the child control shows order details data, and I want to place it on a form that show user orders. When you select an order, the selected item value on the parent control (orders list), is data bound to the child control, to show details.
The problem is that the child control’s dependency property's OnChanged handler never gets called. If I do not set a data context on the child (so it uses the parent's data context) all works fine, but when I set a different data context, it breaks down.
Ideally, your ViewModel would be for the outer UserControl and a property on the ViewModel will be the DataContext of the Inner/Child userControl
Its true that when the Parent control's DataContext is set, it is propogated down to all its child controls. But the child control has an option of overriding this behavior by setting its own DataContext (which you seem to be doing in your example). Hence by the rule of preferences, the child control's DataContext is given more preference and thus it overrides the parent's one. Also since the child's DataContext never changes after it's initially set, the DP never gets invoked.
So I thought about this some more, and I understand what is happening, but I think its very confusing, and is not done right. If I am doing data binding on a control in the main page, it should use the context of that page to do the binding. And binding I do inside the control should use the control's context.
The way it works now uses the control's context no matter where I put the binding expression (unless I am doing E2E binding, then its using the main page's context). That is silly to me. But at least I understand it now.
I solved the problem using Element to Element binding, and got it to work. I hope the SL team would change this behavior.

Resources