I'd like to bind selected elements from a Grid to text boxes on a different page.
Can this be done?
If you mean completely separate pages, those screens only exist separately. When your "text box page" appears the previous "grid page" no longer exists. If it could be done my answer would be "Don't do it" as you would wind up with separate pages tightly bound to each other. That is considered a bad practice.
The latest Silverlight practices say that data should be shared via Models and View Models that live longer than the screens (lookup Silverlight MVVM patterns on Google). View Models are basically a place to move your code-behind to. The aim is to leave your XAML pages virtually code free.
Basically you want your screens to share common data. In this case that would include your current selection in a list of data items (you don't actually care if it was a grid that did the actual choosing).
The "grid screen" is bound to the data model to get its data source for the grid and also has its current selected item bound to an item in the data model. The same Model (or View Model) is bound to your "text box page" when it is created. The text boxes on that page are bound to the results previously stored in the data model.
One downside is that all bindable properties in data model/view Models have to be Dependancy Properties. If you do not make them bindable you get no error, just no data.
Related
I have a requirement to display a number of graph/chart "thumbnails". Clicking one will show an "expanded view" (in a separate panel) that displays a larger version of the chart, plus controls to view and manipulate the chart.
There will be a number of different charts, each plotting my data in different ways. Also, a given chart type may appear several times, each plotting a different subset of the data. The controls in the "expanded" view will also differ from one chart type to the next, so there is little commonality here.
I'm struggling to get my head around how to model all this in MVVM, especially given the need to dynamically create an unknown number of thumbnails (and in some cases multiple instances of the same type).
Thinking aloud, I guess I need a view/viewmodel that represents a single thumbnail (the view contains the chart component and the VM exposes the data to plot). I guess I also need a V/VM for the "thumbnail list" UI, responsible for creating the thumbnails and exposing them via a collection for binding to the list. But how does it instantiate these? A VM gets injected into its view, suggesting the "thumbnail list" VM would have to dynamically instantiate the thumbnail views - but a VM shouldn't have knowledge of views should it?!
Lastly, when I display the "expanded" view, it would make sense to (somehow) pass it the charting component/view that was used in the thumbnail, to avoid having to render the chart again, but how?
If it's relevant/helps, I'm using Castle Windsor for dependency injection, and the navigation features of Prism.
This is indeed a complex topic,...
I would suggest a VM for the list of icons not necessarily for the icon itself. this can be bound to properities of the IconListViewModels. Then you should think about a ChartViewModelFactory. Which works in conjunction with your DIC.
An important discussion is the VM-V marriage. View first or View Model first... one way could also be ViewResolver if which returns the matching view based on your view model... this can rely on some sort of conventions. So the final steps could be ask the factory for a view model find the matching view glue them together and bind them to a content presenter...
I hope this helps to get you started...
We have a list of items in a TreeView where users can select the item they want. Every item can be associated with another item. I have a button on my ItemEditor view that opens a new window with the associated item in read-only mode. The read-only copy of the item has no save functionality nor does it give any of the edits made by previous users. It does however share 90% of the fields, out of ~50.
Do I take the hit in almost duplicating the entire view and create a pure ReadOnlyItemViewModel? Or is it typically more acceptable to set flags in my view model to display which editable items are hidden?
You can map multiple views onto the same View Model. It's actually encouraged. You don't have to make a ReadOnlyItemViewModel...just make a View on top of the ItemViewModel. If you are trying to auto-generate the view, make whether it generates read-only or fully editable view a strategy of the generator. If you need more fine grain control consider adding attributes that express how a field should be displayed in Read-Only vs. Editable mode. Only after you've explored all those avenues should you consider splitting the VM into two.
I'm trying to build a data entry form in wpf. To perform validation I apparently need to have an object attached in the datacontext of my grid. But how can I have one when I didn't create one yet?
How does it work?
For example, I have a screen with a datagrid. The datagrid contains users that were obtained from membership. Above the grid is a button: add user. When clicked a new window appears and the following can be entered: user name, password, email. To perform validation on the textboxes to see if they aren't empty. Now, it is my understanding that the way this works is by having an object attached to the window (datagrid datacontext). But how can I have it attached when it doesn't exist yet?
This is a case where MVVM design patterns are very useful.
Every WPF view has a corresponding view model object that the properties in the view are bound to. So your window with the data grid has a view model - its DataContext - and the view model has properties that are bound to properties in the view - e.g. the ItemsSource in the data grid is bound to a collection (see note 1).
The "add user" command (which is implemented as a RelayCommand in the window's view model) creates a new view (the new window) and its corresponding view model object (the new user), sets the view's DataContext to the view model, and calls ShowDialog to show the window. (See note 2.) If the user accepts the new object, ShowDialog returns true, and the logic in the command takes the view model object (which now contains whatever changes the user made) and uses the information in it to create a new model object and add it to the model. If the user cancels, ShowDialog returns false, and the command discards the view model object without creating a new model object.
Note 1: The collection here may be a collection of model objects, or it may be a collection of view model objects. It depends on whether or not you need anything that's not in the model for displaying the model objects in a data grid. It's common, in this kind of scenario, for the objects in the grid to be view models for the dialog - that is, the view model objects have properties implemented for both display in the grid and modification in the dialog window. On the other hand, if all the grid is doing is displaying data from the model, there may be no need for an intermediary object.
Note 2: Having the command create a WPF window violates a central MVVM design principle, which is that view models shouldn't create WPF objects. The reason for this principle is pretty simple: you can't build an automated unit test for this command, since it's just going to throw up a dialog and wait. There are all kinds of different approaches to this - see, for instance, this question, and Josh Smith's blog post on the Mediator pattern - and all of them involve delegating the creation and display of the actual dialog window to a separate service that can be mocked out for unit testing. If you don't want to choose one of those approaches up front, you can retrofit one into your application once you get this thing working.
The idea here is that you should attach an object which is slightly different from your business models. In your case it won't UserInfo (or whatever you have for users in grid). It will be some other class, more suitable for editing. In MVVM this class will be a ViewModel. This class will have some differences comparing to your regular user class, for example it may have some properties nullable (when you haven't set them yet). Also this class will handle validation. You should instantiate this class at the same time you're creating an editor window and put instance of this class into Window.DataContext.
Hmm, there is a lot in this question but I just created a screen with three data grids (I am using Telerik in this case) and under each datagrid is a button to add to the grid. No the window with the three datagrids has it's own view model. and each of the "pop up's" has it's own viewmodel, in this case all of these are user controls and I just create a new window and set window.content and call show dialog.
Communication is facilitated via "events" - not the standard events you are used to in .NET but in this case I am using Prism and it's CompositePresentationEvent class. When the user is done creating their new object they click add and I fire off this event with the "payload" being the object they created. The main window with the three grids listens for that event and has a method to handle it, in this case adds it to the ObservableCollection which is what I bind the grids to.
If I were you I would look into the various frameworks that are out there, Prism, MVVM light etc... Again, your question seemed rather broad, I tried to give an overview but I didn't go into detail, if you look into some sort of framework I think it will clear up a lot of these details for you.
When the users hit Add New, create a new blank copy of your object, and set the datacontext to that new object.
Set some kind of flag to identify that it is a New object. This can be the Id being NULL, 0, -1, etc or an ObjectState property set to New. That way all your validation rules apply, and once the user hits save you know to INSERT instead of UPDATE
I'm not really sure how to do this in the best MVVM way...
Basically, my main app opens up a search window that shows all records in a TabPanel. Then if a record is double clicked a new tab is opened with that record. Now, I'm trying to keep things MVVM, but I can't for the life of me figure out how to close the gui tabitem when a person deletes the record (why keep it open if the record is gone).
The only way I can figure out how to do it now is to pass the instance of the TabItem as a parameter of the DeleteCommand, which to me seems like a big no-no, but I can't for the life of me figure out how to accomplish this.
If you were going to do this in the true MVVM sense, then double-clicking a record would, behind the scenes, add a record to a collection of records. That record collection is the datasource for the tabs in your control. Simply removing that item from the list (usually an ObservableCollection<T>) would result in the UI updating and the tab being removed.
Which approach are you currently using to show the tab?
Edit (in response to comment):
That is not "true" MVVM. It doesn't matter if the tabs can be more than just records. You should create View Models which abstract those details, then just put your view model instances (RecordViewModel, ReportViewModel, etc) in an observable collection and bind to that. Use datatemplates to render the correct views for each tab's content based on the type of view model the current tab is being bound to.
Josh Smith wrote an amazing article describing how MVVM works. The sample application does something very similar to what you want to do.
The application displays a TabControl which displays 1 or more workspaces. The workspace area displays two different kinds of items. The tab items are closable. Take a look, I'm sure this will solve your problem.
WPF Apps With The Model-View-ViewModel Design Pattern
I'm building a simple financial record-keeping application. The main window view model holds a list of Accounts. The view shows this list (in a ListView) along with a panel showing details about the currently selected Account.
At first, I bound the details panel and ListView's SelectedItem to the same property (of type Account) on the view model. However, I quickly realized that the details panel needed to be bound to an AccountViewModel, not directly to an instance of Account.
There are several ways to providing this AccountViewModel:
Bind the details panel to a separate property on the view model. When ListView's SelectedItem changes, the view model should create and set this new property to an instance of AccountViewModel that is associated with the selected Account.
Give the main view model a list of AccountViewModels instead of an Accounts list. Both the ListView listing all accounts and the details panel could then be bound to the same property on the main view model.
Have one AccountViewModel, changing the Account it references with each change to ListView's SelectedItem property.
Are there other options? Which choice do you recommend?
Thank you,
Ben
This is what I do:
Give the main view model a list of
AccountViewModels instead of an
Accounts list.
This will serve you well in many ways. I always find that eventually, for one reason or another, I need to augment my Models in some way to support a View, so these days I just start out by creating ViewModels.
The way you can tell that this is going to be a better option is that it involves less code. Less code always equals less bugs, in my opinion.
i like this option
Bind the details panel to a separate
property on the view model. When
ListView's SelectedItem changes, the
view model should create and set this
new property to an instance of
AccountViewModel that is associated
with the selected Account.
then you can bind the selected item to the view model and the details pane as well. this can be tested independently of the view. when you create your list of accounts you can also create a list of account view models, so when you change selection you are not having to create anything its all sitting there. this way your viewmodel is comprehensive, representing the whole screen not just floating bits of viewModel.
So far, the idea I like best is #3 from the original post for two reaons:
It has a 1 view to 1 view model correspondence, which I think best fits the M-V-VM pattern.
Since the account view model is told when to change to display details of a different account, it can ask the user if he wants unsaved edits to be saved before changing to display the new account (etc.).