I'm new to Silverlight and I'm having trouble understanding how to properly navigate between pages, especially when I need to pass data around.
Classic example: I have a list of People on one page, and when I click on a person in the datagrid I'd like to go to the details page and load that data. I need to pass the PersonId. More importantly, I need to know how to do this from the ViewModel.
It's easy to fire a command from the datagrid that is on the ViewModel, and the SelectedItem on the viewmodel is also bound and thus tracked, but then what? How do I get to the next page? I can't for the life of me figure this one out. This seems like it should be really easy, but so far it's been anything but easy.
The most basic thing to do would be to change what Application.Current.RootVisual is set to and set the appropriate DataContext. However it is much better to have some wrappers that set this up properly for you. For example in your custom view that you are navigating to you can have the view's constructor handle some of that logic for you in a nicer way. If you are using Prism then you are ultimately talking about modifying the shell, or a container within the shell.
In the SelectedItemChanged you could set a ViewModel property "SelectedItem" with the object that you need in the other page. You ViewModel would need to be a Singleton. In the other page, you need to have the DataContext set to the ViewModel and now you can bind the SelectedItem to the control that you want.
The only thing that I do not like is that you still would need to go to the code behind of the starting page, get the SelectedItem from the DataGrid and set the ViewModel with this value.
Related
I have an app with MVVM which works fine. Now I want to replace one of my controls with a dynamic control. By dynamic I mean that I have no idea what control this is, only that it is a GUI control. It could be something as simple as a image, or a custom third party user control that will be created by someone else after this app is done.
Can someone shed some light on how this can be achieved in MVVM? I've done it before a long time ago using ListBox or similar (iirc) to generate GUI elements (don't remember details). But I'd like to learn the theory behind it this time.
Edit:
Lets say the View contains a list of instances of for example System.Windows.UIElement. I want to display all of these UI controls on a surface (for instance in a stacked control).
You could create a View that exposes a Content property as a placeholder (so a ContentControl might be all that is needed) The content property could then be set to the dynamic control.
You would have to add a little reflection to dynamically load the assembly and instantiate the required control.
The dynamically loaded control would have to access the data by using the DataContext property. If the dynamic control is MVVM too it might have its own ViewModel so you would have to find a way to load that too (reflexction again?) and point the DataContext of the control to the loaded ViewModel.
Does this make sense, is this what you are looking for?
I am using LinqToSql as my datasource, let’s say I query a list of programmers from a table and then loop through that data populating an ObservableCollection. (First question, is this part wrong? It just seems weird to query data into a list and then loop through it to populate another list)
Next, when I databind my ObservableCollection of programmers to a ListBox. Then I bind the selectedItem of the Listbox to a TextBox. I understand that when I select an item in the ListBox the textbox will be updated and when I make a change in the textbox, the ListBox will get updated and as a result the ObservableCollection that the listbox is bound to will also be updated.
What I don’t completely understand is what the best practice is to get the data from the OC back into my original datasource. Do I just loop through the observable collection commiting my changes by updating each record? That doesn’t seem terribly efficient.
Thanks so much for your help!
-Josh
This is purely a view-model issue. You have complete control over all the objects and properties on the data side of the fence. Sometimes you have a simple arrangement where the user can only edit a single record, databinding does all the work, and you just write it back to the database when the user clicks save.
If you have a lot more data being displayed and any one piece of it can be modified by the user, then it is probably wise for you to keep a dirty flag in the object itself that records whether any of the properties have been changed. That way, you can efficiently save back just the modified entries.
Since your objects probably support INotifyPropertyChanged and your collections are observable, you can even automatically detect and manage the dirty flag. Or it might be simpler to just set dirty to true in all of your setters.
In any case, this information can even be useful to the user. For example, a user-interface can show unsaved records in bold or with some other convention.
The ObservableCollection is not the only one collection which you could use in wpf. But it is standard collection allows wpf to automatically update ui item containers like ListBox on collection changes like addition or removal of an item. You can't do it with List.
When the user modifies a textbox in ListBoxItem the ObservableCollection is not updated cause you don't add or remove or reorder items in the collection. You change the property in one of the items.
The ListBox contains a list of ListBoxItem containers, one for each item in collection specified as an ItemsSource.
The DataContext of each ListBoxItem is set to the corresponding item stored in ObservableCollection. So, if you change the text in TextBox in code, the binding engine will change the property of that item specified for TextBox.Text in binding. Nothing to change or update for the ObservableCollection object.
In the setter of such item's property the PropertChanged event of INotifyPropertyChanged interface are usually raised. That is also the usual the place to set up a dirty flag. Then you could also commit changes immediately from there, keep some list of dirty objects or search for them on commit like:
items.Where(item => item.IsDirty)
Also there are good tools like Snoop and WPFInspector, which greatly help you to understand the wpf app visual tree and datacontexts for each element
I am trying to hook up an ICommand on the model to a button within the ItemTemplate of a Pivot control.
To get a link to the parent model from within the ItemTemplate I usually use ElementName specifying the Name I provided for the xaml page.
This works when I use a ListBox to contain the items but not a pivot control.
Does any one have any ideas or come across this problem before?
Just noticed that if I define the PivotItems in xaml the Binding works. So it is only failing when I am dynamically populating the Pivot control.
UPDATE : OK So I'm beat with this now. I have linked the event to the models ICommand in the views code behind (nasty) and I'm going to look # this later. I will post my solution here once I have found it but any help would be great.
This is a know problem in Silverlight 3. Since, WP7 uses it right now, you will face the same thing with it as well.
To fix that, wrap your DataTemplate content that you put in your ItemTemplate into a UserControl.
Look into this question for further details.
WP7: Why does a ListBox.ItemsPanel break my ElementName data binding?
I'm using the DevExpress GridControl with a context menu. Their context menu implementation uses their bars control which creates a lose reference from a row in the grid to a group of reusable bars. What this means is the context menu items don't have the same context as the grid (sparing details).
I can bind the command (ala ICommand) property of the bar to a command I've creaed on my view model. The challenge is I can't get my syntax to work just right. The VM is set to the DataContext of the view, but something like this isn't workign (where the view's x:name is "VideoModulePage):
Command="{Binding Path=DataContext.ViewVideoCommand, ElementName=VideoModulePage}"
When I create this databinding expression in Blend/VS2010, it makes me thing this is valid, but the command isn't being fired. The CanExecute always returns true. Is this syntax valid? Any tips on a better approach to this? I think what I really need is the new SL5 databinding debugging now! :(
Here's a post I put in the DevExpress forum, but I don't think my issue is with their control, rather with my databinding syntax: http://community.devexpress.com/forums/t/96068.aspx
In particular I would like to know how to bind the 'SelectionChanged' event of the dataGrid to a Command on my Viewmodel.
Since DataGrid doesnt have a Command property, how do I call a modelView command as in MVVM fashion? I dont mind using a delegate on the code behind XAML, if I knew how to do that...
Since I am new to WPF I am very stuck on how to accomplish this. May someone please help me with this?
Kind Regards,
Kave
Thanks Cameron. I had discovered it first too, but I prefer not using 3rd Party libraries at this stage.
After many many hours, I have found this link that helped me solving the problem in a different way.
In fact, there is no need for a DataGrid to use commands because its not really executing an action such as a button. The 'SelectionChanged' event can be easily made talking to the modelview by exposing a "selectedItem" property in the modelView and bind it to the Datagrid's selectedItem. The following example does it with a combobox instead of a datagrid, but its exactly the same concept. However I recommend using the CollectionView instead and making sure to feed the datagrid with a ObservableCollection<> and not with a e.g. DataTable.
What is the easiest way to handle SelectedItem event with MVVM?