I have a usercontrol that i want to use throughout my Silverlight MEF MVVM solution.
I want to be able to link it up with one of a number of ViewModels depending on which module i am in. What this control does is list the records of a given entity so i can Add, Edit or Delete. I realized i would be using this control in multiple locations - to update several lookup tables, so i decided to make it's ViewModel dynamic. As seen below, I am using the Galasoft MVVM plugin.
if (!GalaSoft.MvvmLight.ViewModelBase.IsInDesignModeStatic)
{
// set DataContext
DataContext = PluginCatalogService.Instance.FindSharedPlugin(ViewModelTypes.ViewModelMT, PluginType.ViewModel);
_viewModel = (ViewModelMT)DataContext;
}
My question is how can i dynamically change from ViewModelMT to ViewModelCT to allow me to independently display lookup tables e.g. Maintenance Types and Contract Types on an instance of this same usercontrol? I took a look at the Viewmodel locator, but I'm still not sure how to get this done.
Thank you
I don't think this is really a ViewModel thing. It's more of a Service problem.
Your ViewModel for the control will not change but you'll dynamically slot in the required service to maintain your list. ie. MaintenanceTypeService and ContractTypesService will implement IListMaintenanceService which exposes an list of items and Add,Delete and Edit commands.
Related
So I'm trying to wrap my head around MVVM and I'm finding that I have more questions than answers. The tutorials don't go far enough for me when it comes to the next step...
Basically I want a list of items and then a way to get the detail of each item.
Below is the examples that I've found online and they work great for displaying the list, but I need to know how I can use my VM to get the detail of this item.
private IList<item> m_items;
private IList<item> m_Item;
private IList<item> getItemDetail(Int32 iId)
{
var myItem =
from i in items
where i.iId == iId
select i;
m_Item = new List<item>();
foreach (var item in myItem)
{
m_Item.Add(item);
}
return m_Item;
}
public myViewModel()
{
m_items = new List<item>
{
new item(1, "test,),
new item(2, "test2"),
new item(3, "test1")
};
m_Item = new List<item>();
m_Item = getItemDetail(iId);
}
Update:
I updated my View Model code above. I think what I've done is I have added another List where when the user navigates to a detail page the view model gets called with the specific ID which then populates the detail List. I probably don't need a list here but I wanted to try to keep it consistent with the main page code.
In my detail page I'm setting up the VM this way:
itemViewModel VM = new itemViewModel((Int32)navigationParameter);
DataContext = VM;
When I break on the VM variable I see my 2 lists. However, my binding doesn't work on the XAML. If I need to post some sample XAML let me know. I can do that but I'm hoping there is something I'm missing here.
I'm trying to learn MVVM and I want to do things right. So instead of continuing down a wrong path I would really like to know the "right" way of doing things. So if you see errors, please let me know.
Thanks!
right, i'd suggest you go back to basics first and watch Laurent's Mix sessions about MVVM, you find links to then from the mvvmlight site on codeplex.
but to break it down you've hit a few of the hurdles I did when I first started.
1: (the biggest gotcha) for databinding to work, you must expose data using a property (get and set pattern), just a list variable won't work. this goes for everything you want to bind to. The alternative is to set item sources directly in code but you will loose all the features of databinding, including updates.
2: to understand databinding you need to understand the INotifyProperty changed pattern, this is the underlying gubbins (technical term ;-D) to enable binding to work properly. as suggested start a new "master/details" project template and walk through it, from the viewmodels holding the data to the views (pages) looking at the data in the view model
3: use observablecollections for lists, they are just better for binding and are basically just lists with extras
4: remember you can also bind the "selecteditem" or "selectedindex" of a listbox to capture what the user has selected, just be sure to set the binding to "twoway" so the view can push data to the viewmodel and not just read, like this: {binding myselecteditem, mode="twoway"}
hope this helps but if your still stuck Laurents videos are the best, just watch them a few times and follow what he does line by line
I believe you want to use what Microsoft calls the "master-detail binding scenario", where several controls bind to a single collection or to its selected item. To do so, you need to bind to a so called collection view, which is just a layer on top of the collection used by WPF. For instance, you can bind a ListBox's ItemSource and a ContentControl's Content to the same collection view, and the ContentControl will display the details of the the ListBox's selected item.
see: http://msdn.microsoft.com/en-us/library/ms752347.aspx#master_detail_scenario
P.S. you may want to use an ObservableCollection instead of a List, and make sure your view model implements INotifyPropertyChanged.
I'm new to Silverlight/MVVM. I tried some example of MVVM Light, it looks great.
For my scenario, I want to create a Panorama Page, for each Panorama Item, showing my usercontrol, a item list for a customer.
I've built usercontrol(view), viewmodel and WCF service model and works well in a single Panorama Item(Only use first customer).
Also, I use Locator of MVVM Light shown in MIX10 demo, it enables me to make design time data for Expression Blend.
My viewmodel will receive a parameter of customer ID then exchange data with WCF based on this ID.
And the customer list also comes from WCF. So I can't actually makes viewmodels in Locator's static constructor.
If viewmodels are built in runtime by calling Locator, how to make data binding?
The only way I think about is to make viewmodel object in usercontrol's constructor and make it datacontext.
Is there a better solution?
If you want to keep the same declarative model in the XAML, you can put a CurrentCustomerViewModel property on the locator and then set property to the right viewmodel before you navigate to the page.
Personally though for pages like that I typically put a viewmodel factory method on the locator (so it can cache them, etc) and call it from the OnNavigatedTo method, something like this.
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
string id = NavigationContext.QueryString["customerID"];
vm = ViewModelLocator.GetCustomerViewModel(id);
DataContext = vm;
base.OnNavigatedTo(e);
}
Then I just use Blend's sample data capabilities for design time data. This way also helps support pinning the page to the start screen since that will be the entry point to the app and I won't necessarily get a good chance to set the "CurrentCustomerVM" property anyway.
At the article, WPF Apps With The Model-View-ViewModel Design Pattern, the author who is Josh Smith said:
(1) In a well-designed MVVM architecture, the codebehind for most Views should be empty, or, at most, only contain code that manipulates the controls and resources contained within that view. (2) Sometimes it is also necessary to write code in a View's codebehind that interacts with a ViewModel object, such as hooking an event or calling a method that would otherwise be very difficult to invoke from the ViewModel itself.
My question is ,at the (1), why the empty codebehind is regarded as a a well-designed MVVM.(It sounds that the empty codebehind is always good.)
EDIT: My question is, as the following, why the approach like the AttachedCommandBehavior or the InvokeCommandAction is tried to avoid the codebehind coding.
Let me explain more detail.
As far as the (1) is concerned, I would think like the following situation as from the AttachedCommandBehavior. As the Border doesn't implement the ICommandSource for the MouseRightButtonDown, you cannot commonly bind the event and the ICommand, but can do with the AttachedCommandBehavior.
<!-- I modified some code from the AttachedCommandBehavior to show more simply -->
<Border>
<local:CommandBehaviorCollection.Behaviors>
<local:BehaviorBinding Event="MouseRightButtonDown"
Command="{Binding SomeCommand}"
CommandParameter="A Command on MouseRightButtonDown"/>
</local:CommandBehaviorCollection.Behaviors>
</Border>
OR
We can do this with the System.Windows.Interactivity.InvokeCommandAction.
<Border xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" >
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseRightButtonDown">
<i:InvokeCommandAction Command="{Binding SomeCommand}"
CommandParameter="A Command on MouseRightButtonDown"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Border>
BUT,
We use the following XAML and its codebehind having the Border_MouseRightButtonDown method, which is linked to the (2) Josh Simth said above.
<Border MouseRightButtonDown ="Border_MouseRightButtonDown"/>
I think using the codebehind as above is not bad just because the difference between these is only where binding a command or add event handler is.
What do you think about this?
why the empty codebehind is regarded as a a well-designed MVVM
Having a code-behind file which consists solely of a call to InitializeComponent() in its constructor means you have achieved purity - you have absolutely zero logic in your codebehind. You have not polluted your view with any code that rightfully belongs in the viewmodel or model. This means a couple of things:
the viewmodel (and model) is easier to test in isolation
you have achieved a good level of loose coupling, which has excellent benefits from a maintenance and extensibility perspective
The benefits really become noticeable when you have to change your UI, i.e. you switch from using a ListView to a DataGrid, or you change from using the standard Microsoft controls to using some other vendor's.
As mentioned though, it is sometimes impossible to avoid a little code in the code-behind file. What you should ensure is that the code you do have is purely UI related. As an example, if you have ComboA and ComboB, and ComboB is set in response to the selection in ComboA, then setting the SelectedIndex of ComboB from the view is fine, but setting the Items or the SelectedItem of ComboB is not - those properties are both data related and should be specified via binding to the viewmodel. The SelectedIndex property is directly visual related and somewhat independent of the actual data (and it is irrelevant to the viewmodel).
If you do access the viewmodel from code-behind in the view, you should try and do it via an interface. This means your viewmodel is injected or given to the view as an interface. (Note that the binding subsystem doesn't know or care about the interface, it will continue to bind in its normal way. What this achieves is better code, with less tight coupling). The way I code it, the viewmodel has no idea that a view exists, and the view only knows about the viewmodel as an interface.
One thing to remember though is that MVVM is a pattern, and a pattern is simply a recipe or prescription for achieving a certain result in a certain situation. It shouldn't be treated as a religion, where non-believers or non-conformers are going to go to some purgatory (although adherence to the pattern is good if you want to avoid the purgatory of maintenance hell and code smell).
If you want an excellent example of how this particular pattern helps, try writing a few reasonably complicated screens in ASP.Net, and then write the same in WPF or Silverlight, and note the difference.
Edit:
let me answer some of your questions, I hope it helps....
the viewmodel's (model of view) role , in my view, has UI logic and state of a view
The viewmodel should never have any UI logic or "view state" in it. For the purposes of this explanation, I would define view state as scroll position, selected row index, selected index, window size, etc. None of those belong in the viewmodel; things like SelectedIndex are specific to the way the data is shown in the UI (if you change the sort order of a DataGrid then the SelectedIndex can change, even though the SelectedItem is still the same). In this particular case, the SelectedItem can be bound to the viewmodel, but the SelectedIndex shouldn't.
If you need to keep track of UI session type info them then you should come up with something generic (for example, I have persisted view state before by saving important stuff into a KeyValuePair list) which is then "saved" with a call to the viewmodel (via the interface I mentioned previously). The view has no idea how the data is being saved, and the viewmodel has no idea the data is coming from a view (it has simply exposed a call through its interface).
and the view's role is displaying some contents and synchronizing the viewmodel(having databinding code)
Yes, the view's responsibility is simply to visually display data presented by the viewmodel. The viewmodel gets the data from the model (the model is responsible for making database calls or WCF webservice calls, this will usually be done via a "service", but that is a whole other discussion). The viewmodel can then shape or manipulate the data, i.e. it may get a list of all customers, but only expose a filtered version of that list (maybe the current customers) in a public property which the view can then bind to.
If the data is to be manipulated into something visual (a common example is an enum value being translated into a color), then the viewmodel still only has the enum value(s), and the view still binds to that value, but the view also uses a converter to translate the pure data to a visual representation. By using the converter the viewmodel has still avoided doing anything UI related, and the view has avoided any real logic.
The MVVM can split code and page design completely; coders just care about coding and designers only care about design. But:
I've never seen any designer who using Blend or understanding XAML.
Almost all XAMLs are written by coder himself.
There is nothing inherently bad in code-behind. For simple cases, it's fine to have it. However, UI logic can get difficult to manage in many scenarios. Encapsulating that logic in attached behaviors and view models allows us to isolate the variables (and test them) so that it's easier to comprehend and maintain.
If testability is a concern, the more of your UI logic that you can encapsulate in viewmodels and attached behaviors, the more you you will be able to verify without resorting to UI testing. (While it doesn't eliminate the need for UI Testing altogether, it does provide a first level of verification before engaging in UI Testing which will be more time/resource intensive.
I think the quoted section refers to the way data is visualized. I think they mean you should not write code in code behind that is, for example, related to how or where the data is displayed (for example something like: label1.Text = ...). Doing things like that using bindings makes it easier to separate design and code (what happens if you need the data to be displayed in a text box named "tbTest" in a later version? You'd have to change your code behind).
They are not saying that you shouldn't have any code in code behind - they are just saying that in an ideal world, you'd only react to events or process data that could not otherwise be processed.
At least that's what I understand from the section you quoted.
The MVVM pattern is powerful but I find it too 'Purist'. I can see benefit is having the code behind handle all the commands and properties in the view while the ViewModel is concerned with any translation to business model properties.
A benefit of this is that if you wish to change the user UI, perhaps from desktop to browser it is likely to be just replacing the View and its code behind.
Just my thoughts!!
I'm building an Silverlight application which consists of a grid containing multiple different widgets. Each widget is implemented as a ViewModel class which are then binded to grid.
With WPF I'd use implicit DataTemplates to bind certain ViewModel to a certain View. But since Silverlight doesn't support this feature I'm a bit stuck.
So far I've only thought of implementing some sort of global DataTemplateSelector to which each Prism module would register matching ViewModel and View pairs at startup. Then I could use Unity to inject this selector to grid and achieve what I want but this doesn't feel like the best way to do it.
Any ideas how should I do this?
I did some more googling and found few articles about TemplateContentControl (e.g. http://blogs.microsoft.co.il/blogs/arielbh/archive/2010/10/24/how-to-develop-mvvm-silverlight-applications-with-prism.aspx) and after some testing it seems to be just what I was looking for.
Check out the DataTemplateSelector for Silverlight.
Read about it more here.
If I have a usercontrol (in Silverlight) that I've written, that uses XAML to define it's appearance, how can I make a customised version of it?
i.e. I have MyControl.xaml & MyControl.xaml.cs
What do I need to do if I want a "SpecialisedControl" child class? I assume I just make a new code file, then inherit from MyControl. But what if I want to change the appearance of the base class - then what do I do?
I wrote this thinking you were talking about WPF, rather than Silverlight, but there may be enough overlap for this to be helpful, so I'm posting it, anyway.
If by "change the appearance of the base class" you mean "provide a new template", then what you need is probably a CustomControl, not a UserControl.
The best way to accomplish this is to follow the example set by other Microsoft controls, such as Button or ListBox:
Create a class that derives directly from Control (or whatever is closest to your control).
If any properties will need to be exposed to the control (such as text on a button, for example), make sure that you properly define them as DependencyProperties.
As described here, create a ResourceDictionary called Themes/generic.xaml and add a style for your class that includes a template (don't give the style a key).
Use TemplateBindings for any properties of elements on your control that need to get values from your control.
If you'll need to attach any event handlers to elements in your template, give them a unique name. Microsoft uses the convention of prefixing these names with "PART_", and I think it's a good thing to do for the sake of consistency, but it's not strictly required.
Again, if you need to attach event handlers, overload OnApplyTemplate(). In this method, you should detach any old event handlers (we certainly don't want any memory leaks!), and look for elements that have the names your provided in your template--when you find them, attach event handlers, as necessary.
This is certainly much more work than simply deriving from UserControl, but if you want to be able to totally re-template controls, like you can with the built-in controls, this is the way to do it.
On the other hand, if all you want to do is to provide a certain amount of limited customization, such as changing the background, or associating a Command with some user action, then the best thing to do is to expose DependencyProperties, which can then be set in styles for your control, or on instances of your control, itself.
In the case you mentioned of wanting to customize the look in an inherited control, the process is pretty similar: just add a default style for the new control with a new template; if you need to add more event handlers, just be absolutely certain that you call base.OnApplyTemplate().
I dunno, I like doing things with just plain objects. Here's an article that describes an easy way to slip a XAML-designed control outside your inheritance hierarchy so that you can customize appearance and behavior using SimpleThingsLikeInheritance rather than MicrosoftStuffThatAlmostWorks
http://gen5.info/q/2009/02/10/subverting-xaml-how-to-inherit-from-silverlight-user-controls/
As Mihnea's link describes, the easiest solution is to simply add a namespace in your XAML:
C#
public class MyBase : UserControl
{
}
public class FirstUserControl : MyBase
{
...
}
XAML
<local:MyBase
x:Class="FirstUserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:local="YourAssembly" ...>
<!-- Sticking with UserControl instead of local:MyBase makes this clearer -->
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
..
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
..Your XAML
</local:MyBase>
You can solve this by using a wrapper as described in the link above.
But you can also use the strategy pattern to solve this problem.
In this post I explain how you implement these two methods.
http://www.lab101.be/2008/07/silverlight-usercontrol-inheritance/