OK, once again, my Google-Fu isn't up to par and I would really appreciate a little guidance here.
I have a WPF app with multiple pages, one of which contains a TabControl, of which one of the tabs contains a grid, in which one of the columns contains a StackPanel with just two items on it: a Label and a TreeView. I have no need to update the TreeView once the content is obtained. The app uses MVVMLight (great toolkit!) to expose the data and said data is exposed in an mvvm (observable) property as it should be. I have checked and the data itself is available in correct form once I get to the point of setting the ItemsSource property so I know it's not the lack of data or the structure of the data itself. I have looked at all the entries on the web (at least the first 4 pages worth) matching the search terms "wpf treeview dictionary" and all articles come close, but don't get me to where I need to be. I'm missing something and what's worse, IntelliSense is even "helping" by providing the correct values for the xaml settings. So I know I'm close, but after two days of frustration, I'm throwing in the towel and asking for an assist.
So...to the meat of the problem: The data that the TreeView needs to display is in the form of SortedDictionary<string, List<ServerEntityNameMsSqlSvr>>. A ServerEntityNameMsSqlSvr class contains multiple properties, one of which is FullName. What I want the TreeView to display is the dictionary Key as the parent node and the FullName from each of the items in the List<ServerEntityNameMsSqlSvr>. You'd think that'd be simple, no? Not for me, the closest I can get is to display the Key of the dictionary, but either nothing for the children (best case) or throw an exception that stops the app with a null exception (worst case).
Here is the xaml I'm using (worst case):
<TreeView Grid.Column="0" ItemsSource="{Binding TableHierarchy}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Path=Value}">
<TextBlock Text="{Binding Path=Key}"/>
<HierarchicalDataTemplate.ItemTemplate>
<DataTemplate DataType="awe:ServerEntityNameMsSqlSvr">
<TextBlock Text="{Binding FullName}"/>
</DataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
"TableHierarchy" is the MVVM property that exposes the data, it is declared as SortedDictionary<string, List<ServerEntityNameMsSqlSvr>>. The DataType "awe:ServerEntityNameMsSqlSvr" is a simple class with a few methods and properties, nothing special. One layer of inheritance, no interfaces. Of the properties that are available, I want to expose just the FullName, which is declared as public string FullName => _FullName(); Yep, it calls an overloaded method to build the full name but the result is a simple string (and the method call happens when the data is built, not a display time, iow, the values are already there, at least debugging to the setter shows that the content is correct.
Some of the solutions that I have researched suggest that the data type be changed to something other than a dictionary. In this case, that's not possible and given that the lists are, on occasion, quite large, I don't want to rebuild it into something else. This needs to work with the sorted dictionary as declared.
The xaml shown above is indeed correct, however, the gadget that supports the data (the methods in the ServerEntityNameMsSqlServer class) all need to not throw exceptions under any circumstances. In this case, one of the methods not directly involved with the author's code but used somewhere else in the framework (an overloaded call to "Equals" that was constructed to check individual property equality to determine the result) was throwing a null exception because a property wasn't filled in for the particular use case.
Difficult to find, but that was the cause.
I am new to MVMM Light toolkit (note, I'm using Light on .NET 3.5). So far I am really starting to like the pattern save for two challenges.
I'd like to have reusable XAML templates for certain types of pages in my application. Think of a movie ticket kiosk. Main content in the center but almost always a button somewhere on the screen to cancel or go back. I'd like to have reusable grid(s) where when I create a new page I basically import that grid layout and don't have to worry about the common bits and can just focus on my part. Doing a little research I feel like <ContentPresenter> might be the way to go here but it's still foreign to me.
Assumign I succeed in my first challenge, I would think the data context for those common items (say a Cancel button) would be somewhere else other than that page's ViewModel to avoid a bunch of duplication of code. Is that best approach to take the individual controls and reference a different view model from the XAML? Something like...
<Button ... DataContext={Binding CommonStuffVM, Source={StaticResource Locator}} />
You can use Templates or DataTemplates to create a reusable template defining how an object should look.
For example,
<DataTemplate DataType="{x:Type local:MovieTicket}">
<!-- Write the XAML for your Movie Ticket -->
</DataTemplate>
You can give your DataTemplate an x:Key to reference it specifically in an ItemTemplate or ContentTemplate, or leave it out so it will be used anytime WPF tries to draw a MovieTicket object
<ItemsControl ItemsSource="{Binding MovieTickets}" />
<ContentControl Content="{Binding SelectedMovieTicket}" />
For your second question, I think this would be a bad idea for individual controls, although its a common practice for complete sections of the program.
When using MVVM, your ViewModels are your application, not your UI.
If your window should display a list of Movies for the user to edit, and allow the user to Save or Cancel their changes, then your ViewModel should contain an ObservableCollection<Movie> and contain an ICommand SaveCommand and ICommand CancelCommand
You really want your View to only reflect your ViewModels, and not have them pulling the data they need from all over the ViewModel hierarchy.
Based on your question, you may be interested in a blog article I have about Navigation with MVVM which uses code very similar to what you're asking about. It shows how to change the UI using implicit DataTemplates, and contains a complete code sample that you can download and look at to get a better idea of the MVVM architecture.
I'm still getting comfortable with WPF, so this might be a silly question. I'm tracking the source of a tab control issue and discovered that I don't know the answer to the question in the title.
My Mvvm-Lite project template put the usual in the Windows opening tag:
DataContext="{Binding Source={StaticResource Locator}, Path=Main}"
And from somewhere else (I really don't remember) I have this handy static resource:
<ObjectDataProvider x:Key="src" ObjectType="vm:MainViewModel" />
While I'm troubleshooting my tab control issue (I won't bore you with those details here) I realized that I didn't know if these two ways of pointing to the view model confilicted in any way. Two separate instances of the view model? I don't think so cause the ViewModelLocator is holding a static reference to Main. Anyway, I just wanted to be sure that I haven't made a "greenie" mistake.
Thanks,
Jim
I am pretty sure that this is going to create two different instances. You can easily verify this by placing a breakpoint in the MainViewModel constructor and running your application in debug mode.
ObjectDataProvider was introduced before MVVM was popular. I would argue that many objects in WPF are kind of obsoleted by MVVM, because now we create these objects and properties in code in the ViewModel layer. In your case, I guess that you probably don't need the ObjectDataProvider, but can use the ViewModelLocator.Main everywhere instead.
Cheers,
Laurent
I was looking for best approach to set data context property. I found three ways
Assign data context on View (either on XAML or code behind).
Assign data context on ViewModel through constructor.
Use some configuration that takes view and view model reference and bind data context on run time through some infrastructure classes.
Which is the best option among this in terms of loosely coupled, maintainable? Or Is there any best approach?
I personally like this approach because it makes me have to write less code :). It basically uses an IValueConverter to lookup which view to use whenever a wpf control needs to present a ViewModel visually and the IValueConverter sets the datacontext for you. It also shows you how to create a datatemplate that allows you to require WPF to utilize this converter by default, something like this:
<DataTemplate DataType="{x:Type ViewModels:ViewModelBase}">
<ContentControl Content="{Binding Converter={StaticResource MyConverter}}"/>
</DataTemplate>
the 4. way would be a DataTemplate.
i think the best approach is the one which fits best in your current situation.
if i have viewmodel first dynamic scenarios i use datatemplate/contentpresenter or with view first i take your way one and so on...
I want to know why we should use MVVM to implement Silverlight app. What're it's advantages?
We don't do Unit Test for ViewModel, so I want other reasons.
Below are my questions about some advantages people usually say:
1.Loosely Coupled : When we use MVVM , a view rely on ViewModel but not a view, why it's loosely coupled?
2.If I provide public methods in a code-behind, they can also provide reusability.
Well, the unit-testability of the view-model is a significant advantage, so you'll miss out on that benefit. Regarding the other two:
Loosely coupled
Yes, the view does rely on the view-model. They have to be connected in some way to accomplish the function of the application. As a result, they cannot be uncoupled. The only choices are tightly-coupled or loosely-coupled or somewhere in between. With MVVM your view-model interacts with your view in a very limited way: basically just objects, properties and commands. Compare this to doing everything in the code-behind where the view and its control are essentially inseparable.
Re-use
If any code in your code-behind is re-usable enough to merit being public, it can be taken out of the code-behind and put into a general-purpose class. The problem is that what's left after that is not reusable.
If you don't want to go into the MVVM deep dive, then you can get some of the benefits of MVVM by focusing on databinding. After you learn the benefits of databinding, you can reconsider the other benefits of MVVM.
We don't do Unit Test for ViewModel,
With MVVM, it isn't just about unit testing ViewModel. Ideally, your VM should be very thin and only have properties needed by view. So, it isn't really necessary to test the VM.
But, without a VM, how do you do your your feature/functional testing across layers? In Silverlight, to facilitate testing you should use commands, instead of writing code in code-behind files. This allows you to simulate button click and other GUI events while unit testing. Using MVVM pattern along with commands, you can test all of C# code (not xaml), right up to UI (Converter, VMs, etc).
If I provide public methods in a
code-behind, they can also provide
reusability.
Not going into details of how that is a bad design, I want to ask you, How does that provide reusablity? If you create a user control, then the code-behind class is a control? You want to create instances of your control and use them? This is like saying that why do we need member methods, we can just create public static methods and access them. I have a strong opinion that if we don't want to use the automatic binding provided by WPF/Silverlight, then it is better NOT to use these technologies. And to exploit the full capabilities of binding, MVVM is essential.
why it's loosely coupled?
VM is very much part of your view. It is not decoupled from the view. As I have said, your VM should be as thin as possible with only public properties needed by your view. Your business logic will be decoupled from your view (and VM).
I think this is one of the best resources available, in case you want to use and contrast the usage of MVVM vs. ANY other pattern or no pattern.
http://karlshifflett.wordpress.com/2010/11/07/in-the-box-ndash-mvvm-training/
I can answer how I use MVVM pattern.
MVVM is better in the following scenarios:
1 If several controls are bound with a single property.
MVVM:
<TextBlock x:Name="text1" Visibility="{Binding IsSomePropertyTrue, Converter={StaticResource VisibilityConverter}"/>
<TextBlock x:Name="text2" Visibility="{Binding IsSomePropertyTrue, Converter={StaticResource VisibilityConverter}"/>
I can quickly add a similar control or remove an existing control.
Compare with code-behind:
public string IsSomePropertyTrue
{
set
{
//...
text1.Visibility = value;
text2.Visibility = value;
}
}
2 Instead of a multi-converter
public Brush StateColor
{
get
{
if (this.State == State.Edited && this.IsPriority)
return new SolidColorBrush(Color.FromArgb(255, 0, 255, 0));
//...
}
}
<sdk:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Background="{Binding StateColor}" Text="{Binding State}"/>
</DataTemplate>
</sdk:DataGridTemplateColumn.CellTemplate>
3 As an item model in controls like ListBox or DataGrid. For example, if I want to create a list of items with a remove button near each item, I will create a ItemView control and a ItemViewModel class.
<ItemsControl ItemsSource="{Binding SomeItems}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<view:ItemView DataContext="{Binding}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
4 Copying a data from one view to another:
public JournalEntryViewModel(SalesOrderViewModel vm) {}
5 ViewModel can inherit CLR-classes and implement interfaces (INotifyPropertyChanged or INotifyDataErrorInfo).
Also I use MVVM for replacing events with commands or properties. And use of ViewModels forces to call properties by intelligible names.
I was an early adopter for WPF and I can tell you what made me choose MVVM (and this more or less applies to Silverlight as well). For the project I was working on, I had to create a screen that allowed users to subscribe to notifications within the system. This was a 3 step process:
The user had to search for the item they wanted to be notified about
They had to select the item and fill out additional options regarding the subscription
The system had to provide a summary and allow the user to confirm or edit the subscription.
After implementing the functionality the first time (without MVVM), I was told that we need to exclude from the search items that were already subscribed to by the user.
After making that fix, I was informed that we needed to give the user a live preview of the subscription based on options.
By then I started noticing that some of these changes could be extracted and made easier if I didn't have to deal with manipulating the UI as I changed the logic. I had never intentionally followed MVVM but I realized that the abstraction that I made closely matched the MVVM pattern.
So this is why I recommend the pattern. It simplifies the task of changing the logic that drives the UI by separating it from the UI itself. I also would recommend that you hold off implementing it until you need it. There is a cost to using MVVM but it is amortized over the cost of changing the UI logic.
Without MVVM, your Silverlight app code very soon will turn into unmanageable mess
What is also interesting in MVVM is dynamic automatic binding.
Imagine, that your view model has properties like this: bool IsFirstNameVisible, bool IsFirstNameEnabled, string FirstName, double FirstNameWidth etc.
In your XAML file, you define TextBox with x:Name = "FirstName" and call your dynamic MVVM-binder. It inspects your view model class via reflection, looks what properties you have defined and binds them dynamically to similar properties of control with the same name, applying value converters if needed.
In this case, your get very clean XAML, without kilometer-long data-binding expressions and converters.
That is what my MVVM library does.
Separation of Conerns people. Separation of Concerns.
Forget unit testing (I love it; but that's not the thing here). Forget reusability (do you really re-use view models? No, let's be real here).
It's about Separation of Concerns and putting code and logic where it belongs. The whole idea is maintainability; being able to make changes to the code as it evolves over time without breaking other stuff and without turning the whole thing into a big pile of spaghetti.
MVVM, done properly, allows your code to be separated into logical portions that make sense and allow for reasy refactoring and change as the app's requirements change. It's easier to find where something is when you need to make a change. Trying writing any halfway complex application and then leaving it alone for a month, then coming back to it and trying to make significant changes. A properly structured application with judicious use of MVVM is way easier to grok after a layoff, and it's way easier to make changes.