Rules of MVVM??

UPDATE #2:

There is very active discussion about MVVM in WPF Disciples User Group. If you are interested then please read all posts and get invoked in discussion. Here is the link. Update: Here is another one.

As I had a MVVM session at my office, I was re-reading a few articles about MVVM. We have very interesting discussion about MVVM in WPF Disciples User Group as well. You can read that post from here.

Someone in Silverlight Forum (link) posted that ~

“There are currently three main areas of criticism regarding the MVVM pattern. The first is that MVVM currently lacks standardization from Microsoft both in implementation and in toolsets. For example, the community has some lack of clarity about where and whether to implement View logic in the View layer or the ViewModel. Given that the MVVM pattern is still relatively new, and that new tool-sets, walkthroughs, or patterns, such as Onyx, Prism, the Microsoft WPF Toolkit, Crack.net, Caliburn and MVVM Light Toolkit are being released, this problem may be solved over time. Microsoft has announced in discussion boards that the MVVM template pattern will be released in Visual Studio 2010.

The second comes from MVVM creator John Gossman himself, who points out that the overhead in implementing MVVM is “overkill” for simple UI operations. He also states that for larger applications, generalizing the View layer becomes more difficult. Moreover, he illustrates that data binding, if not managed well, can result in a considerable excess of metadata in an application. Given these limitations, MVVM may have a practical minimum and maximum size for the type of application it can support, suggesting it may not perform well with large enterprise applications.

The third is that the exercise in creating large numbers of data bindings to the ViewModel results in duplicate code and maintenance problems. Additionally, because of the nature of the semantics of data bindings, critics suggest that the ViewModel does not directly describe the View.”

So, I was thinking it would be great if John and our WPF/Silverlight community can define some simple and obvious rules for MVVM pattern.I understand that there are a lot of way to implement MVVM but at least, there are some obvious rules that everyone can follow so everyone has same understanding about that pattern.

Here are some of my thoughts about MVVM.

Why MVVM?

  • Testabiltiy ( ViewModel is easier to unit test than code-behind or event driven code)
  • Clear seperation between UX designer and developer
  • Increases the “Blendability” of your view
  • Model never needs to be changed to support changes to the view
  • ViewModel rarely needs to be changed to support changes to the view
  • No duplicated code to update views

Do and Don’t in View

  • shouldn’t contain any logic that you want to test : As Glenn said that MVVM is not code counting exercise, we can write code in code-behind. But you should never write any logic that you want to test. For example: If user select a country then you want to display the list of states or city in your view. This is the business requirement so you should have unit test to test this logic. So, you shouldn’t write it in code-behind.
  • can be a control or Data Template
  • Keep the view as simple as possible. : We can still use Data Trigger or Value Converter or Visual State or Blend Behivor in XAML with care.
  • use attached property if something is not bindable :

Do and Don’t in ViewModel

  • Connector between View and Model
  • Keep View State, Value Conversion : (You can create the data structure that you want to display in ViewModel instead of using ValueConverter. For example: You need to show the Name instead of First Name and Last name. Your Model can have First Name and Last Name but You can create Name property in ViewModel. )
  • No strong or weak (via Interface) reference of View
  • Make VM as testable as possible (e.g. no call to Singleton class)
  • No Control related Stuff in VM ( Because if you are changing the view then you will have to change VM as well. )

Model

  • can be Data Model, DTO, POCO, auto-generated proxy of domain class and UI Model based on how you want to have the separation between Domain Service and Presentation Layer
  • No reference to ViewModel

What do you think about that? Feel free to let me know if you have any comment or suggestion..  Thanks.

UPDATE:

This is the open post. I will keep on updating it based on the feedback. I’m trying to discuss about those rules in WPF Disciples User Group. I understand that there are a few people who don’t want to get invoked in this kinda discussion because it can turn into a fight. Anyway, I will try to discuss with people nicely. :) I will get the feedback several groups like SL MVP/Insiders group, Stackoverflow, Codeproject and etc.

My WPF MVVM Session at Consistel

I gave MVVM presentation at Consistel today. It was 2 hours long section and we had a lot of great discussions about MVVM pattern. Due to the problems with laptop and remote desktop, I was not able to show the demo in my session. I’m going to have another WPF session with my colleague “Nyi Nyi” tomorrow. Thanks to everyone who is attending my session. Especial special thank to Arpad and Maneesh for arranging this session and supporting me in my session.

Topics

  • Understanding MVVM
  • Motivation and benefits
  • Implementing the pattern
  • Dependency Injection and IoC
  • Unit Test and Mock
  • Supporting libraries and frameworks

Download ~

Demo ~

Here is the list of things that I used in

You can also download the demo here.  MVVMDemo.zip (5.34 MB) Note: Unity and Moq dlls are already included in zip file.

As I want to show the team how to write the test, I didn’t write anything for both View and Service. The test below are the BDD (Behavior-Driven Development) Style.  There are a few BDD framework for .NET but I don’t really like any of them so I’m using VS Unit Test with BDD-style test. The main difference between TDD and BDD is that BDD focus more on specification and readability. (Some people said that BDD is TDD done right. :) )

Feel free to let me know if you have any question or comment. Thanks.

Bindable WPF RichText Editor with XAML/HTML Convertor

Introduction

This post will give you some tips/tricks of using Rich Textbox in WPF. As we all know, the build-in WPF RichTexbox doesn’t provide some features that we are looking for so if you are in need of using RichTexbox in WPF project, you should know that you will need to roll your own implementation (at least) a bit. In this post, I will brief you how to make WPF RichTextbox bindable, how to display the HTML in WPF, how to create a Rich Textbox Editor with toolbar.

Contents

  • Bindable RichTextbox
  • RichText Editor
  • HTML to XAML Conversion

wpf-rich-text-editor

Source DownloadWpfRichText.Ex.zip (336 KB)

Dependencies ~

Bindable Rich Textbox

A lot of people asked how to bind RichTextbox on the net. Yes. IMO, the Rich Textbox should be bindable but I’m not sure why Document property of RichText is not a dependency property in WPF ( someone can ask me this question?) but people like us who are using MVVM pattern need to have a binding between RichTextbox and the property of ViewModel.  How are we going to make this happen?

Well,  we probably need to a custom property that can be bindable in that control so the first thing that come into my mind is the attached property. There maybe a lot of definitations for it but the way I understand is that it is a custom property that can be attached to control. For example: AA property to B Control or etc.

You can take a look at how Sam implemented the binding support for Passwordbox in his post. (Forget about encrypting the password in memory or etc for now. ) We will follow this approach to implement the binding support in RichTextbox as well.

The first thing that you might notice is that RichTextbox has the Document property. So, you can create an attached property by wrapping RichTextbox.Document property. Please take a look at siz‘s implementation as below (link: ref).


class RichTextboxAssistant : DependencyObject
{
public static readonly DependencyProperty DocumentProperty =
DependencyProperty.Register("Document",
typeof(FlowDocument),
typeof(RichTextboxAssistant),
new PropertyMetadata(new PropertyChangedCallback(DocumentChanged)));

private static void DocumentChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
Debug.WriteLine("Document has changed");
}

public FlowDocument Document
{
get { return GetValue(DocumentProperty) as FlowDocument; }
set { SetValue(DocumentProperty, value); }
}
}

But…… OMG! why it’s so hard to use FlowDocument? How come do we need to call Content.Start and End just to get the text? why not having a property called Text which is a string datatype?

Yes. it’s ture that using FlowDocument is not so simple compared to a string datatype. we also got the same feeling when we were implemneting this feature. what did we do? We decided to change Document property, a FlowDocument type, to “BoundDocument” which is a string datatype. So, the new code will be like that below. As you can see, it’s a bit complicated then before since we are handling all complex things there.


public static class RichTextboxAssistant
{

public static readonly DependencyProperty BoundDocument =
DependencyProperty.RegisterAttached("BoundDocument", typeof(string), typeof(RichTextboxAssistant),
new FrameworkPropertyMetadata(null,
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
OnBoundDocumentChanged));

private static void OnBoundDocumentChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{

RichTextBox box = d as RichTextBox;

if (box == null)
return;

RemoveEventHandler(box);

string newXAML = GetBoundDocument(d);

box.Document.Blocks.Clear();

if (!string.IsNullOrEmpty(newXAML))
{

using (MemoryStream xamlMemoryStream = new MemoryStream(Encoding.ASCII.GetBytes(newXAML)))
{

ParserContext parser = new ParserContext();
parser.XmlnsDictionary.Add("", "http://schemas.microsoft.com/winfx/2006/xaml/presentation");
parser.XmlnsDictionary.Add("x", "http://schemas.microsoft.com/winfx/2006/xaml");
FlowDocument doc = new FlowDocument();

Section section = XamlReader.Load(xamlMemoryStream, parser) as Section;
box.Document.Blocks.Add(section);
}

}

AttachEventHandler(box);

}

private static void RemoveEventHandler(RichTextBox box)
{

Binding binding = BindingOperations.GetBinding(box, BoundDocument);

if (binding != null)
{
if (binding.UpdateSourceTrigger == UpdateSourceTrigger.Default ||
binding.UpdateSourceTrigger == UpdateSourceTrigger.LostFocus)
{
box.LostFocus -= HandleLostFocus;
}
else
{
box.TextChanged -= HandleTextChanged;
}
}

}

private static void AttachEventHandler(RichTextBox box)
{

Binding binding = BindingOperations.GetBinding(box, BoundDocument);
if (binding != null)
{
if (binding.UpdateSourceTrigger == UpdateSourceTrigger.Default ||
binding.UpdateSourceTrigger == UpdateSourceTrigger.LostFocus)
{
box.LostFocus += HandleLostFocus;
}
else
{
box.TextChanged += HandleTextChanged;
}
}

}

private static void HandleLostFocus(object sender, RoutedEventArgs e)
{

RichTextBox box = sender as RichTextBox;
TextRange tr = new TextRange(box.Document.ContentStart, box.Document.ContentEnd);
using (MemoryStream ms = new MemoryStream())
{
tr.Save(ms, DataFormats.Xaml);
string xamlText = ASCIIEncoding.Default.GetString(ms.ToArray());
SetBoundDocument(box, xamlText);
}

}

private static void HandleTextChanged(object sender, RoutedEventArgs e)
{

// TODO: TextChanged is currently not working!
RichTextBox box = sender as RichTextBox;
TextRange tr = new TextRange(box.Document.ContentStart,
box.Document.ContentEnd);

using (MemoryStream ms = new MemoryStream())
{
tr.Save(ms, DataFormats.Xaml);
string xamlText = ASCIIEncoding.Default.GetString(ms.ToArray());
SetBoundDocument(box, xamlText);
}

}

public static string GetBoundDocument(DependencyObject dp)
{
return dp.GetValue(BoundDocument) as string;
}

public static void SetBoundDocument(DependencyObject dp, string value)
{
dp.SetValue(BoundDocument, value);
}

}

Yes. That’s it. You can now simply bind this attached property with a string instead of a flow document.


<RichTextBox  attached:RichTextboxAssistant.BoundDocument="{Binding Text}" Height="92" />

RichText Editor

After implementing the binding support for WPF RichTextbox, we got new requirement that we need to develop a RichText Editor (something like TinyMCE) as well. So, we quickly create a new user control called RichTextEditor.xaml and place a RichTextbox with our attached property. After a few minutes, we got a WPF RichText Editor as below. ( As there are a lot of code snippets already in this post, I’m not going to post it here. Please feel free to take a look at RichTextEditor.xaml in sample project. )

wpf-rich-text-editor1

HTML to XAML Conversion

Our manager was quite happy with our quick and cool solution for implementing WPF Rich Textbox so we checked-in the changes that we made to SVN. and then, the continous integration integrated our latest changes into the new build so people from QA can start testing on our new feature.

After a few hours, we started getting new bugs regarding to our new RichText Editor from QA. Ouch!

What happened was that there is one ASP.NET website that is using the same service and same table. The ASP.NET team is using TinyMCE, a Javascript WYSIWYG Editor in that website so those HTML tags which are the output of that editor are being saved in database. That’s why our WPF RichText Editor wasn’t able to render those HTML tags. The same way, their TinyMCE was also having problems with our XAML tags.

wysiwyg-javascript-editor

So, what should we do? Ha! I can tell that what’s in your mind now. Yes. a converter! What we need here is a converter that can convert HTML to XAML (vise-versa). Luckily, Microsoft provides a set of classes that can do the conversion for you. You can grab a copy of those classes from this link. (Thank you! MS). We embedded those classes in our application and changed our code as below to support the conversion.


public static string GetBoundDocument(DependencyObject dp)
{
var html = dp.GetValue(BoundDocument) as string;
var xaml = string.Empty;

if (!string.IsNullOrEmpty(html))
xaml = HtmlToXamlConverter.ConvertHtmlToXaml(html, false);

return xaml;
}

public static void SetBoundDocument(DependencyObject dp, string value)
{
var xaml = value;
var html = HtmlFromXamlConverter.ConvertXamlToHtml(xaml, false);
dp.SetValue(BoundDocument, html);
}

That’s is. I already attached all sourcecode in the zip file. Please feel free to download it and play as much as you like. But hey! don’t forget to give the feedback if you found something uncool!.

Here is how my sample looks like. Happy Wpf-ing!!! :)

wpf-super-cool-rich-text-editor