I have WPF window that uses a dockpanel and the menu control. I have the code to create the menu options based on a user ID.
Within this window, I have a frame that contains a WPF page. I carry out all the authentication on the page and then have a user ID for the window to use. However, I cannot get the parent window to "refresh" and create the menu bar with the new ID information. When the window loads, I do not run through the commands to display the menu bar. I have tried putting that in its own, public, function and calling it from the page but that does not seem to work.
There must be a window method that I'm missing that can make the menu bar display based on the call from the page.
It sounds like you're still thinking in procedurally, in WinForms style. What you describe would be necessary in WinForms, but in WPF it is usually much easier: just use data binding. As long as your menu items are generated from a "UserID" dependency property (or enabled/disabled based on it), then all you need to do is set the UserID DependencyProperty and the UI will update itself with no additional code.
Here is how to get the UserID into a DependencyProperty of the Window or a context object:
In your Window or a context object create a "UserID" DP
Make your Window or your a context object the DataContext of the page
At the end of the authentication code, set DataContext.UserID (or alternatively create a UserID property on the page, and have the Window bind to it with a two way binding)
Once you have the UserID in a DependencyProperty, there are many ways to update the menu items automatically whenever it changes:
In each menu item, bind its visibility to the UserID DP on the window using an appropriate converter (using the converter parameter to distinguish between items), -OR-
Use a converter for setting ItemsSource so you filter your items, -OR-
Create a PropertyChangedCallback that sets a filter on the CollectionView you use for menu items, -OR-
Some other technique (there are many other good ways to do this)
For typical situations we're talking about less than 10 lines of C# here, not counting the DependencyProperty declarations.
Related
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.
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.
I'd like to create a CustomWindow class that behaves this way:
1. Non-client area of window is utilized too, TabControl's tabs are present instead of window title like in Google Chrome.
2. Tabs are right-padded so when window is too small, min/max/close buttons don't collide with tabs - this should be doable in TabControl template.
3. There is a button after tabs much like a "new tab" button in Google Chrome. Again, this should be doable with custom implementation of TabControl and creating a fake child for rendering I guess.
4. My class inherits from Window class and every child in children collection is mapped to a TabControl tab like if TabControl.ItemsSource was bound to Window.Children.
5. Window exposes property ItemsSource that behaves like children collection too.
6. Window offers a way to style what TabControl recognizes as ItemTemplate. When I feed the window like CustomWindow.ItemsSource = new string[] { "a", "b", "c" }; and I populate a template for items, three tabs will be created where tab header style is hardcoded in CustomWindow class and tab item content area is templated by user.
As you can see this is basically a outline of Google Chrome window which is exactly what I am trying to accomplish. I know how to bend window's chrome the way I want with everything like system menu, double-click maximizing etc. handled. But I don't know how to make inherited class from Window that will force it's only child to be a TabControl of my choice (tabs headers are styled) but in reality it's child collection will be TabControls child collection. I am not as much experienced with WPF as I'd like and I want to start this the right way so I don't need to rewrite it in future.
Additionaly, when this is resolved, I want to give user the way to tell the tab it's pinned, which I guess is best accomplished by defining an attached property in CustomWindow, something like CustomWindow.IsPinned for any child control?
Thank you.
Add a DependencyProperty ItemsSource to your window (of type IEnumerable<object> and in your window Template set the tabcontrol with ItemsSource="{TemplateBinding ItemsSource}". That will make the window have its own child collection, which will then be rendered as tab items in the tabcontrol.
I am currently working on a project which has a tab control which contains a Wrap panel which contain a series of user controls. I am looking for a way to allow the user to select one user control and maximize it to the size of the tab control/window.
One thought is to simply remove all the other items from the panel.However I am attempting to use MVVM as much as possible and I'm not sure how much the user control should know about the panel. (The user control will contain a button to allow maximizing)
Is there a way to temporarily remove the usercontrol from the grid and treat it like a modal popup or just to fill the window?
How about having "Visible" or "Maximized" bool properties in the view model for each user control based item, and databind said user controls Visibility property to the appropriate property. Then bind your user controls maximize/restore button to command in the view model to change the VM properties appropriately?
I have a user control on a page and I'd like to load another custom user control within it's grid. However I want the user control type to be dynamic - e.g selecting "Calculator" from a drop down list would display my custom calculator control and selecting "Currency Converter" would load my currency converter. Can anybody help?
By the way I am trying to stick to MVVM.
Thanks in advance.
One way is to define multiple DataTemplates one for each child. As user selects the option set the corresponding ViewModel to a ContentControl's DataContext present in parent view and framework will pick the corresponding view for you.
John Papa has written a great blog post on exactly how to do this here.
The basic strategy is to instantiate a new instance of a class that derives from UserControl once selected from the drop down.
In other words, the SelectionChanged event of the drop down list could be handled and a new UserControl object created based on the selected item.