I'm trying to design a WPF application where users can design an algorithm flow chart. This means lots and lots of graphics on my grid. (I was going to use Canvas, but decided to go with grid since canvas doesn't support ScrollViewer natively). I am using MVVM design pattern in my application.
To add/remove graphics dynamically, what states from viewmodel should I export to my view?
As is typical with in all cases where you are going to be displaying a collection of items, you need to:
Create a class that represents each item (i.e. a Model for the items)
Expose an ObservableCollection of this class as a property of your ViewModel
The particulars may vary quite a bit though. I cannot visualize how exactly you intend to implement the view as a Grid, so here are some guidelines assuming it were a Canvas.
Determine your persistence model
When the items are placed on the view, is the user going to be able to move them around? Should their positions be faithfully reproduced if the document is saved, closed and then reopened? If so, then your model for the items needs to aggregate these display parameters. If not, then the view might decide how to position the items itself at runtime.
Use sub-ViewModels if it makes sense
If your item models are very simple then it's possible that you can represent them visually using an inline ItemTemplate for your ItemsControl. If not, then you might want to create an ItemViewModel and expose an ObservableCollection<ItemViewModel> from your main ViewModel.
Related
I am completely new to WPF and MVVM, that's why I decided to start working on that. I am developing a Battleship game. If I create Canvas in my View, and create another canvas in ViewModel and bind them - everything works fine. However there is a problem. To begin with, I add Rectangles and TextBlocks to my Canvas to represent the grid. My "Field" Class (Model) is used in ViewModel for the logic to be done. And I want to have the property inside that class IsLegendHidden (bool). If I set that to true, then the method is called. In that method the linq looks for the textblocks related to my legend and then sets their visibility to hidden. It works fine, however having logic in the Model class is wrong in MVVM structure. But moving the algorithm to the ViewModel side will eliminate the ability to use class property "IsLegendHidden". But I want to have that property inside the model class. How can I solve that?
Your Model Class is free to implement INotifyPropertyChanged and it can notify the ViewModel when a particular property changes. This allows you to have a simpler model and get the logic done in the ViewModel.
You can also have a separate modeling of properties that are more focused on view concerns that the ViewModel can consult.
When using MVVM I like to try to separate things as much as possible. The model objects should just represent the concept they're modeling. The ViewModel is tied to a specific view so it will interpret or translate the model's properties into what is important to the view. You can have something on the Model that isn't 'IsLegendHidden', but that powers the ViewModel's 'IsLegendHidden' property.
I am working on mvvm in c# wpf, I have a little understanding of mvvm.
I am creating an object of my View class in My ViewMode classl.so is it violating mvvm pattern? and how ? it would be great if some one explains this in detail..
The whole point of the MVVM pattern is to maintain separation of the View (the display that presents controls to the user) from the Model (data, the business logic, data-access) and the ViewModel (the glue between the model and the view). The VM should not have to worry about UI (i.e. View) concerns, so creating and using a view within a viewmodel is violating that MVVM pattern.
A View is nearly always made up of UI elements, such as buttons or textblocks. A Viewmodel should be concerned with things like properties, such as a UserName, or a StartDate, or a WarningState. These VM properties are then bound (with DataBinding) to properties on UI elements within a view ... so the view has a dependency on the VM but not the other way around. Where the VM gets the data from to populate those properties in the first place is the model, or for data-entry maybe they'll all be blank to begin with and the application relies on the user entering data in the view.
You might want to bind the WarningState to a TextBox, for example, but equally you could bind it to a ComboBox. Or you could use a converter and bind it to the foreground colour of a rectangle, or the background colour of a UI element that is used for something else entirely different.
The point is that these are things the VM doesn't need to worry about: all it cares about is presenting data/state. It is up to the view how it deals with that information (or doesn't deal with it). In this way you could completely replace the view with a different version, and not have to change anything in your VM ... you have successfully separated your display from your logic.
I have multiple of views (user controls), each with its own ViewModel. To navigate between them I am using buttons. Buttons display image and text from corresponding view model and also need column and row (because there are like 10 views: 10 columns with different number of rows each).
Right now buttons are created dynamically (I made a Navigator control for this) and for view models I have base class to hold text, image, column and row. Number of views available will be different (depends on user level and certain settings), that's why it's I need control here.
Question: how shall my control get data from view models?
Right now I have interface INavigator, defined in (lol) control itself. And view models implement it. I could go opposite, let my control to know about view models. Both looks wrong.
There is a single Navigator control what has, lets say, Items bound to a list of view models. It can cast each view model to INavigator or ViewModelBase (common for all pages) to obtain specific view model image, text, column and row. So either view model knows about control (to implement INavigator) or control knows about ViewModelBase.. And this is a problem, both solution bind tight control and view models, which is bad in mvvm.
Schematically
The way you've drawn your diagram answers your own question as to how you should structure the code for this.
What you need is one VM (let's call it MainVM) which contains an ObservableCollection<VMBase> of the other VMs (using your base type so that they can all happily live in the same collection).
Your View needs an ItemsControl (bound to your ObservableCollection<VMBase>) where you specify a DataTemplate for the Button using the properties exposed by the VMBase type only. Set the Command property in the Button to call SwitchCommand, CommandParameter is set to the item itself (i.e. {Binding .}).
Your View also needs a ContentControl bound to a SelectedVM property on MainVM which you can populate.
Implement SwitchCommand to set the SelectedVM property based on the value from the CommandParameter.
public void ExecuteSwitchCommand(object parameter)
{
var vmBase = parameter as VMBase;
if (vmBase != null)
SelectedVM = vmBase;
}
All properties mentioned here should be INotifyPropertyChanged enabled so that the View registers when they change and updates the UI.
To get the different UIs for the ContentControl, add type-specific DataTemplates for each of your specific VM types to the Resources file of your View (or if you're smart and are building a custom plug-in framework, merge the Resource Dictionaries).
A lot of people forget with MVVM that the whole point is that there is a purposeful separation of View from ViewModel, thus meaning you can potentially have many Views for a single ViewModel, which is what this demonstrates.
I find it's easiest to think of MVVM as a top-down approach... View knows about it's ViewModel, ViewModel knows about its Model, but Model does not know about its ViewModel and ViewModel does not know about its View.
I also find a View-first approach to development the easiest to work with, as UI development in XAML is static (has to be).
I think a lot of people get to wrapped up in 'making every component (M, V, VM) standalone and replaceable', myself included, but I've slowly come to the conclusion that is just counter-productive.
Technically, sure you could get very complicated and using IoC containers, create some ViewLocator object which binds a View-type to a ViewModel-type, but... what exactly does that gain you besides more confusion? It makes it honestly harder (because I've done this at one point) to develop because now you've lost design-time support first and foremost, among other things; and you're still either binding to a specific view model interface in your view or creating the binding at run-time. Why complicate it?
This article is a good read, and the first Note: explicitly talks about View vs. ViewModel. Hopefully, it will help you draw your own conclusions.
To directly answer your question, I think having your ViewModels implement an INavigator interface of some sort is probably ideal. Remember your VM is 'glue' between your view and model/business logic, its job is to transform business data into data that is consumable by your views, so it exists somewhere between both your UI and business layers.
This is why there are things like Messengers and View Services, which is where your navigator service on the ViewModels can fit in nicely.
I think the design has led to a no way out situation.
I believe that creating a custom button control where the dependency properties tie the image, the row and column actually provide a way for the page, which it resides on ,to get that information to them; whether they are dynamically created or not.
Continuing on with that thought. There is no MVVM logic applied to a custom control, the control contains what it needs to do its job and that is through the dependency properties as mentioned. Any functionality of the button should be done by commanding; all this makes the button data driven and robust enough to use in a MVVM methodology or not.
Question: how shall my control get data from view models?
There should only one viewmodel which is the page the control resides on. The control is simply bound to information which ultimately resides on that VM. How it gets there, that is up to the programmer. If the button is going to contain state data, that is bound from its dependency property in a two way fashion back to the item it is bound to.
By keeping VMs out of the buttons and only having one VM that is the best way to segregate and maintain the data. Unless I am really missing something here....
Same as others here I find it a bit hard to actually understand what you are asking, so this is quite general. The answer to the question header is simply: the Control gets the data from the ViewModel through bindings, always. You set the DataContext of your Control to the corresponding ViewModel, and from there you keep the ViewModel and the Control synchronized:
If you add an ItemsControl containing buttons to the View, you add an ObservableCollection<ButtonViewModel> to the ViewModel and bind the ItemsSource of the ItemsControl to this.
If you allow the user to dynamically add content to the View, the actual code that does it resides in the ViewModel, e.g. when the user clicks on a button "Add Button", you use the Command property to call a ViewModel method that adds a ButtonViewModel to the collection and the View will automatically reflect your changes.
There do exist complicated cases that are impossible to code exclusively in the ViewModel, I have found Behaviors to be the missing link there, but I'll get into that when you show me the specific case.
If you'd like to get a working example, please provide as much code as you can, with your exact expectations of what it should do.
I'm writing a custom control from scratch (using Graphics) that will represent a set of columns each of which will have a list of cells, a lot like a grid view except this will have some custom features.
I'm having a hard time trying to figure out how to manage all the data binding problem. I'd like this grid to have a DataSource property which would basically need to be a jagged array (2D) of some objects each of which would need to be bound to a cell in the control. I'm still not sure which properties each of these objects will have, and so far I'm only using text. What I've been trying to do is have my model implement this interface:
public interface IDiagramDataSource
{
IBindingList Columns { get; }
}
and then have each column implement this:
public interface IDiagramColumnDataSource : INotifyPropertyChanged
{
IBindingList Cells { get; }
}
But I'm still having a hard time figuring out the best way to keep all these objects synchronized to the corresponding objects in my grid. I'd love to be able to put all the binding mess in an independent class but not sure how to do this. For now I'll just repaint the whole thing whenever there is any change in the data source, but I'd like to eventually be able to identify which property in which cell or which cell in which column have changed so that I can update only the necessary items in my grid.
Is there any pattern to follow when you want a control to be bindable to nested lists? I'm guessing there is since the DataGridView control does this.
I would suggest 2 option:
First suggestion has been suggested by HighCore, is to using WPF rather than custom winform object to do the job. WPF also has much more controls (ListView, even the generic ItemContainer, if I am not mistaken). Just implement the INotifyPropertyChanged at the ViewModel, then call OnPropertyChanged for the root (aggregate) element everytime you need to refresh the control. Don't forget to add UpdateSourceTrigger for ItemsSource Binding. WPF controls also has good implementation for drag and drop function.
I won't detail the implementation in WPF since there are much articles explaining it.
However if you think that it must be done with custom graphic drawing, then it is quite complex. You must trigger the method to re-draw your control graphic everytime any changes occured in the item list for it to take effect. It will be better if you can do partial update to your graphic (maybe using panels to trick it), but it is harder.
If not handled correctly (moreover if your control contains huge amount of data and/or control size) then it can causes some high memory loads.
I'm working on a plug-in for a 3D modeling program to assist in architectural design. I have a Building class which needs to contain a collection of Floors.
My Floor class has properties such as Elevation, Height, ProgramType (residential, retail, etc), and ID. Each building has a FloorList property which is the collection of all the Floors contained by the Building. The properties of a Building are generally viewed through a property grid control and I was planning on using a custom UITypeEditor to allow the user to edit the FloorList collection.
I'm trying to figure out the best way to create this FloorList collection class so that creating the UITypeEditor is as easy as possible, and I can take advantage of any existing collection editing ability's in the .NET controls. For the editor I was thinking I'd use a DataGrid view to show all the floors in the collection something like the table below.
Height Elevation ProgramType ID
15' 70' Residential 23423
15' 55' Residential 42342
15' 40' Residential 98723
20' 20' Retail 23454
20' 0' Retail 98723
The user should be able to edit the height of the floor through the DataGrid, but the elevation of a floor would be derived from the sum of the floor heights below it. The program type should either be a text box or a drop down, and the ID is a read only value shown for information only.
The interface should also allow the user to edit the members of the collection such as adding one or more floors, removing one or more floors, or changing to order of the floors.
The DataGrid control has some built in functionality for allowing a user to add and delete rows, but is there built in functionality to allow a user to reorder the rows?
The only times I've ever used a DataGrid has been to show a DataTable. Is there a straight forward way to use a DataGrid control to allow a user to see and edit properties of objects in a collection? What about being able to add and remove objects from that collection by adding or removing rows from the DataGrid?
One caveat to this problem I have is I can't just edit the collection items directly, as changes to one item will affect another. For example if I remove a floor I'll need to move down (change the elevation of) any floors above the removed floor. Likewise if I increase the height of a floor I'll need to move any floors above the taller floor up. So any changes to the collection or items in the collection will need to be done through the collection itself rather then directly at the item.
So again I was thinking my FloorList collection would implement IEnumerable so that other methods could itterate over all the floors in a building. But any actual manipulation of the collection or objects in the collection would be done through Methods of the collection such as....
FloorList.AddFloor(Floor floorToAdd);
FloorList.RemoveFloor(Floor floorToRemove);
FloorList.MoveFloor(Floor floorToMove,int newPosition);
FloorList.ChangeFloorHeight(Floor floor);
etc..etc...etc..
Sorry for the long question, especially with out any sample code. But right now I don't really have any code written as I'm for once trying to plan out my work rather then jumping right into the code.
Update
I've been reading some examples and it looks like the DataGrid will show properties of objects in an IList. So now I'm thinking it makes more sense to implement a List, but set up the overridden methods to handle changing the floor elevations. If I'm ultimately going to be binding this list to a DataGrid control would it be better to base the FloorList collection of BindingList or IBindingList instead?
Update
I've done some more reading and decided to completely reword my question. The new version is here.
To answer your first question: In your business layer I would have Create, Add, Edit, Delete (and so on) methods that handle all your custom logic (just have it pass in your models to these methods). Then call those methods through the OnEditing, OnUpdating, etc. events from the DataGrid.
To answer your second question, BindingList will give you a built in OnChange event whereas the List will not. If this is being used in a Windows Form app, BindingList will come in handy. But using that event in a Web app can get kinda hairy. It depends on how you want to implement the updating logic in your business layer.