In the last days I studied MVVM and I downloaded a couple of samples.
The following article is very good and it included the source code:
Better User and Developer Experiences – From Windows Forms to WPF with MVVM
http://reedcopsey.com/series/windows-forms-to-mvvm/
When I first opened the project in Visual Studio 2013 all the fields and lists were empty like expected. The program is a RSS reader and I loaded one feed with lots of feed items which filled in all the fields in the form. But now even when I stopped the program I can see all the data in the design.
This is obviously very good because it makes it a lot easier to see and possibly amend the design.
I think what I saw is covered under the name Blendability – but I am not sure about this.
Now my question: Where does this Blendability come from? I looked at the source code of the project and I don’t find where the data comes from in design mode.
Over the last days I installed a couple of extensions in Visual Studio and maybe I installed something which causes this behaviour. Or maybe this is some special function in this example (which is not mentioned anywhere in the article).
If possible please let me know where this Blendability comes from and how I can implement it in my own projects.
Design time has a nifty feature where if you were to set the DataContext to a class, then that class will actually be instantiated at design-time.
It's quite probable that the DataContext of this particular window is a class with a constructor that executes the RSS reading code.
Take this for example:
public class MyRssReaderViewModel
{
public MyRssReaderViewModel()
{
//Read RSS and populate properties
LoadRSS();
}
public void LoadRSS()
{
...
}
...
}
Now if you were to set the DataContext like this:
<Window.DataContext>
<ViewModels:MyRssReaderViewModel/>
</Window.DataContex>
The designer will instantiate the class at design-time, and by extension call the LoadRSS method. Any elements that reference properties in your view model will update to display the bound data.
One important thing to note is that the class will be instantiated every time you build the project.
Related
I have been tasked to design a contact management program for my company. We have VS 2012 and since I have never used WPF before I thought I would use it to develop this application.
I am having huge problem getting started on the binding when utilizing the entity framework for the database which btw is database first.
I have followed the instructions within this link to the letter.
http://msdn.microsoft.com/en-us/data/jj574514.aspx
The objects show up in the data sources window just fine. But when I drag and drop to my window, nothing happens. No idea what I am doing wrong and cannot find anyone else with this problem.
Can anyone help me out here? I have looked everywhere. Any help is appreciated
Ok. I actually went thru that article, just to show good faith and let you know that I actually want to help you.
I came to the following conclusions:
That article show a very basic scenario of getting data from an Entity Framework context and showing it in a WPF DataGrid.
It doesn't have any kind of validation nor business rules.
It doesn't have any UI behavior such as conditionally enabling/disabling or showing/hiding any UI elements.
That kind of scenario is where the Designer is useful, when you don't actually need anything except getting / saving data from / to a DB.
Unfortunately (or fortunately for all of us developers who make a living of it), most applications will require some level of validation and business rules and some level of UI logic.
The designer is really useless when it comes to developing complex logic.
You can use the designer for such situations where you don't require complex logic, however I must warn you the following cons:
The Visual Studio WPF designer produces fixed-size, fixed-position UIs. these type of UIs don't work well when executed in computers with different screen resolutions and DPI settings. Just like winforms.
It also produces XAML that has many unnecessary things (such as x:Name="categoryIdColumn" and things like Margin="13,13,43,191" which are really bad from a maintainabilty / scalability point of view)
From what I've seen, the designer-generated XAML also contains a CollectionViewSource, this is both a good thing and a bad thing. It's a good thing because it enables Design-Time Data in the DataGrid, but it is also bad because it bloats your XAML with lots of unneeded things and introduces unnecessary <Window.Resources> that complicate things up.
Now, this is the very minimal XAML needed for that DataGrid, without Design-time data support:
<Window x:Class="MiscSamples.DesignTimeDataGrid"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="DesignTimeDataGrid">
<DataGrid ItemsSource="{Binding}" AutoGenerateColumns="False">
<DataGridTextColumn Header="Category Id" Binding="{Binding CategoryId}"/>
<DataGridTextColumn Header="Name" Binding="{Binding Name}"/>
</DataGrid>
</Window>
You see? It's actually faster to type that (much more so with the help of Intellisense) than what it takes for you to browse the property window and set these properties manually.
My suggestion is that you get familiar with XAML instead of insisting in the hard way to do things
Another very important aspect to keep in mind is that generally speaking, you don't put anything in code-behind in WPF because it's not needed, therefore that tutorial is actually going against the WPF Way of doing things, but that's Ok because it's actually an Entity Framework tutorial, not a WPF tutorial.
ease of development
You really need to reconsider what you call "ease of development". When it comes to UI development, I call "ease of development" to actually being able to do what I want with the UI without having to resort to shitty procedural code practices involving P/Invoke (whatever that means) and "owner draw" type of things for evertyhing.
WPF provides REAL ease of development as opposed to the fake ease of development exhibited by winforms
winforms lets you do everything with a designer (and this is just because the code the designer generates is actually so shitty that nobody would have ever used winforms if they didn't have the designer) but then when it comes to adding complex DataBinding or UI logic you're stuck with winforms' incapabilities forever.
WPF encourages manual XAML writing, not only because XAML is declarative (as opposed to the procedural winforms approach), but also because the levels of customizability and reusability are so high that a designer-centric approach does not make sense.
drag and drop is the easy way out
No it's not. It's actually the hard way. The easy way is to learn XAML and be able to do Things you can't even imagine to do with winforms.
If a designer-centric approach still makes sense to you, you may want to try Expression Blend
Automatically Create Data Grids from Your Models
Using a data source to drag and drop a template onto a WPF control is an excellent and fast way to get up and running!
Start by doing this: In your project create a folder named Models, then use either Entity Framework DB first or code by hand the models you want to show.
OR see discussion below on Object binding...
In that same folder create a dummy class that is a property for IEnumerable like this..
public IEnumerable<MyClassModel> MyCollection { get; set; }
From there go to the Main Visual Studio menu, to View/Other Windows/Data Source and click that link.
Click on Object and find the MyCollection property just created above.
Now open a user control or window in WPF but keep the datasources toolbox opened.
It should default to a DataGrid, but you can right click on the datasource and change it to detail, datagrid or select individual properties of the class it represents.
Simply drag that datasource onto the XAML's grid area. The right click on the new stuff you see and click reset to set the content to be the size of the entire window.
After having done this you will have code injected into the code behind of the view as follows in the window loaded event of that window, usercontrol etc.
// Do not load your data at design time.
if (!System.ComponentModel.DesignerProperties.GetIsInDesignMode(this))
{
//Load your data here and assign the result to the CollectionViewSource.
System.Windows.Data.CollectionViewSource myCollectionViewSource = (System.Windows.Data.CollectionViewSource)this.Resources["Resource Key for CollectionViewSource"];
myCollectionViewSource.Source = your data
// }
Go back to the XAML and look for the CollectionViewSource KEY property that was also inserted when you dragged the property to the XAML. It looks like this:
Use the Key name in the code behind, and then "Bind" the CVS to your data source which is an enumerable of type MyClassModel it can live in the View Model or in the code behind of the view as you choose.
If you only use the CollectionViewSource to as the datacontext of the grid you do not need to implement INPC for any underlying collections! The CVS updates the view automatically everytime the source is updated! Once you get good at this you can create working View prototypes of data in 2 minutes! Forget hand-coding XAML that just takes too long.
Object Binding
Create a static class with a static method that returns something like this:
When using the datasource wizard choose the "Object" selection.
Click Ok and you should see something like this:
You have just mapped all of the properties into the data source definition.
For anyone finding this issue in VS 2022: as per this is written, VS 2022 has this known bug unable to drag and drop data source to XAML form.
More info: https://developercommunity.visualstudio.com/t/drag-a-a-table-from-datasource-and-drop-in-a-windo/1660788
UPDATE:
It says that the fix has been released on 15th June. You can try updating your VS 2022 to the latest.
Background:
I'm using MEF to help compose an Excel 2007 Add-In (VSTO) that can create an entity from spreadsheet data and a creep requirement exposed a shortcoming in my architecture that I'm trying to reconcile(I am now needing to identify columns on "template load" rather than on "worksheet submit")
I have each of my local entity properties decorated with a DescriptionAttribute that contains the name of the column in my worksheet. On submit, I reflect on these attributes to identify which property maps to that worksheet column and create a Dictionary of pairs that map a PropertyName to a column ordinal. I do this because the Excel COM object model seems to only expose the cells of a worksheet based upon row/column ordinals. Performing this mapping allows my add-in to dynamically locate my properties on the worksheet without having to maintain any static property-to-ordinal map.
So, this was all fine and good...and, as this is a stopgap solution for our business partner while we rearchitect the underlying system, we discussed that this was going to be a very "unfriendly" add-in and everyone was intitially onboard. But now, the business has validation concerns for some reference data that will be showing up in the sheet. We had agreed that validation would be performed on submission, but that has changed to need me to have reference columns bound to validation drop downs that only contain valid values.
The Problem
So now, I've been needing to restructure my View and ViewModel such that the mapping of the columns to their entity properties occurs on loading of the View, and that's where the problems have started. I implemented Josh Smith's RelayCommand from code that he has made available, I implemented Reed Copsey Jr's CompositionInitializer for WPF, and I created a ViewModelLocator to assist my compositioncontainer in locating my ViewModel...but whatever I do, I cannot locate the appropriate ViewModel. I'm a bit strung out on this issue at the moment..spent all weekend trying to fix it, to no avail. Can anyone please help? I'm not a MEF expert. I've dabbled with the MVVM pattern, but I've been outside of C# for the past few years and missed much of its evolution. I think it's highly likely that my problem is fundamental, but I have been staring at my code for too long to find it. Please, help.
The Code
I have begun a post in the Microsoft social forum for WPF where I have already posted the relevant code. If anyone would like me to repost it here, I would be happy to oblige. But for now, I will include a link to that thread. (I included a background in that thread as well, but I'm happier with the one here. You can skip the background I included over there and not miss anything)
http://social.msdn.microsoft.com/Forums/en/wpf/thread/f22f081d-e342-4f4e-af41-600cec68f0cd
I am uncertain whether this will have any impact, but instead of exporting your StopgapViewModel class, create a factory class and export the factory class, like so:
public StopgapViewModelFactory
{
[Export(typeof(StopgapViewModel))]
public StopgapViewModel Instance
{
get
{
return new StopgapViewModel();
}
}
}
Remove the [Export] declaration from the StopgapViewModel class, and give it a go.
I've been reviewing the features of the RichTextBox control in Silverlight 4.
What I've yet to find is any examples of Loading and Saving content in the RichTextBox.
Anyone come across any or can shed some light on it?
The control has a BlocksCollection in which I guess one could use the XamlReader to load a bunch of markup assuming that markup has a single top level node of type Block. Then add that block to the Blocks collection. Seems a shame that the RichTextBox bothers to have a "collection" in this case, why not simply a top-level Block item?
Never-the-less that still leaves saving the content of a RichTextBox, I have no idea where to begin with that one?
I'm sure I must be missing the obvious here but unless loading and saving data in to and from RichTextBox is at least possible if not easy I can't see how we can actually put it to use.
Edit
Thanks to DaveB's answer I found discussion of something called the DocumentPersister. However no reference to this class can be found in the MSDN documentation nor can I find it in the installed dlls via object browser search. Anyone, anyone at all?
Check out this tutorial
on the RichTextArea control. Persisting content is described in exercise 2, task 3. The code for the tutorial includes a helper class.
Edit:
The question was raised about the DocumentPersister class referenced in the tutorial. It is found in the source code download for the tutorial. I think the author created it. By looking at the code you will get an idea as to persisting your data. The only downside was that if your data contained images, the helper class did not support them. Here is the link to the download.
http://ecn.channel9.msdn.com/o9/learn/Silverlight4/Labs/TextEditor/Source.zip
Just to update the link in the accepted answer, it's moved to here:
http://channel9.msdn.com/learn/courses/Silverlight4/NewFeatures/RichTextBox/Introduction/
Be wary of investing too much in the Silverlight 4 RichTextArea until it's confirmed that it will support full RichEdit functionality like bullet points/lists etc which it currently does in SL Beta 1... although I'm sure it will in RTM?
I have a sample from Microsoft to persist the contents which I have to find which I will do tomorrow. I got this sample in october when beta 4 was not even announces due to which there were no tutorials available. Since that project I have not worked on silverlight so I don't know how many tutorials are available now.
ok I have found it. Where should I upload it?
One option for loading text into RichTextBox is to use XamlReader. Dependent on the text which you are planning to load, you might need to add tag around it
public class TextToXamlConverter
{
private const String ParaHead = "<Paragraph xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\" xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\">";
private const String ParaTail = "</Paragraph>";
static public Paragraph Convert(string text)
{
String formattedText = ParaHead + text + ParaTail;
Paragraph p = (Paragraph)XamlReader.Load(formattedText);
return p;
}
}
Seriously, it seems like every time I want to make my UI elements talk to each other, I end up coding a new, custom, IValueConverter :(. Someone tell me that I'm doing it wrong, please!
Examples:
I wanted a button to be enabled only if my textbox contained a valid URI. Great, time to code up a UriIsValidConverter!
Oh oops, I also wanted to disable it while I'm processing something. I guess now I need to code up a UriIsValidAndBoolIsFalseMultiConverter!
I want to display a list of files in a certain directory (specified by a textbox) inside a listbox. I guess I need a DirectoryPathToFileList converter!
Oh hey, I want icons for each of those files in the listview. Time for a FileInfoToBitmap converter!
I want my status to be red if my status-string contains "Error", and green otherwise. Yay, I get to code up a StatusStringToSolidColorBrushConverter!
I'm really thinking this isn't that much better than the old Windows Forms method of just wiring up everything manually using TextChanged events (or whatever). Which I guess is still an option. Is that what people actually do, perhaps, and I'm trying too hard to make everything fit into the databinding paradigm?
So yeah, please tell me if this is really how WPF coding is---or if I'm doing it wrong, and if so, what I should be doing.
Your approach is perfectly valid (though I would use a multibinding for the second example, rather than a such a specialised converter), though by placing all your logic into the XAML you are producing very high coupling between the way the application looks and the way that it behaves, because of this you may want to look into the MVVM pattern to separate those things out.
Under the MVVM pattern your XAML (the view) just contains very simple data bindings into a ViewModel which handles all the logic and updates the view through the INotifyPropertyChanged interface. The code for your third example may look something like:
public class DirectoryManagerViewModel : INotifyPropertyChanged
{
private string _directory;
public string Directory
{
get { reutrn _directory; }
set
{
if (_directory != value)
{
_directory = value;
OnPropertyChanged("Directory");
if (IsValidDirectory(value))
{
PopulateFiles();
}
}
}
}
public ObservableCollection<FileViewModel> Files { get; private set; }
private bool IsValidDirectory(string directory)
{
//return if the directory exists etc.
}
private bool PopulateFiles()
{
//Populate Files with files in directory
}
}
Where FileViewModel is another view model which contains the name and the icon for a file.
The advantage of this approach is that the ViewModels can be reused with other views and other technologies such as ASP.NET or Winforms so you are not locked into the WPF stack. (alos if you work in an environment where there are designers responsible for the look and developers responsible for the behaviour, this helps define those boundaries)
At the end of the day though this logic does need to go somewhere and while there are better and worse ways to architect your application you are still going to be writing code that takes a string and converts it into a series of filenames and icons somewhere.
First, you might want to start by reading about the Model-View-ViewModel pattern (MVVM). Josh Smith had a fantastic article in MSDN Magazine recently. MVVM and WPF go perfectly together. Done right, you won't need IValueConverters so much. The way that you are going about it now is causing a very tight coupling between your visualization and your application actions. MVVM is designed to decouple these elements.
In this context, your view model will track state for you. Your button will be enabled if the CanExecute method on a certain ICommand in your view model returns true. This same concept can handle disabling the button when processing something.
You want to display a list of files in a certain directory that is specified inside a listbox? Have a DirectoryViewModel view model that will handle providing the list of files to the view by binding to the view model. The display of the files can be specified with a DataTemplate specified in XAML with no code behind. This same concept can handle providing the icons to the view whose display can be specified in the template.
You want your status to be red if a status message contains "Error" and green otherwise? Let a view model handle determining the state and let the view bind to that state and now you only need an IStateConverter to convert the state to red or green appropriately (this is one of many ways to handle this problem in the MVVM context).
Get in the habit of keep data and state separate from your view and your applications will be loosely coupled, easier to design and maintain, and easier to test.
Don't know if you are wrong, just making it a lot harder than it has to be!
I use MVVM, so where you are writing customer converters, I provide a bindable property on the view model that tells the view what to do. For example:
To display a list of files, I provide a collection that contains that list.
If I want icons the object in that collection has a icon property
If I want a status to be red or green I provide a StatusColorbrush property.
By moving this logic into the view model, I get:
much simpler Xaml.
can test my view logic without the view.
This approach uses one of the strong points of WPF, it's binding capabilities.
I have an MVVM application. In one of the ViewModels is the 'FindFilesCommand' which populates an ObservableCollection. I then implement a 'RemoveFilesCommand' in the same ViewModel. This command then brings up a window to get some more user input.
Where/what is the best way to do this whilst keeping with the MVVM paradigm? Somehow
doing:
new WhateverWindow( ).Show( )
in the ViewModel seems wrong.
Cheers,
Steve
I personally look at this scenario as one where the main window view model wants to surface a task for the end user to complete.
It should be responsible for creating the task, and initializing it. The view should be responsible for creating and showing the child window, and using the task as the newly instantiated window's view model.
The task can be canceled or committed. It raises a notification when it is completed.
The window uses the notification to close itself. The parent view model uses the notification to do additional work once the task has committed if there is followup work.
I believe this is as close to the natural/intuitive thing people do with their code-behind approach, but refactored to split the UI-independent concerns into a view model, without introducing additional conceptual overhead such as services etc.
I have an implementation of this for Silverlight. See http://www.nikhilk.net/ViewModel-Dialogs-Task-Pattern.aspx for more details... I'd love to hear comments/further suggestions on this.
In the Southridge realty example of Jaime Rodriguez and Karl Shifflet, they are creating the window in the viewmodel, more specifically in the execute part of a bound command:
protected void OnShowDetails ( object param )
{
// DetailsWindow window = new DetailsWindow();
ListingDetailsWindow window = new ListingDetailsWindow();
window.DataContext = new ListingDetailsViewModel ( param as Listing, this.CurrentProfile ) ;
ViewManager.Current.ShowWindow(window, true);
}
Here is the link:
http://blogs.msdn.com/jaimer/archive/2009/02/10/m-v-vm-training-day-sample-application-and-decks.aspx
I guess thats not of a big problem. After all, the Viewmodel acts as the 'glue' between the view and the business layer/data layer, so imho it's normal to be coupled to the View (UI)...
Onyx (http://www.codeplex.com/wpfonyx) will provide a fairly nice solution for this. As an example, look at the ICommonDialogProvider service, which can be used from a ViewModel like this:
ICommonFileDialogProvider provider = this.View.GetService<ICommonDialogProvider>();
IOpenFileDialog openDialog = provider.CreateOpenFileDialog();
// configure the IOpenFileDialog here... removed for brevity
openDialog.ShowDialog();
This is very similar to using the concrete OpenFileDialog, but is fully testable. The amount of decoupling you really need would be an implementation detail for you. For instance, in your case you may want a service that entirely hides the fact that you are using a dialog. Something along the lines of:
public interface IRemoveFiles
{
string[] GetFilesToRemove();
}
IRemoveFiles removeFiles = this.View.GetService<IRemoveFiles>();
string[] files = removeFiles.GetFilesToRemove();
You then have to ensure the View has an implementation for the IRemoveFiles service, for which there's several options available to you.
Onyx isn't ready for release yet, but the code is fully working and usable at the very least as a reference point. I hope to release stabilize the V1 interface very shortly, and will release as soon as we have decent documentation and samples.
I have run into this issue with MVVM as well. My first thought is to try to find a way to not use the dialog. Using WPF it is a lot easier to come up with a slicker way to do things than with a dialog.
When that is not possible, the best option seems to be to have the ViewModel call a Shared class to get the info from the user. The ViewModel should be completely unaware that a dialog is being shown.
So, as a simple example, if you needed the user to confirm a deletion, the ViewModel could call DialogHelper.ConfirmDeletion(), which would return a boolean of whether the user said yes or no. The actual showing of the dialog would be done in the Helper class.
For more advanced dialogs, returning lots of data, the helper method should return an object with all the info from the dialog in it.
I agree it is not the smoothest fit with the rest of MVVM, but I haven't found any better examples yet.
I'd have to say, Services are the way to go here.
The service interface provides a way of returning the data. Then the actual implementation of that service can show a dialog or whatever to get the information needed in the interface.
That way to test this you can mock the service interface in your tests, and the ViewModel is none the wiser. As far as the ViewModel is concerned, it asked a service for some information and it received what it needed.
What we are doing is somethng like that, what is described here:
http://www.codeproject.com/KB/WPF/DialogBehavior.aspx?msg=3439968#xx3439968xx
The ViewModel has a property that is called ConfirmDeletionViewModel. As soon as I set the Property the Behavior opens the dialog (modal or not) and uses the ConfirmDeletionViewModel. In addition I am passing a delegate that is executed when the user wants to close the dialog. This is basically a delegate that sets the ConfirmDeletionViewModel property to null.
For Dialogs of this sort. I define it as a nested class of the FindFilesCommand. If the basic dialog used among many commands I define it in a module accessible to those commands and have the command configure the dialog accordingly.
The command objects are enough to show how the dialog is interacting with the rest of the software. In my own software the Command objects reside in their own libraries so dialog are hidden from the rest of the system.
To do anything fancier is overkill in my opinion. In addition trying to keep it at the highest level often involving creating a lot of extra interfaces and registration methods. It is a lot of coding for little gain.
Like with any framework slavish devotion will lead you down some strange alleyways. You need to use judgment to see if there are other techniques to use when you get a bad code smell. Again in my opinion dialogs should be tightly bound and defined next to the command that use them. That way five years later I can come back to that section of the code and see everything that command is dealing with.
Again in the few instances that a dialog is useful to multiple commands I define it in a module common to all of them. However in my software maybe 1 out of 20 dialogs is like this. The main exception being the file open/save dialog. If a dialog is used by dozens of commands then I would go the full route of defining a interface, creating a form to implement that interface and registering that form.
If Localization for international use is important to your application you will need to make sure you account for that with this scheme as all the forms are not in one module.