WPF: Switch Template based on UserControl Data - wpf

Trying to implement what I thought was a simple concept. I have a user control (view) bound to a view model which provides a list of data. I have added toggle buttons to the usercontrol and would like to allow the user to use these toggle buttons to switch out which template is used to show the data. All of the templates used for the data work, and they are very different from one another so it's not just simple changes to a single template. I'd like to get this as much in XAML as possible.
Here's what I have now:
Where the data appears I have <UserControl Template="{StaticResource ListSwitchingControlTemplate}" />
In that control template I have all "sub templates" - really it's just all 3 representations with their visibility set to Collapsed. Then I use a data trigger on that control template to show the currently selected view. This works, but I noticed that all 3 representations get bound - they each act like they are active (and they are I guess).
I'd rather be able to truly switch the template at run time. I tried converting the containing user control to use a ContentTemplate for itself, but that just messes up all of the binding I have elsewhere. If only UserControls could use DataTriggers I'd be ok.
Any suggestions on how to cleanly go about getting this behavior. I have an idea that I'm just missing something simple.
Thanks,
Dave

you could do it via code?
http://www.switchonthecode.com/tutorials/wpf-tutorial-how-to-use-a-datatemplateselector ???
http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/4fd42590-8375-46d0-b7bc-6c217df0f0ba/
http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/dbbbb5d6-ab03-49a0-9e42-686fd41e0714

One way to do this would be to use a DataTemplateSelector.
Basically, you create a class that inherits from DataTemplateSelector and override its SelectTemplate virtual function. The return value from the function is the DataTemplate you want to use and in that function you have access to the object and its properties, which you can use to decide which template to select.
There is an example on MSDN here:
http://msdn.microsoft.com/en-us/library/system.windows.controls.datatemplateselector.aspx

Related

WPF/Prism: Nested views and toolbar

I have a WPF/prism application similar to the mockup shown below:
Both TabControls contain a separate Prism region, the second one being nested into the first one. Now the toolbar should activate/deactive items depending on which view is currently active.
The toolbar is currently defined in the shell.
I tried using some sort of registry, where each ViewModel could register the toolbar commands it supports. However I then realized that the toolbar cannot know which view (and therefore which viewmodel) is active.
The problem is in the nesting, without that I could probably achieve what I wanted by binding the TabControl.SelectedItem property to the toolbar and use my registry from above.
Maybe there is a better way to do this? Or a way to let the toolbar find out which view is active?
edit: I now tried to use ActiveAware ViewModels as descriped in this article: http://www.codeproject.com/Articles/56826/ViewModel-Active-Awareness-in-a-Prism-Based-Applic, however I now have the problem that when I switch from Tab "One" to Tab "Two" and back, the nested tab's "First Tab" GotFocus event is not fired, meaning the toolbar will represent the wrong view.
Maybe this is the way to go?
edit 2: The problem seems to be that the second tabcontrol is not inside it's own scoped region. I'm using the ViewDiscovery approach to add views to my regions, so I'm not explicity creating the regionmanager in a scope. SyncActiveState seems to work only with scoped regions, as the first tabcontrol viewmodels correctly get updated when switching views.
Is there a way to use XAML to create a scoped region instead of a normal one?
The problem here is that the toolbar does not know anything about the active region; they are deliberately decoupled.
I would (personally) use the Event Aggregator to publish messages from the active ViewModel to say "I am currently active" and have the toolbar subscribe to those messages and update the buttons as appropriate.
If I were attempting to do this, I would probably create an IToolbarManager which has bool properties for each of the available toolbar actions, and an ICommand for the actions themselves.
Then, implement this interface in a concrete type where the bool properties change the CanExecute values of the commands, and call CommandManager.InvalidRequerySuggested. Register this type as a singleton with the container, then use DI to inject it into each of the views and into the shell. The Shell can then databind the Toolbar buttons to the Commands in the IToolbarManager, and the views can then set whether or not the actions are enabled as they get initialized.
I don't have a code sample because I'm just thinking through how I'd solve this, but hopefully you can follow what I'm suggesting, and it proves helpful.
I now ended up with creating an extended TabControl that uses the SelectionChanged event to set IsActive on all items implementing a specific interface. Also it walks down the VisualTree and finds any extended TabControl and does the same for the items of these and so on.
Work pretty well here, we only use TabControls so far, so this solution works for me.

Can I use different datatemplate for same datatype basedon some creteria?

I'm new to wpf and now I have a problem. I have a model class say Customer and I've created a DataTemplate with TargetType property set to Customer. It works good. But I actually want two different templates like one for just displaying the record and another for in-place editing. Is it possible to specify two different templates for same datatype based on some creteria?
And I want to switch this template based on some property on ViewModel like when IsEditmode is True.
Or am I doing it wrong? Should I use styles instead?
Your approach seems to be perfectly fine.
You can create a DataTemplateSelector which will allow you to choose a data template based on arbitrary criteria from code behind.
I often use these to decide which template to use based on a enum-type property.
There are two easy ways I can think of, ofcourse there are other ways based on the complexity and architecture you want to follow.
Define DataTemplate with 'Key' and specifically call that either using StaticResource/DynamicResource Binding.
You can have a DataTrigger inside the datatemplate which makes some parts of the template visible/collapsed based on your 'EditMode' property

Show/hide controls based on user role in WPF

I need to do a quick sample WPF application where the controls on the forms should be made visible or hidden based on the user roles.
Something like this will be great,
How to manipulate WPF GUI based on user roles
I am not sure where to put the XAML defined in the thread(<Control ) so that the every control in the form uses RoleToVisibilityConverter to show or hide the controls.
i am very new to windows dev..could you please help me ?
Regards
Bala
You could solve this by binding the Visibility to a corresponding property in your code-behind/ViewModel.
This is an example from a binding in one of my testcontrols using WPF (in combination with Caliburn):
Visibility="{Binding Path=IsAdmin}"
Here I have a bool property in my ViewModel called IsAdmin.
For me, the easiest way was creating a global variable in my app. For that, go to your Project->Properties->Settings.settings and create a new variable (called, for example, Administrator), and set it to True of False depending on what you want to do. Something like this:
Then, at your MainWindow, when its initialized, you can write this:
if (!Properties.Settings.Default.Administrator)
{
DisableSettings();
}
And then, disable the fields you want to.

Should a ViewModel in MVVM reference the View?

In the MVVM (Model-View-ViewModel) pattern should the ViewModel reference the view. I would think that it should not. But how should the following scenario be handeled? I have a view that has a tab control as the main container, the viewmodel for this view implements a command to add a new tab to the tab control. The easy way would be to allow the viewmodel to reference the view and then in the command implementation to just programmatically add the new tab to the tabcontrol in the view. This just seems wrong. Should I somehow bind the tabcontrol to the viewmodel and then implement a data/control-template to add the new tabs. I hope this makes some kind of sense to somebody :)
In "pure" MVVM, the ViewModel shouldn't really reference the View. It's often convenient, however, to provide some form of interface in the View whereby the ViewModel can interact with it.
However, I've found that I almost never do that anymore. The alternative approach is to use some form of attached property or blend behavior within your View, and bind it to your ViewModel properties. This allows you to keep the View logic 100% within the View. In addition, by creating a behavior for this, you create a reusable type that can be used to handle this in every ViewModel->View interaction. I strongly prefer this approach over having any View logic within the ViewModel.
In order to demonstrate this technique, I wrote a sample for the Expression Code Gallery called WindowCloseBehavior. It demonstrates how you can use a Behavior within the View bound to properties in the ViewModel to handle controlling a Window's life-cycle, including preventing it from being closed, etc.
Reed and Dan covered the general approach but in reference to your specific case, TabControl is an ItemsControl and so can bind its ItemsSource to a data collection in your ViewModel representing the set of tabs to display. The UI for each type of tab can then be represented by a DataTemplate specific to the data type of an item (either using DataType or a DataTemplateSelector). You can then add or remove data items as needed from your VM and have the tabs update automatically without the VM knowing anything about the TabControl.
I find that it's often a helpful compromise to expose an interface on the View that handles View-specific functionality. This is a good way to handle things that are awkward to accomplish with pure binding, such as instructing the form to close, opening a file dialog (though this often gets put in its own service interface) or interacting with controls not designed well for data binding (such as the example you provided.)
Using an interface still keeps the View and ViewModel largely decoupled and enables you to mock the specific IView during testing.
One of us is missing something obvious. Your tab control is an ItemsControl. You should bind the ItemsSource of your tab control to an ovservable collection in your view model. When you handle the command in your view model to add a tab, you simply add a new element to this collection and, voila, you've added a new tab to the control.

How to call a user control method using MVVM?

I'm working in a WPF project, I'm using the MVVM patter in my project.
I created a user control (also in WPF) and I want to use it in my project, now, my problem is that I have a method in my user control that I need to call from my View Model, but I don't know how to do that, how to bind to the method inside my control from the view model.
If I use code behind, obviously there is no problem since I have a direct reference to my control, so I can do "mycontrol.MyMethod();"m, but of course, doing in this way will go against the logic of the MVVM pattern.
I tried to use a Dependency Property in my user control, and use that Dependency Property to bind to it in the xaml of my project but it didn't worked, the compiler says that the property was not found or is not serializable.
So I will appreciate if someone can share some light about how can I accomplish this.
Edited
As far as I understand you have the view, which is all the GUI, then you have the model, which is all the logic, and them you have the view-model which is like an intermediate layer used to bind the view with the model, right?
In this way I have developed my project, however I came to the problem that I need a custom control, a TextBox that remember what the user entered, and when he start typing, if there are words that start with that letter, those words are shown as a suggestion, as Google does it.
This TextBox is used as a search filter; so I created a user control to do this, I added a method to my user control to allow whatever application that uses my control to add items to an internal array that holds all the strings that the user has entered.
I created a user control because I couldn't find any control that behaves the way I want.
So my problem is when I add my user control to the main project, because I need to someway be able to call the method that add the items to the internal array, but maybe I'm doing things the wrong way, so if any of you has a better idea, I will appreciate if you shared it with me.
You should never call View methods from ViewModel, and vice versa.
Make a property (ObservableCollection?) on your ViewModel, it will have CollectionChanged event, subscribe to it to monitor changes (if needed).
When you add an item to the collection in your ViewModel, GUI will be updated accordingly (you have to perform the Add() operation on GUI thread, btw).
If you need to change the current position in your list, there are colections for that (CollectionViewSource, etc).
If you really really need to pass a string to your control, make a DependencyProperty and bind it OneWay to your ViewModel's property. When you set the value, it will call PropertyChangedCallback on your DependencyProperty.
Why does the consumer of the user control need to maintain the control's internal array? That seems like you've exposed an implementation detail that you don't need to.
Why not simply make that array a dependency property (and an IEnumerable<string> or ObservableCollection<string> besides)? Then you can simply create the corresponding property in your view model and bind it to the control. It also makes the control considerably more versatile.
You shouldn't call something in the View from the ViewModel since that breaks the model.
If the reason you want to call the method in the user control is to do with UI only, I don't see anything wrong with doing it from the view - the view's cs and the view's xaml are in the same "space" in the model. You can be overly-purist in wanting to have lean and mean view cs files.

Resources