An Early Look at Silverlight Model-View-ViewModel Toolkit 1

Introduction

This post is just an early look of upcoming Silverlight Model-View-ViewModel Toolkit. I know that this is very early state but I’m writing about this here because I would like to get the feedbacks from the community so that I can prioritize the plans based on what the community want. If you are a fan of WPF MVVM Toolkit then you will probably like it.

Silverlight MVVM Toolkit

Download : SilverlightModelViewApplication.zip (15 KB)

Features

The toolkit includes:

  • A Visual Studio 2008 Project Template
  • Silverlight Command Implementation
  • ViewModelBase that implements INotifyPropertyChanged interface

What is Silverlight MVVM Toolkit?

Silverlight MVVM Toolkit is a Visual Studio project template that has some useful pre-written implementations for Silverlight Command and INotifyPropertyChanged interface. The main intention of creating this toolkit is to help developers to develop the MVVM pattern-based Silverlight application quickly.

I’ve been using this template since a few weeks ago and I found it quite useful because whenever I need to create some samples for my blog or the POC projects for my Office, I always need to create a ViewModal class that implements INotifyPropertyChanged interface and need to add the Prism V2 assembly as a reference in my sample for using DelegateCommand. When I look at WPF MVVM toolkit, I really like it because it saves a lot of my times for copying and pasting the old code from my old sample to new sample. After using WPF MVVM toolkit, I was thinking why not create a project template for Silverlight as well. and now, I did it.

The project template is already attached in this post so you can download and test it in your machine. The msi file for that template is not ready yet but I will show you very simple steps (just two steps only) to make it visible in Project Template Dialog of Visual Studio 2008.

How to install Silverlight Model-View-ViewModel Toolkit

Please download the zip file (Don’t extract it) and close all Visual Studio 2008 instances before following the steps below ~

Step #1: Copy and paste SilverlightModelViewApplication.zip under this path below

%ProgramFiles%\Microsoft Visual Studio 9.0\
Common7\IDE\ProjectTemplates\CSharp\Silverlight\1033

    VS Project Template

Step #2. Open Visual Studio 2008 Command Prompt and type “deven /setup”

commandline

Yes. That’s all for installing new project template for Visual Studio.

Once you have finished registering new project template, you open the Visual Studio 2008 and check “New Project” dialog.  Then, you will get new project template “Silverlight Model View Application” under Silverlight project type as shown in picture below.

Silverlight MVVM Template in VS

Choose that template to create a Silverlight MVVM appliction. Note that linking with ASP.NET project, enabling the RIA service and generating unit-test project are not availble in this template but I will add all of this later.

The structure of Silverlight MVVM project is as below.

Silverlight MVVM Folder Structure

Commends

Let’s talk about classes under Commands.  The Command implementation that I’m using in this toolkit is from CompositeWPF version 2. I know that I can probably roll my own implementation but I’ve been using Prism for long time and DelegateCommand is working perfectly fine so I dont think that I need to waste my time to do the duplicated things. Please feel free to let me know if you found something that is not supported by DelegateCommand.

Here is the examples for using DelegateCommand.

XAML


xmlns:cmd="clr-namespace:SilverlightModelViewApplication4.Commands"

Here is how you can use Command Binding and CommandParameter in Silverlight.  ( The earlier implementation of Prism v2 is cmd.Command.Click but Prism team re-named this to Click.Command at drop 9.  You can read this post if you like to know why they did the changes)


<Button
cmd:Click.Command="{Binding SearchCommand}"
cmd:Click.CommandParameter="This is a CommandParameter"
/>

</div>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 2503px; width: 1px; height: 1px; overflow-x: hidden; overflow-y: hidden;"><Button</div>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 2503px; width: 1px; height: 1px; overflow-x: hidden; overflow-y: hidden;">cmd:Click.Command="{Binding SearchCommand}"</div>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 2503px; width: 1px; height: 1px; overflow-x: hidden; overflow-y: hidden;">cmd:Click.CommandParameter="This is a CommandParameter"</div>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 2503px; width: 1px; height: 1px; overflow-x: hidden; overflow-y: hidden;">/></div>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 2503px; width: 1px; height: 1px; overflow-x: hidden; overflow-y: hidden;">

C#


public DelegateCommand<string> SearchCommand { get; set; }

//Construtor
public MainPageViewModel()
{

SearchCommand = new DelegateCommand<string>((arg) =>
{
MessageBox.Show(arg);
});

}

INotifyPropertyChanged implementation

Some of you might know that I wrote about how to implement INotifyPropertyChanged interface with Expression Tree so you don’t need to use any magic string in property setter.  If you haven’t read it yet, please go and read this post to get some idea. I implemented the same implementation in ViewModelBase class of this toolkit so you can probably use this feature as below in ViewModel class.


//Example: How to use RaisePropertyChanged without having any magic string.

private string name = string.Empty;

public string Name
{
get { return name; }
set {
name = value;
this.RaisePropertyChanged(p => p.Name);
}
}

Upcoming Features ~

  • A Project Template Waziard for linking with ASP.NET, enabling RIA Services and generating a Text project that has the references o Silverlight Unit Test Framework and Silverlight Moq
  • A C# and VB.NET project template that supports all editions (inlcuding express edition) of Visual Studio 2008
  • Creating a msi installer by using Windows Installer XML (WiX) toolset

Questions?

I have a few questions for you guys.

  1. What kind of functionalities do you guys like to see in this toolkit? For example: Extensions/Attached properties, Utilities and etc
  2. Do you think that I should create an installer (msi) for that? OR is it okay to have zip file and register it by youself with two simple steps? I’m asking you this because in order to create a msi, I will probably need to spend some times for learning Windows Installer XML (WiX) toolset. So, if you guys are okay with two simple steps, I can work on other things first.

Feel free to drop a comment if you have any comment or suggestion for this toolkit. If you already have similar things in your mind, please let me know. We can work together to contribute our community. You can also reach me with this email mchlsync AT gmail DOT com.

I will be hosting this project in codeplex.com once it’s ready.

Silverlight Attached Properties: Binding.UpdateSourceTrigger.PropertyChanged

Note: It is one of my answers from Silverlight Forum.

Problems

UpdateSourceTrigger is not supported in Silverlight until version 3.o.

Workaround

You will need to set the focus on other controls and re-focus to the control that you are using. For example: You are typing in TextBoxA. You want to have UpdateSourceTrigger support for that textbox. So, what you have to do is that you need to change the focus on another control (e.g. TextboxB) and re-set the focus on TextboxA while typing.

Yes. you can do it very easily from code-behind. But ( genius? ) people from pattern world don’t like the idea of using code-behind file (so, creating a code-behind file for each and every xaml in Visual Stuid is a waste? What about changing the default pattern (MVC) to MVVM in Visual Stuido Template? ) Anyway, let me get back to the topic. So, we can probably create an attached property to workaround the UpdateSourceTrigger in Silverlight.

Note: This code is just giving you some idea how you can workaround the issue. You will need to do the modification based on your need.

Let’s name our attached property aS “UpdateSourceTriggerHelper”. We will add some codes for registering the property and getter/setter as below. I will tell you more about OnUpdateSourceTriggerChanged


public class UpdateSourceTriggerHelper
{
public static readonly DependencyProperty UpdateSourceTriggerProperty =
DependencyProperty.RegisterAttached("UpdateSourceTrigger", typeof(bool), typeof(UpdateSourceTriggerHelper),
new PropertyMetadata(OnUpdateSourceTriggerChanged));

public static bool GetUpdateSourceTrigger(DependencyObject d)
{
return (bool)d.GetValue(UpdateSourceTriggerProperty);
}

public static void SetUpdateSourceTrigger(DependencyObject d, bool value)
{
d.SetValue(UpdateSourceTriggerProperty, value);
}

In OnUpdateSourceTriggerChanged method, we are going to add the logic for focusing other controls and re-setting the focus back to the original control. So, we need to walk throught the Visual Tree to get the object of other control. Please take a look at findFocusableControl();


private static void OnUpdateSourceTriggerChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
TextBox textBox = d as TextBox;
if ((bool)e.OldValue)
{
textBox.TextChanged -= (s, arg) => {

};
}
if ((bool)e.NewValue)
{
textBox.TextChanged += (s, arg) => {
var c = findFocusableControl(textBox);
if (c != null)
{
c.Focus();
}
textBox.Focus();
};
}
}

Let’s take a look at what we did in findFocusableControl(). Based on the control that you are typing, you can get the parent of control by using VisualTreeHelper. But if you want to use this code in production, you will have to modify the code. (For example: if you can’t find any parent then you will need to find the child element. and you need to check whether that control that you get from Visual Tree Helper is focusable or not. yes. there are a lot of things to do it.)


private static Control findFocusableControl(Control control)
{
var ctl = VisualTreeHelper.GetParent(control);
if ((ctl as Control) != null)
{
return ctl as Control;
}
else
{
int childrenCount = VisualTreeHelper.GetChildrenCount(ctl);
for (int i = 0; i < childrenCount; i++)
{
var c = VisualTreeHelper.GetChild(ctl, i) as Control;
if ((c != null) &amp;amp;amp;amp;amp;amp;amp;&amp;amp;amp;amp;amp;amp;amp; (c != control))
{
return c;
}
}
}
return null;
}
}

Here is how we can use our attached property to provide PropertyChanged event.

Usage (Example)


<UserControl x:Class="UpdateSourceTriggerExtDemo.Page"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:UpdateSourceTriggerExtDemo"
Width="400" Height="300">
<Grid x:Name="LayoutRoot" Background="White">
<StackPanel>
<TextBox x:Name="nameTextbox" Height="25" Width="100" Margin="5" Text="{Binding Name, Mode=TwoWay}"
local:UpdateSourceTriggerHelper.UpdateSourceTrigger="True" />
<TextBox x:Name="addressTextbox" Height="25" Width="100" Margin="5" Text="{Binding Address, Mode=TwoWay}"
local:UpdateSourceTriggerHelper.UpdateSourceTrigger="False" />
<TextBox x:Name="phoneTextbox" Height="25" Width="100" Margin="5" Text="{Binding Phone, Mode=TwoWay}"
/>
<Button Height="25" Width="100" Margin="5" Content="Save" />
</StackPanel>
</Grid>
</UserControl>

Hope it helps. Feel free to let me know if you have any better solution.. I’m always open to any suggestion from you guys. Thanks..

Happy Silverlighting!!!

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

Things that make me disappointed these days

1. Windows 7 on Sony VAIO – VGN-C25G/B

I love technology. I love the most latest things when it comes to technology. This is what I am. I can’t control myself not to install Windows 7 on my machine as soon as it’s up on MSDN subscription downloads. then, CRASH!!  I don’t want to repeat how disappointed I am at that time. Some of my friends from Twitter know about that. I asked about that in Windows 7 Forum.

ACPI.sys Address 88ET3481 BASE AT 88EP4000 DATESTAMP 49E9766

Env:

Previous OS : Vista Home Premium
Laptop : Sony VAIO – VGN-C25G/B E1
Memory : 2 GB
Processor : Core 2 Dual

viao

2. Firefox says “Using Internet Explorer is So 2006″ :(

Using Internet Explorer is So 2006? what the f**k! why did they mention “Internet Explorer”?? Why did they use other competitor’s name there? I’m not a Microsoft fanboy or anything. I will say the same thing if they use Opera or Google Chrome or any other browser. Insulting other by name is not cool. It seems like people from Firefox are proud of themself or something.

Yes. It was the day that I stopped using Firefox. I’ve been using it since long time back but I won’t use it anymore. I will miss Firefox and I will definitely miss Firebug but it’s over. I’m currently using Google Chrome until I found the browser that I like. Good Bye, Firefox!

shameless-firefox-ads