I have a list of items representing packages in an MVVM control.
When you hover over the tooltip it needs to go to the database for additional information, lets just call it 'PackageDetails' for simplicity. I know how to handle the database loading with a ViewModel class but I'm having trouble figuring out when to instantiate it.
Approach 1) Have a 'lazy-load' property in the 'Package' object so when the tooltip is triggered the viewmodel will be created and immediately access the database.
This approach isn't ideal because each 'Package' object isn't a true viewmodel and came from WCF objects originally.
Approach 2) Use a converter as explained in this Josh Smith blog entry. His example seems to fit a converter well, but I don't think it really suits my situation well.
Approach 3) Somehow create a viewmodel in the XAML, but this seems like a bad idea.
What's a good approach to dynamically generate a viewmodel for a tooltip using MVVM
?
Binding models ( in your case the packages ) to the view only works for very simple situations where there is no more "processing" or business logic to implement.
I have experimented with a few options and in the ended up creating a VM wrapper for just about all my models. Going down this path makes having a tooltip property straight forward.
The other option that i have experimented with is to use partial classes to extend the wcf models. This works unless you are using dataannotations for validation ( wcf and dataannotations dont work together properly )
if you decide to wrap your models with a vm, then instantiating your list of VM wrappers is just one line of code using linq and lambdas
assuming you have a constructor on your VM that accepts your model as a parameter.
var listPackageVMs = new ObservableCollection<PackageVM> ( listPackageModels.Select(model=> new PackageVM(model)));
You could create a partial class to Package. I would avoid placing data access logic in an entity class, but this is the cheap and easy way.
namespace WCFServiceNamespace
{
// Since WCF generated entities are partial classes, we can inject features
public partial class Package
{
private readonly IDataAccessor _DataAccessor;
public Package()
: this(DataAccessor.Instance) // how you choose to inject a data accessor is up to you
{
}
public Package(IDataAccessor dataAccessor)
{
_DataAccessor = dataAccessor;
_ToolTip = new Lazy<string>(GetToolTip);
}
private readonly Lazy<string> _ToolTip;
public string ToolTip
{
get
{
// executes GetToolTip when the Value property of Lazy<T> is accessed
return _ToolTip.Value;
}
}
private string GetToolTip()
{
// we're assuming we can retreive the tooltip by ID, and that PackageId is defined in the generated WCF entity
return _DataAccessor.GetToolTipByPackageId(PackageId);
}
}
}
Related
I need to send notification from ViewModel to View in MVVM WPF application. In most cases it will be simple MessageBox on View side. Is it unacceptable violation of MVVM pattern to use types like System.Windows.MessageBoxResult or System.Windows.MessageBoxImage in ViewModel (in this case VM must reference UI-specific libraries)?
I need to pass title, message and notification type from VM and by creating custom enumerations I am in fact copying existing functionality from .NET Framework.
You don't need notification mechanism. That's one option. Another is using simple service class:
public class ViewModel
{
IDialogService _dialogService; //ctor injection or use service locator
public void CommandExecute()
{
_dialogService.ShowMessageBox(...);
}
}
public interface IDialogService
{
bool? ShowMessageBox(params....);
}
public class DialogService : IDialogService
{
public bool? ShowDialog(params...)
{
MessageBox.Show(params...);
}
}
I find this approach more straightforward, easier to understand and easier to debug. Messaging may easily turn into memory leak and in this case I don't see any benefit over my approach.
EDIT:
Will you use custom enum in ShowMessageBox parameters, or will you use
System.Windows.MessageBoxImage?
First of all, ViewModels belong to presentation layer. It is OK to use enums like System.Windows.MessageBoxImage in ViewModel.
In MVVM, ViewModels are separated from Views because of following reasons:
ViewModels expose data and logic from Model in such way that is easily consumable from Views (e.g DataBinding)
ViewModels are easier testable
ViewModels provides better design time support (Blendability, test data)
ViewModels separates application logic from the actual presentation markup which makes it easier to understand (readbility)
Does using enum like System.Windows.MessageBoxImage breaks any of the points above? The answer is no.
If you wanted to reuse IDialogService and your ViewModels on multiple platforms, for example WPF, UWP and Xamarin, then you need to create your own enum, because it may not exist on all platforms. The golden rule is: don't add another layer of abstraction if you don't need it.
You could have the view implement an interface, say INotificationService and then pass the view to the view model constructor. That won't violate MVVM, and you will still be able to bind the view model to the view using the DataContext property on the view.
I decided to keep ViewModel as clean of UI (View) stuff as possible, so I will create custom enumeration inspired by MessageBox and tailored exactly to my needs.
I'm working on a WPF project that's a mishmash of code-behind xaml/xaml.cs and a few not-quite ViewModels as well.
(Disclaimer: Until recently I've had very little in the way of WPF experience. I can design and lay-out a Window or UserControl fairly proficiently, and I think I get the hang of separating an MVVM ViewModel from the View and doing binding wire-ups, but that's the limit of my experience with WPF at present.)
I've been tasked with adding some new features to the program, such that it looks like converting it to use MVVM properly first is going to be necessary.
I'll demonstrate a specific problem I'm facing:
There is a View called SettingsWindow.xaml that I'm working with. It's a set of textboxes, labels and whatnot. I've stripped-out all of the View data into a ViewModel class which resembles something like this:
class SettingsViewModel : ViewModelBase {
private String _outputDirectory;
public String OutputDirectory {
get { return _outputDirectory; }
set { SetValue( () => this.OutputDirectory, ref _outputDirectory, value) ); }
}
// `SetValue` calls `PropertyChanged` and does other common-tasks.
// Repeat for other properties, like "Int32 Timeout" and "Color FontColor"
}
In the original ViewModel class there were 2 methods: ReadFromRegistry and SaveToRegistry. The ReadFromRegistry method was called by the ViewModel's constructor, and the SaveToRegistry method was called by MainWindow.xaml.cs's code-behind like so:
private void Settings_Click(Object sender, RoutedEventArgs e) {
SettingsViewModel model = new SettingsViewModel(); // loads from registry via constructor
SettingsWindow window = new SettingsWindow();
window.Owner = this;
window.DataContext = model;
if( dialog.ShowDialog() == true ) {
model.SaveToRegistry();
}
}
...but this seems wrong to me. I thought a ViewModel should consist only of an observable data bag for binding purposes, it should not be responsible for self-population or persistence, which is the responsibility of the controller or some other orchestrator.
I've done a few days' worth of reading about MVVM, and none of the articles I've read mention a controller or where the logic for opening child-windows or saving state should go. I've seen some articles that do put that code in the ViewModels, others continue to use code-behind for this, others abstract away everything and use IService-based solutions, which is OTT for me.
Given this is a conversion project where I'll convert each Window/View individually over-time I can't really overhaul it, but where can I go from here? What does a Controller in MVVM look-like, exactly? (My apologies for the vague terminology, it's 3am :) ).
My aim with the refactoring is to separate concerns; testability is not an objective nor would it be implemented.
I personally disagree with putting much in my ViewModels beyond the stuff that is pertinent to the View (it is, after all, a model of a View!)
So I use a Controller paradigm whereby when the View tells the ViewModel to perform some action (via a Command usually) and the ViewModel uses a Command class to perfrom actions, such as saving the data, instantiating new View/Viewmodel pairs etc.
I also actually separate my ViewModel and ViewData (the ViewModel 'contains' the ViewData) so the ViewData is puirely dealing with the data, the ViewModel with some logic and command handling etc.
I wrote about it here
What you need is called Commanding in WPF.
Basically you bind Button.Command to a ICommand property in your ViewModel and when Button is clicked you get a notification in ViewModel without using code behind and casing DataContext or whathever hacks you tried.
http://msdn.microsoft.com/en-us/library/ms752308.aspx
I have a Windows Forms application which makes use of an MVP pattern. Each view is a WinForms user control and is backed by a presenter which handles non-UI concerns. The application makes use of Castle Windsor, and all views presenters and many other components are resolved via the Windsor Container.
What I would like to be able to do is customise property injection for the user control views. My views don't make a whole lot of use of property injection, but it is occasionally very useful and works well. The problem is, my user controls often contain nested controls, which in turn can contain other nested controls, and property injection is not going to work for these nested controls, because they were not directly resolved via the container.
What I would like to do is to configure property injection for components that inherit from the SWF Control class. In addition to finding properties on the component, I would like to also find properties on nested controls (in the Controls) collection and inject into these nested properties as well.
I know that Castle Windsor is extremely flexible and configurable so this may be possible. I need a bit of a nudge in the right direction though. Is this possible? Has anyone tried to do something similar?
If I have understood your question correctly I think that the only way to achieve what you want is by some sort of poor man's dependency injection because the way the winforms designer generates a method that constructs the various sub-controls you speak of makes it decidedly uncondusive to IoC.
I am not sure you will be able to do property injection but you can utilise the constructor, here is a hair-brained scheme I have just concocted ...
Firstly, create some way to access your windsor container - something like this would probably do the trick:
public static class MyContainer
{
private static readonly IWindsorContainer _container = Bootstrap();
// I did it like this so that there is no explicit dependency
// on Windsor - this would be the only place you need to change
// if you want an alternate container (how much you care about
// that is up to you)
public static T Resolve<T>()
{
return _container.Resolve<T>();
}
private static IWindsorContainer Bootstrap()
{
var container = new WindsorContainer();
container.Install(FromAssembly.This());
// ... whatever else you need to do here
return container;
}
}
Secondly, in the inner controls, where you want some properties injected do something like this (I went for the good ol' ILogger as an example of something you may want injected):
public partial class MyFancyControl : UserControl
{
// Constructor to keep the winforms designer happy
public MyFancyControl()
: this (MyContainer.Resolve<ILogger>())
{
// Intentionally always blank as this
// is an un-unit-testable method
}
// Constructor that does the actual work
public MyFancyControl(ILogger logger)
{
InitializeComponent();
Logger = logger;
}
public ILogger Logger { get; private set; }
}
Note: using the logger raises one of the couple of obvious smells in this - sometimes you don't register such a component with the container at all (usually you have a null logger) so you may need to hook up some sort of mechanism for that but I leave that up to you if you need it or not.
In our application we have many Model objects that have hundreds of properties.
For every property on the model:
public string SubscriptionKind { get; set; }
...100x...
we had to make an INotifyPropertyChanged-enabled property on the ViewModel:
#region ViewModelProperty: SubscriptionKind
private int _subscriptionKind;
public int SubscriptionKind
{
get
{
return _subscriptionKind;
}
set
{
_subscriptionKind = value;
OnPropertyChanged("SubscriptionKind");
}
}
#endregion
...100x...
which meant that when our View sent the Save event, we had to remap all these values of the view model back into the model:
customer.SubscriptionKind = this.SubscriptionKind
...100x...
This became tedious and time-consuming as the models kept changing and we had to map all changes up into the ViewModels.
After awhile we realized that it would be more straight-forward to just connect the DataContext of the View directly to the Model which enables us to bind the XAML elements directly to the Model object properties so that the save event would simply save the object without any mapping whatsoever.
What we lost in this move is:
the ability via UpdateSourceTrigger=PropertyChanged to do fine-grained validation and manipulation in the ViewModel Property Setters, which I really liked: this we don't have anymore since any change in XAML simple changes the dumb property on the Model
the ability (in the future) to create mock views which test our viewmodel's UI logic in a novel way, e.g. "if property SubscriptionKind is set to "Yearly" then (1) change discount to 10%, (2) run "congratulations animation", and (3) make order button more prominent.
Both of these approaches have obvious advantages, e.g. the first way "View-direct-to-Model" approach especially when combined with LINQ-to-SQL is pragmatic and enables you to produce useful software fast, and as long as you use {Binding...} instead of x:Name you still have the ability to "hand off your views to a Blend Designer".
On the other hand, although MVVM requires you to maintain tedious mapping of Model to ViewModel, it gives you powerful validation and testing advantages that the first approach doesn't have.
How have you been able to combine the advantages of these two approaches in your projects?
Since your ViewModel has access to the model, you can also just directly wrap the model's properties:
#region ViewModelProperty: SubscriptionKindprivate
// int _subscriptionKind; - Use the model directly
public int SubscriptionKind
{
get
{
return this.Model.SubscriptionKind;
}
set
{
if (this.Model.SubscriptionKind != value)
{
this.Model.SubscriptionKind = value;
OnPropertyChanged("SubscriptionKind");
}
}
}
#endregion
The advantage here is you can keep your validation in place in the ViewModel if you wish, and have more control over how it's set back to your model, but there is less duplication in place.
Why not use a mapping tool like AutoMapper? It's speedy and you don't have to write all of that mapping code:
Mapper.CreateMap<MyModel, MyViewModel>();
MyViewModel vm = Mapper.Map(myModelInstance);
Really easy and now you get the best of both worlds.
Automapper uses a technique that generates assemblies on the fly to do the mapping. This makes it execute just as fast as if you had written all of that tedious mapping code, but you don't have to.
Since my model objects are business objects, not directly related to the datamodel, I use them directly in the ViewModel.
The first mapping (datamodel to business object model) and the creation of properties are generated by a code generator.
I used a t4 Generator class to create my ViewModels from XAML not sure if this would help your situation.
When using .NET RIA Services and MVVM in Silverlight 3.0 is there a difference between the Metadata type from RIA Services and the ViewModel from the MVVM pattern? Are these the same thing or should they be keep separate?
The metadata type is a sealed internal class to the partial Entity class. There doesn't seem to be a proper separation there but the metadata type can also be decorated with attributes for Validation which makes it look like a ViewModel.
I've searched around but I didn't see anything that talks about this in any detail.
Agree with ChuckJ - generally the DomainContext forms part of a view model. For example, say I had a search page that allowed searching against a product catalog. Here is how I'd structure things:
On the server:
class Catalog : DomainService {
IQueryable<Product> GetProducts(string keyword) { ... }
}
The generated DomainContext:
class Catalog : DomainContext {
EntityList<Product> Products { get; }
void LoadProducts(string keyword);
}
The view model I would write:
class SearchViewModel {
Catalog _catalog = new Catalog();
public IEnumerable<Product> Results {
get { return _catalog.Products; }
}
public void Search(string keyword) {
_catalog.Products.Clear();
_catalog.LoadProducts(keyword);
}
}
And then finally in my xaml, I'd set my UserControl's DataContext to be an instance of SearchViewModel, and bind an ItemsControl to the Results property. I'd use the ViewModel pattern of your choice to bind a button click to Search (which is effectively a command that SearchViewModel exposes). I personally like something that I have working with Silverlight.FX as in:
<Button Content="Search"
fxui:Interaction.ClickAction="$model.Search(keywordTextBox.Text)" />
and as initially shown here.
As Chuck mentions I might indeed have other state in my view model, for example, the SelectedProduct that might be two-way bound to the SelectedItem of a ListBox in my xaml, and then bind the same SelectedProduct as the DataContext of a DataForm to show details of a selected product.
Hope that helps! I'll be blogging about this some more on my blog soon.
The RIA services data context was designed to play the role of a ViewModel in the MVVM pattern since they natively support data binding, but they don't use that term in their documentation. However, it really depends. You will probably need state in your view model than the RIA data context provides such as commands and other view related state. I think what you want to do is use the data contexts from the RIA services as a part of the view model.