Silverlight: binding an observable collection to different usercontrols conditionally - silverlight

I'm new to Silverlight 4 and having a tough time googling this one since I'm not terribly familiar with the terminology involved. Can someone point me in the right direction?
I have an observable collection that I want to represent in an ItemsControl list. The type of the collection is a class that- for simplicity's sake- let's call PersonInfo. Each PersonInfo has a string property Name and an observable collection PhoneNumbers. Everything works fine when I tell the ItemsControl's DataTemplate to use "UserControl1" for visualizing the data- the bindings work.
My problem is that- for this theoretical example- I want to base the control used to display the PersonInfo on certain values in the Name propery. So I want to use UserControl1 for any entries named "Joe", and use UserControl2 for all others. I've found IValueConverter stuff, but that doesn't seem to help with selecting the control type used to visualize the data.
Sidenote: UserControl1 and UserControl2 show data in a similar way, but there are some differences within their complicated grid layouts that forced me to create 2 separate usercontrols. If anyone knows how I could build multiple layouts into UserControl1's xaml and then switch between them at runtime via a property binding, that would probably let me sidestep this issue altogether...
Can anyone recommend a general strategy for solving either side of this problem?
Thanks in advance!

I’ve solved a similar dilemma by using an IValueConverter in an unusual way: I created a "VisibilityConverter" that tells a control whether it ought to appear. In the case of your example you would have two of them: one Convert method would
return ((PersonInfo)o).Name == "Joe" ? Visibility.Visible : Visibility.Collapsed;
and the other would do the opposite. Then bind UserControl1's visibility to one VisibilityConverter and bind UserControl2's visibility to the other and violà, they swap out based on the data.

Related

ListBox on Canvas: overlay multiple canvases or use CompositeCollection?

In wpf with mvvm I use a ListBox with Canvas as ItemsPanelTemplate and DataTemplates to customize appearance.
I would like to improve performance by first adding all items of type 1 to the drawing, then all items of type 2.
I could create two ListBoxes both with Canvas as ItemsPanelTemplate and they would be overlays.
Panning and scrolling could be synchronized by means of bindings.
This way I can raise PropertyChanges for both lists independantly from each other.
Question: do you have experience whether overlaying canvases is good or bad for performance?
I an not sure whether this is also possible using a CompositeCollection for the ItemsSource of one ListBox. Or for that matter give both types a common subclass and stay with ObservableCollection.
Question: do you think that somehow a list with CompositeCollection can be given separate PropertyChanges for different parts of the Collection?
EDIT:
Suppose I have a great number of points, lines, labels for the canvas, each of a different type, however with a common base type. I select the DataTemplate using DataType: DataType="{x:Type my:Point}", DataType="{x:Type my:Line}" etc.
First as quicly as possible I want the user to see the lines. I raise PropertyChanged("Lines") and the ListBox+Canvas for the lines is visible.
In a backgroundworker I raise PropertyChanged("Points") and the ListBox2+Canvas2 for the points is visible.
When done in another backgroundworker I raise PropertyChanged("Labels") and the ListBox3+Canvas3 for the labels is visible.
There's a much simpler solution using basic Object Oriented Programming. Create a base data type and make all of your data objects extend from it. It could be empty, but if nothing else, you could implement INotifyPropertyChanged in it so you don't have to in each of the other data types.
Then you simply add a property of type ObservableCollection<BaseClass> to your view model or code behind and data bind that to the ListBox.ItemsSource property. As long as you don't set the x:Key values on the different DataTemplates, then WPF will implicitly set them to the relevant data type objects when it renders them.
So you can put all of your different data types in the same collection. Then you can add your first type in and wait for however long and add some of a different type, or whatever order you feel like.
UPDATE >>>
In response to the edit in your question, I don't quite understand the reason for you trying to use the INotifyPropertyChanged interface to show the items, type by type. If you have the base class collection that I mentioned above, then you simply add the instances of the first type to the collection first, so they'll appear first. When you want the next type to appear, just add them into the collection and then they'll appear and so on. The ObservableCollection will take care of that.

Custom property dependant on other properties

Advance apologies for the event-style explanation; there's a lot of factors that I feel all play a role of their own. WPF is not my native framework of choice, and it probably shows. :)
Old situation: I had a window with several controls. Depending on their selections, I used multibindings and a converter to determine whether certain controls needed to be shown that inform the user about the implications of their changes before they'd eventually confirm them by OK (or simply dismissed by using Cancel). This worked perfectly.
Problem: Too many controls as time went by, too much clutter.
Solution: Put stuff in different Pages so it becomes easier to browse for the user. In order to have changes-to-be persist as a user arbitrarily browses between the pages, I create these dynamically and put them in a cache (Dictionary<string, BasePage>, see below), from which they will be pulled as the user chooses them.
Consequence: I need to decouple the bindings to the notification controls as the different options are now on different pages.
Solution? I put a BasePage class in that exposes certain abstract read-only properties that define the various aspects that the window needs to know about in order to do its notifications. For example, a bool requiresReboot property defines whether the current state of things on that page requires a reboot to take (full) effect. A specific page implements the property based on its controls.
Problem: I do not know how to keep create a proper binding that properly gets updated as the pages are changed. I tried giving my notification controls a binding to the Dictionary<string, BasePage> with a converter that checks all pages and the relevant property.
Questions:
1) How do I create a proper property for this purpose? I presume I need a DependancyProperty as I did a fair bit of reading on MSDN, but I can't figure out how this fits together.
2) How do I make a link between my custom property so that it allows (multiple) control(s) on a page to change that property? Do I use INotifyPropertyChanged somehow? My old example bound against several CheckBox.IsChecked properties in XAML. I am trying to avoid putting tons of events (OnChange, etc) on the controls as the original code did not need it and I have been told it makes for a messy solution for as far WPF is concerned.
3) Finally, I suspect I may need to change my Dictionary<string, BasePage> class to a custom implementation that implements some sort of INotifyPropertyChanged but for Collections? Observable Collection is the term I am looking for, I believe.
I hope someone is able to bridge the gap in my understanding of WPF (property) internals; I would very much appreciate it. A basic sample would be even better, but if it is too complicated, just a nudge in the right direction will do. Thank you. :)
It's been a while since I solved this, and while I cannot remember the exact cause of the problems, there were a few different issues that made up the bulk of the trouble I ran into.
I ended up making the Property in question a non-abstract DependencyProperty in the base class; it was the only way in which I could properly delegate the change notifications to the interface. Derived classes simply ended up binding it to their controls (with a proper Converter in the case extra logic was necessitated).
As Dictionary<string, BasePage> does not support any sort of change notification, I made an extra collection of ObservableCollection<BasePage> which I used for binding purposes.
However, such a collection does not propagate a change event when items inside of it has a property changed. Since this situation required that, and I was binding to the collection itself in the context of a property that does not have a Master<->Detail relationship like a DataGrid (which basically add their own OnPropertyChanged handlers to the binded object), I ended up subclassing a VeryObservableCollecton<>. This one listens to its own items, and throws a proper change event (I think it was an OnPropertyChanged from the INotifyPropertyChanged interface) so that the binding (or in this case a multi-binding) would refresh properly and allow my interface to update.
It is hardly the prettiest code, and it feels over-engineered, but at least it allows me to properly bind the UI to the data in this manner.

WPF - how to bind to source in different page?

Could anyone answer a really frustrating newbie question please?! I've been hunting for an answer for a few days & have found answers to similar questions posed, but nothing that exactly solves my issue.
I'm trying to bind a textbox to the currently selected item in a listview (which itself is bound to an Observablecollection of objects, not sure if this matters).
The listview is in RecentEntities.xaml & the textbox is in Relationship.xaml, both of which are positioned on the Main Window from within Maincontrol.xaml. So they're in the same namespace but they're in different pages so using ElementName doesn't work as this just seems to look within the current page.
The issue I'm having is when trying to define the source of the textbox binding in Relationship.xaml, how do I reference the selected listview item in RecentEntities.xaml? I wondered about using RelativeSource, but this seems to only let you navigate up the tree to an ancestor of the current control. Because of how MainControl is set up, I would need to travel up to the parent of the textbox, then to a sibling of the parent then down to a child of a child of it in order to get to the listview!
I've explored (possibly not in enough depth) other options like resources, data context, including header files and have read something about Merged Resource Dictionaries but to be honest the more possibilities I explore, the more confused I'm getting about what I need to be doing.
Is this really as complicated as it seems?! Any pointers or help would be brilliant, thanks for taking the time to answer :) I haven't posted on here before, so if you need any code snippets please let me know.
Can you create a ViewModel that both Views will use? Have the selected item in your listview bind to a property in the ViewModel and have the textbox bind to the same property. As long as both views reference the same instance of the viewmodel, it should work.
With two XAML files you will have to use the model or viewmodel (depending on your choice of architecture) for synchronization.
For the listview you can use the SelectedValue to bind to a property, use Mode=OneWayToSource for this binding since you just want to update the property, not change the selection in the listview itself.

How much coupling is appropriate between ViewModels in MVVM

I'm developing a fairly simple WPF application to display an object hierarchy plus detail of the selected object, with a UserControl wrapping a TreeView in the left pane (the tree control), and another UserControl wrapping a ListView/GridView on the right (the details control).
The tree control uses MVVM following this Josh Smith article reasonably closely, and has a number of ViewModel types all derived from the same base type, TreeViewModel. The main window is set up using a MainWindowViewModel as in this Josh Smith article and exposes the TreeViewModel used to populate the first generation of the tree control.
However, when I want to populate the details pane on the right, I have the problem that the SelectedItem of the tree control is derived from TreeViewModel when I need a completely different type of ViewModel for the details pane which will expand the object into a table of properties/values using reflection.
So, questions:
Is it appropriate for the MainWindowViewModel to expose the TreeViewModel for the tree control? I believe that the answer here is yes, but am open to suggestions to the contrary.
How should the selected item in the tree control be adapted to the right ViewModel type for the details pane? One option seems to be that the MainWindowViewModel tracks the selected item in the tree and does the adaption, exposing it as another property, but I'm not sure if there is a better solution.
I'm new to WPF and the MVVM pattern, so please excuse the fairly basic nature of the question. I've done a fair bit of reading around the background of the pattern, looked at some sample apps etc. but I can't quite find anything specific enough to make me confident of the answer. I also realise that MVVM may be overkill for an app this simple, but I'm using it partly as a learning exercise.
1.Is it appropriate for the MainWindowViewModel to expose the
TreeViewModel for the tree control?
I belive yes. The model should hide the look from teh logic FOR THE LOOK, but it can not hide thigns like logical structure.
2.How should the selected item in the tree control be adapted to the right
ViewModel type for the details pane?
One option seems to be that the
MainWindowViewModel tracks the
selected item in the tree and does the
adaption, exposing it as another
property, but I'm not sure if there is
a better solution.
IMHO not.
Working on the similar problem I came to the conclusion that
object Tag { get; set; }
property is inevitable :( except maybe for some rare situations (only 1 type of objects in the entire treeview).
However, when I want to populate the details pane on the right, I have the problem that the SelectedItem of the tree control is derived from TreeViewModel when I need a completely different type of ViewModel for the details pane which will expand the object into a table of properties/values using reflection.
If you're really, really concerned about this, you can build a higher-order view model class that exposes two different properties - one of type TreeViewModel and one of type DetailsViewModel. Then the main window's view model will expose the same object to both the tree control and the details control, but the logical structure of the two view types will be decoupled from one another.
Logically, the selected item in the tree control and the item that's appearing in the details control are the same thing. While the details control doesn't present information about the thing's parent/child relationships, and the tree control doesn't present information about the thing's name/value pairs, it's still the same thing. There's probably not really any need to be too concerned over the fact that a single object representing a thing exposes a property that only one view of that thing uses.

wpf - viewmodel with two bindable collections. Use datacontext of one collection to filter the other one

Long title, hope it makes sense. Can't seem to figure out how I would implement this. Or if my approach is even somewhat on track with best practices for this kinda stuff b/c i'm still working on mvvm and probably not using it correctly yet.
I have a simple viewmodel in an application i'm working on and it contains two properties which point to datamodel collections.
public ChuteGroupsModel Groups { get; set; }
public WaveStatusModel Waves { get; set; }
Each one of these datamodels contains all the data I need for a tabpage in my tabcontrol of my MainWindow. One tabpage is a grid of statistic data and the other page is a custom user control that visualizes a physical "working" area.
I decided today that I would like to display some of the statistic values from the grid (# of items, # remaining, etc) inside of the tooltips of my custom user controls. My two collections are only connected by an ID# field.
So, basically I need to figure out a way to filter/bind to my "Waves" collection according to the ID# property of the current element that is bound to "Groups".
The obvious easy answer here is to modify my sql view to include the additional fields which would make them immediately available for me to bind to in my application.
Since all of the data I wish to visualize already exists, I can't help but feel that changes to sql are a bit unnecessary and that some easy solution exists to help me gather these values out of my other collection.
Can anyone provide any suggestions of what I could attempt to do? If my question does not make sense I can try to re-state it with more code snippets and hopefully that will help.
Perhaps some more information about your ViewModel / View binding would be helpful. As given, if your ViewModel exposes properties of both Groups and Waves to your View, and the View containing the TabControl is bound to your ViewModel, I see no reason why controls on either TabPage couldn't be bound to properties sourced from either data model.
To put it another way, the ViewModel can abstract away the separate data-model collections from the View, building, for example, its own collection of objects which expose the properties of both a ChuteGroup and its associated WaveStatus. The View can then be bound to that collection, and access the properties of both objects.

Resources