Dynamic control display with Silverlight, PRISM, and MVVM - silverlight

In a framework for an app that I'm creating, I can have multiple "plug-in" 's added to a "workspace", where they can be rearranged and re-sized as necessary. I want each plug-in to be able to register WorkspaceParameters (global parameters shared by all plug-ins) with a WorkspaceManager (exposed through IWorkspaceManager interface) class. When the plug-in registers a global parameter, the WorkspaceManager first checks if one with the same name as already been registered and if it has, the plugin just subscribes to be notified if it changes. If it one has not been created already with the given name, a new one is created. The WorkspaceParameter class currently looks like this:
public class WorkspaceParameter
{
public string Label { get; set; }
public Type ParameterType { get; set; }
public object Value { get; set; }
}
I then have a view in the app that I want to display each WorkspaceParameter for the user to be able to change the value. The UI should be based on the ParameterType member of each WorkspaceParameter and all of the parameters should be displayed in a StackPanel. For example, if the Type is DateTime, I want to display a textbox with a calendar selector next to it. If it's a string, a simple Textbox with the label next to it, and lastly for now, if it's an enum type, a dropdown with the available enum options.
How can I implement this dynamic view using the principles of PRISM and MVVM?

I would recommend to look at a series of Blogpost by Glenn Block.
In the last article he refactored his solution to use the mvvm pattern.
He uses MEF heavily this is a framework for extensibilty.
This is No. 5 of a sequal please read all of them it could be basically what you were looking for.
http://msmvps.com/blogs/theproblemsolver/archive/2009/02/18/getting-started-with-the-repository-pattern-in-silverlight.aspx

Related

What constitutes a viewmodel?

I'm still not totally sure what constitutes a view model. I have a class that I use to wrap my model and alter the data slightly, but I am not sure whether it constitutes a view model. What is necessary to be considered a view model? Is it merely not supposed to have direct dependencies on the view, so that the viewmodel does not know how the view uses its properties and the view does not know what is in the viewmodel? and when the view wants to update anything it just gives some abstract command that the viewmodel takes and uses to update the model?
As I understand it in MVVM, I'm supposed to use properties on the view that bind to properties on the viewmodel that bind to properties on the model.
and in the reverse direction, I'm supposed to use commands from the view to the viewmodel, which then can either uses Icommand to command the model, or can just call public functions in the model to make changes to it.
One confusing thing is that in the example of MVVM that I saw made it seem like in MVVM the view should have no code behind other than perhaps creating commands, but I don't see how I could do that in my current project. I'm making a custom control using lots of controls that are interacting on events.
how would I make one treeview expand on another treeview's expand without using events?
Often, View Models end up being very similar to your domain models. One of the main goals of having View Models is to separate the GUI development from the business logic. For example, let's say you have a "User" domain model that has an IsAdmin property which you don't want exposed to the View. You create a View Model called "UserViewModel" that still has the ID, Username, and Password (see example code below), but doesn't have an IsAdmin property. Another approach is to use the domain model inside your view model, see the "AlternateUserViewModel" class below. There are pros and cons to any View Model solution. Creating the UserViewModel class with properties means you are essentially duplicating the objects you created for the domain model, since often times your domain models will be very similar to your view models. With the AlternateUserViewModel approach, there's not clear separation between your business logic layer and your GUI layer because the view model still needs to "know" about the domain model. What approach you decide on really depends on the environment you're working in. For personal projects, I like using the 2nd approach because separating the business logic from the design layer isn't such a major concern that I wouldn't want to let the view model layer "see" the domain model layer, but for a large corporation where you have separate teams working on the design layer and the back-end, the first approach may be preferred.
public class User
{
public int ID { get; set; }
public string Username { get; set; }
public string Password { get; set; }
public bool IsAdmin { get; set; }
}
public class UserViewModel
{
public int ID { get; set; }
public string Username { get; set; }
public string Password { get; set; }
}
public class AlternateUserViewModel
{
public User User { get; set; }
public User ToDomainModel()
{
if (User == null)
return null;
// if this is an existing user, retrieve it from the database so you're not overwriting the IsAdmin property
if (User.ID != default(int))
{
User existingUser = UserService.GetUserByID(User.ID);
existingUser.Username = User.Username;
existingUser.Password = User.Password;
// IsAdmin is not set because you don't want that property exposed in the View Model
return existingUser;
}
else
{
return new User
{
Username = User.Username,
Password = User.Password,
IsAdmin = false
};
}
}
}
You have a number of questions here (consider breaking it into multiple posts). I'll try to answer some.
I think of ViewModel as THE app, in other words, this is where most of the app's logic happens.
In other words, ViewModel receives an input of:
Commands from the View
Changes in bound properties from the View
Events from a background service (e.g. when data is received from the Web)
Other events from the system or from domain models
and generates an output of:
changing properties that the View would bind to (e.g. IsBusy that could cause the View to display the waiting indicator)
showing/hiding stuff in the View (indirectly, of course, for example using various bool Properties)
causing navigation to other Views (also indirectly, since it doesn't have direct access to NavigatonService available to the View).
Another way to think about the ViewModel is like so: the ViewModel is the complete user-facing state of the system. In other words, this state and nothing else would be used by the View to show/present this state in some user-understandable way.
About Commands vs. Events:
Unfortunately, not everything in WPF is exposed as a Command. Buttons generate Commands, but not all controls do.
Luckily, you can use Behaviors to translate Events to Commands and some frameworks provide the implementation. Here's an example of how MVVM Light does this. Blend also provides this functionality.
Also, why do you need to generate Commands in the code-behind? Frameworks like MVVMLight provide an implementation of a RelayCommand (or DelegateCommand) that removes the need to create different ICommand implementations. You can just as easily implement it yourself.

How to properly work with an ItemsSource on demand?

I want to bind a list of persons to a DataGrid control.
The objects are loaded on demand, this means that initally I only have a List of IDs (int). In the DataGrid itself I want the objects (of type Person) with all their properties.
For that I used an IValueConverter that converts my List<int> to List<Person>.
I want to bind the SelectedItem to a property int SelectedId. I cannot simply bind to Person, since my Person class has no ID property. But with the value convertion the SelectedItem obviously is of type Person.
Should I initially load the objects in a Dictionary instead and bind that to the ItemsSource. SelectedItem would then be a KeyValuePair.
What other approaches are possible?
IMHO the best way to provide data in a list, is an ObservableCollecion<T>. I'm convinced that this is also the common way, but I've no source to prove it. So it's an IMHO statement.
It implements the INotifyCollectionChanged interface, so that the view is noticed about any changes (adding and removal of items). For more information pls refer here. If the item in the collection, in your case Person, is implementing INotifyPropertyChanged, the view will also be notified regarding changes of the items itself. Please have a look here for more information.
So if I where you, I would put an id property into Person and load the whole collection into an ObservableCollection. If you cannot modify Person you could create a wrapper like
public class PersonVm
{
public int Id { get; set; }
public Person Person { get; set; }
public PersonVm(int id, Person person)
{
Id = id;
Person = person;
}
}
You will have to add the implementation of INotifyPropertyChanged by yourself, if you want to have the notification feature of the items.
Btw, what I described here is a typical implementation of the MVVM pattern. It has definitely many advantages to implement a WPF application with it, but there are some disadvantages too. E.g. there is an overhead which may not be worth the effort in smaller projects. You can get an overview here.

Using WPF design data with the MVVM pattern

I'm using the MVVM pattern in our WPF application to allow for comprehensive unit testing. The MVVM pattern itself is working great, however I'm struggling to adapt the pattern in a way that means I can use the design-time data support of WPF.
As I'm using Prism the ViewModel instances are generally injected into the constructor of the view, like so
public MyView(MyViewModel viewModel)
{
DataContext = viewModel;
}
Dependencies for the ViewModel are then injected into the constructor, like so
public class MyViewModel
{
public MyViewModel(IFoo foo, IBar bar)
{
// ...
}
// Gets and sets the model represented in the view
public MyModel { get; set; }
// Read-only properties that the view data binds to
public ICollectionView Rows { get; }
public string Title { get; }
// Read-write properties are databound to the UI and are used to control logic
public string Filter { get; set; }
}
This is generally working really well except when it comes to design data - I wanted to avoid compiling design-data specific classes into my released assembly and so I opted to use the {d:DesignData} approach instead of the {d:DesignInstance} approach, however in order for this to work correctly my ViewModel now needs to have a parameterless constructor. In addition, I also often need to change additional properties either to have setters or to be modifiable collections in order to be able to set these properties in XAML.
public class MyViewModel
{
public MyViewModel()
{
}
public MyViewModel(IFoo foo, IBar bar)
{
// ...
}
// Gets and sets the model represented in the view
public MyModel { get; set; }
// My read-only properties are no longer read-only
public ObservableCollection<Something> Rows { get; }
public string Title { get; set; }
public string Filter { get; set; }
}
This is worrying me:
I have a parameterless constructor that is never intended to be called and isn't unit tested
There are setters for properties that only the ViewModel itself should be calling
My ViewModel is now a jumbled mixture of properties that should be modified by the view, and those that shouldn't - this makes it tricky to tell at a glance which piece of code is responsible for maintaining any given property
Setting certain properties at design time (e.g. to see styling on the Filter text) can actually end up invoking ViewModel logic! (so my ViewModel also needs to be tollerant of otherwise mandatory dependencies being missing at design time)
Is there a better way to get design-time data in a WPF MVVM application in a way that doesn't compromise my ViewModel in this way?
Alternatively should I be building my ViewModel differently so that it has more simple properties with the logic separated out somewhere else.
First, I would recommend you to have a look at this video where Brian Lagunas provides several best practices about MVVM. Brian is - at least - involved in the development of Prism, as his name appears in the nuget packages information. Didn't check further.
On my side I only use bits of Prism, and my Model and ViewModel always offer blank constructors (like what Brian shows), the data context is assigned in the view's XAML, and I set the properties values like :
<MyView.DataContext>
<MyViewModel />
</MyView.DataContext>
and
public void BringSomethingNew()
{
var myView = new View();
(myView.DataContext as ViewModel).Model = myModel;
UseMyView();
}
Another benefit with this approach is that the ViewModel is created once, with the same path at design and run time, so you create less objects and save GC efforts. I find this elegant.
With regards to the setters, the design data will still work if you make them private, like:
public string MyProp { get; private set; }
Ok, customize it to manage NotifyPropertyChange at your convenience, but you've got the idea.
Now, I don't have yet a solution to manage ObesrvableCollections (I face the same problem, although putting multiple values in XAML sometimes work... ???), and yes, I agree that you have to manage the case when the properties are not set, like setting default values in the constructor.
I hope this helps.
I too have worked with NUnit testing with WPF and MVVM implementation. However, my version is reversed from yours. You are creating the view first, then creating the model to control it.
In my version, I create the MVVM model FIRST and can unit test it till the cows come home and not worry about any visual design... if the model is broken, so too will the visual implementation.
in my MVVM model, I have a method to "GetTheViewWindow". So, when I derive from my MVVM baseline, each view model has its own view its responsible for. So via a virtual method, each instance will do its own new view window when being applied for production.
public class MyMVVMBase
{
private MyViewBaseline currentView;
public MyMVVMBase()
{ // no parameters required }
public virtual void GetTheViewWindow()
{ throw new exception( "You need to define the window to get"; ) }
}
public class MyXYZInstanceModel : MyMVVMBase
{
public override void GetTheViewWindow()
{
currentView = new YourActualViewWindow();
}
}
Hope this helps as an alternative to what you are running into.

What approach should I use when creating a custom WPF control?

I'm about to redo an old WinForms application as a WPF application. The core of this applicaton is a custom "grid" component. I'd like some ideas on the best way to do this as a WPF component.
The application displays a grid of data for different countries/sectors. Each cell of the grid displays different information (e.g. graph, image) depending on the available data for that country/sector.
I have a domain model assembly that I want to keep clean - to maximize reuse. The structure is as follows:
Table
Continents
Countries
Sectors
Data[country, sector]
The grid displays countries down the left and sectors across the top.
In the current application, the grid component has a (POCO) Table property and an Refresh() methods to manually redraw it. So, if the Table is updated, the parent of the grid component refreshes it. The grid component also has a number of events that are fired if a continent, country or cell is clicked - so that the parent can response with pop-up menus, etc.
This all works fine.
However, I'm wondering whether this is the correct model to use for a WPF application. Looking at many of the WPF example, they support data-binding, etc. But, it's not clear, from the simple examples, how I might bind a complex object to my components - or whether it would even be worthwhile.
Also, the WinForms component is completely custom drawn - there are no sub-controls (e.g. Labels) in use. Would it be better to use a WPF user control and build the table from a GridLayout and lots of Label, Shape, etc controls? In practice, they are maybe 20 rows and 20 columns in the grid, and the user regular removes and adds countries/sectors (rows/columnms) while using the application.
My immediate goal is to make sure my design plays well in the WPF eco-system, but I have a secondary goal of learning how to do things in a WPFy way - given this is my first WPF app. I'm pretty on top of the use of building a general WPF app - it's just the custom control stuff that remains a little fuzzy (even after reading around it a little).
Any insights/guidance would be appreciated.
You definitely want to adapt the MVVM approach, as outlined by Josh Smith. Practically, this means that your custom grid component will be contained in it's own View. Backing the view will be your ViewModel, where you will define an ObservableCollection of objects containing your data. These objects will probably come from your Model. This interaction is shown below:
Models:
public class TableData
{
public string Country { get; set; }
public string Continent { get; set; }
public object Sector { get; set; }
}
public class TableManager : ITableManager
{
public Collection<TableData> Rows;
public void GetData()
{
this.Rows = new Collection<TableData>();
this.Rows.Add(...
}
}
ViewModel:
public class TableViewModel
{
private ITableManager _tableManager;
public TableViewModel() : base(new TableManager())
{
}
// for dependency injection (recommended)
public TableViewModel(ITableManager tableManager)
{
_tableManager = tableManager;
_tableManager.GetData();
}
public ObservableCollection<TableData> Rows
{
get { return _tableManager.Rows; }
}
}
View:
<ctrls:CustomDataGrid
ItemsSource={Binding Rows}
AutoGenerateColumns=True
>
<!-- Use AutoGenerateColumns if the # of sectors is dynamic -->
<!-- Otherwise, define columns manually, like so: -->
<DataGridTextColumn
Width="*"
Header="SectorA"
Binding="{Binding Country}
/>
</ctrls:CustomDataGrid>
I used CustomDataGrid in the view because I assume you're going to subclass your own DataGrid. This will allow you to override events to customize the DataGrid to your liking:
public class CustomDataGrid : DataGrid
{
public override Event...
}

WPF MVVM Dilemma: ViewModel as Control-derivate with Style or as POCO with UserControl?

I am currently working on a new project of mine that is going to be a data record visualizer (for records in Pascal). It should provide a way to define a given record with data fields and pointer fields and then there will be an example view where you can see the record "in action".
Now the problem I am having is that in this model there are records and components and the relationship between them is that one record has multiple components (data and pointer as mentioned above).
I want to use MVVM for the app but I am now unsure how I should approach this. I modelled the record and components into RecordViewModel and ComponentViewModel (with derivates DataComponentVM, PointerComponentVM).
Now to provide a look for these VMs there are 2 options as far as I know:
Deriving the ViewModels from Control and providing a ControlTemplate
Creating a UserControl using the ViewModel as DataContext
The UserControl approach works fine for the RecordViewModel but when I try to design the way the ComponentViewModels are shown (in a ContentPresenter) this approach fails because I would need to provide a collection of UserControls (instead of DataComponentViewModels) in my RecordViewModel that would make that work (and I am pretty sure that is not a good idea).
The Control approach also has the problem that the ViewModels aren't POCOs anymore which I think has a strange feel to it and is also not considered good practice.
Is there any other way to solve the problem? Do you have any other good advice for me in this regard?
Thanks in advance!
Code:
public class RecordViewModel : BaseViewModel
{
public RecordViewModel()
{
Components = new ObservableCollection<ComponentViewModel>();
}
public ObservableCollection<ComponentViewModel> Components { get; set; }
}
public class DataComponentViewModel : ComponentViewModel
{
public string Type { get; set; }
}
public class PointerComponentViewModel : ComponentViewModel
{
public object Target { get; set; }
}
Oh god why didn't I think of this before?
I was only thinking about ControlTemplates (therefore needing my ViewModels to derive from Control) when there are also DataTemplates that work exactly like I wanted them to.
I got lost as to why you think you need to provide a collection of user controls, but it sounds like what you really want is for the RecordViewModel to have some variation of:
ObservableCollection<ComponentViewModel> Components
Components is then bound in xaml to the ItemsSource property of some sort of ItemsControl. Whether or not the ComponentViewModel needs it's own UserControl depends on what you are trying to do with it.
If that doesn't start to click for you then you may want to post some code so we can sort it out.

Resources