Oct
8
Written by:
Michael Washington
10/8/2011 9:39 AM
It is important to know that you should only use the methods described here as a last resort. The methods described here should not be your first choice for implementing a custom Silverlight Control in LightSwitch. 99% of the time these other methods will work:
Videos:
- Part One - Creating and Binding a Silverlight Control in LightSwitch
- Part Two - The 3 methods of integrating a Silverlight Control in LightSwitch
The Problem
The Silverlight RichTextBox is notorious for being difficult to use with MVVM (LightSwitch uses MVVM). The problem is, that unlike most controls, it does not implement a Dependency Property to bind to.
Practically any control you run across will have a Dependency Property for you to bind to. Even when you make your own Silverlight control and put it in LightSwitch, you will usually have a control like a TextBox that has a Dependency Property for you to bind to. So to make this clear, we only need to go through the steps outlined below when we encounter the odd control that does not have a Dependency Property for you to easily bind to, or it has resources in the App.xaml.
The LightSwitch Application
To test out the RichTextBox, we create a simple table called Document.
We clear the Maximum Length property for the DocumentText field to allow unlimited text.
The XAML text created by RichTextBox is very verbose and requires a lot of room.
We make a simple List and Details screen that allows us to enter text.
The Silverlight Text Editor Sample
The first step is to download the Silverlight Text Editor Sample. The sample contains a Rich Text Box, but also implements a toolbar and other features such as copy and paste, and printing.
We unzip the project and add it as an Existing Project.
We point to the SilverlightTextEditor.csproj file.
The project will show up in the Solution Explorer.
We also add references to:
- Microsoft.LightSwitch
- Microsoft.LightSwitch.Base.Client
- Microsoft.LightSwitch.Client
Insert Control Into LightSwitch
On the LightSwitch screen, we select the Document Text Box and change it to a Custom Control.
In the Properties we click Change.
We click the Add Reference Button.
We create a Project reference to the SilverlightTextEditor project.
We will now be able to select the Custom Control.
We Click OK.
If we try to run the project at this point, the screen will just freeze up. We need to program the binding to make the control work, but the reason the screen is freezing up is that there are resources that the control is looking for in the app.xaml that it cannot get to.
Fixing Resource Issues
Currently the control is set to load “resources” such as templates and styling, from the app.xaml file.
The problem is, that when the control is running in LightSwitch, the app.xaml cannot load. We need to remove the references.
There are various methods to do this, however, the easiest is to use Microsoft Expression Blend.
We open MainPage.xaml in Expression Blend.
We delete al the resources in App.xaml.
If any resources are to be broken, we Reset to default values.
We also take this time to remove any buttons (and their associated code behind) that insert objects into the Rich Text Box. We would need additional code to actually save these objects to the database, and that is out of the scope of this article.
Code To Update The Rich Text Box
Normally we would bind LightSwitch to the control, and we would be done. However, the Rich Text Box does not expose a dependency property. We now have to alter the code behind of the control to manually update the control from LightSwitch, and to update LightSwitch when there are changes in the control.
First we create a DependancyProperty that will notify the control when LightSwitch is trying to bind to it. The main purpose for this is that we can wire-up an event, contentItem_PropertyChanged that will be raised whenever the LightSwitch property that the control is bound to changes.
This is the contentItem_PropertyChanged method that will get the value from LightSwitch and update the Rich Text Box:
private void contentItem_PropertyChanged(object sender,
System.ComponentModel.PropertyChangedEventArgs e)
{
// Get the DataContext
IContentItem contentItem = (IContentItem)sender;
// Make sure the contentItem is not null
if (contentItem.Value != null)
{
// Make sure we do not already have the value set
// from rtb_ContentChanged to prevent endless looping
if (contentItem.StringValue != rtb.Xaml)
{
// Check to see if the contentItem is an empty string
if (contentItem.StringValue != "")
{
// Set the value on the RichTextControl
rtb.Xaml = contentItem.StringValue;
xamlTb.Text = contentItem.StringValue;
}
else
{
// The RichText Control will throw an error
// if you attempt to set it to an empty string
// Create and set the minimal default text
StringBuilder SB = new StringBuilder();
SB.Append("<Section xml:space='preserve' HasTrailingParagraphBreakOnPaste='False' ");
SB.Append("xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'>");
SB.Append("<Paragraph FontSize='20' FontFamily='Calibri' Foreground='#FF000000' ");
SB.Append("FontWeight='Normal' FontStyle='Normal' FontStretch='Normal' ");
SB.Append("TextAlignment='Left'><Run Text='' /></Paragraph></Section>");
rtb.Xaml = SB.ToString();
}
}
}
}
The Rich Text Box also has an event that is raised when text changes. This is the method that will fire and update LightSwitch:
private void rtb_ContentChanged(object sender, ContentChangedEventArgs e)
{
// Get the DataContext
IContentItem contentItem = (IContentItem)this.DataContext;
// Make sure we do not already have the value set
// from contentItem_PropertyChanged to prevent endless looping
if (contentItem.StringValue != rtb.Xaml)
{
// Set the value of the RichTextControl
// to the value in LightSwitch
contentItem.Value = rtb.Xaml;
}
}
We also override the code for the Add Button on the LightSwitch screen with code that will properly create a blank document:
partial void DocumentListAddAndEditNew_Execute()
{
// The RichText Control will throw an error
// if you attempt to set it to an empty string
// Create and set the minimal default text
StringBuilder SB = new StringBuilder();
SB.Append("<Section xml:space='preserve' HasTrailingParagraphBreakOnPaste='False' ");
SB.Append("xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'>");
SB.Append("<Paragraph FontSize='20' FontFamily='Calibri' Foreground='#FF000000' ");
SB.Append("FontWeight='Normal' FontStyle='Normal' FontStretch='Normal' ");
SB.Append("TextAlignment='Left'><Run Text='' /></Paragraph></Section>");
var NewDocument = Documents.AddNew();
NewDocument.DocumentTitle = "New Document";
NewDocument.DocumentText = SB.ToString();
}
(the program running with the Metro Theme)
Special Thanks
A special thanks to Sheel Shah and Karol Zadora-Przylecki for their assistance.
Download Code
The LightSwitch project is available at http://lightswitchhelpwebsite.com/Downloads.aspx
28 comment(s) so far...
Thanks for another awesome tutorial Michael.
PS : The code runs without referring Microsoft.LightSwitch.Base.Client.
By Bala on
10/8/2011 12:10 PM
|
@Bala - Thanks for pointing that out. I just automatically add those references :)
By Michael Washington on
10/8/2011 12:15 PM
|
Follow up from prior post referencing build error: 'FontStyle' is an ambigouous reference between 'System.Windows.FontStyle' and Microsoft.LightSwitch.Presentation.FontStyle'
The error is MainPage.xamal.cs in the btnItalic_Click event.
private void btnItalic_Click(object sender, RoutedEventArgs e) { if (rtb != null && rtb.Selection.Text.Length > 0) { if (rtb.Selection.GetPropertyValue(Run.FontStyleProperty) is FontStyle && ((FontStyle)rtb.Selection.GetPropertyValue(Run.FontStyleProperty)) == FontStyles.Normal) rtb.Selection.ApplyPropertyValue(Run.FontStyleProperty, FontStyles.Italic); else rtb.Selection.ApplyPropertyValue(Run.FontStyleProperty, FontStyles.Normal); } ReturnFocus(); }
with the two "FontStyle' references in the statement if (rtb.Selection.GetPropertyValue(Run.FontStyleProperty) is FontStyle && ((FontStyle) . . .
I have both these using statements in the .cs file using System.Text; using Microsoft.LightSwitch.Presentation;
Commenting out either of them obviously throws many other errors.
Would appreciate some advice as to how to resolve this. Thank you very much.
Ken
By Kenneth James on
10/10/2011 10:23 AM
|
@Kenneth James - Open up References in the SilverlightTextEditor project and see if you have Yellow triangles on the three LightSwitch assemblies. If you do then that is the problem. Fix the references by locating them on your machine. My code is pointing to the default locations but you may have installed LightSwitch in another directory.
By Michael Washington on
10/10/2011 10:31 AM
|
Just a note that on a 64 bit OS, the LS assemblies are loaded into: C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\LightSwitch\1.0\Client\
By Garth Henderson on
10/27/2011 7:19 PM
|
@Garth Henderson - Thank you Garth that is very helpful.
By Michael Washington on
10/27/2011 7:26 PM
|
Many thanks for posting this tutorial!
In trying the demo code, I see that the SilverLight RichTextBox neither accepts styled text pasted from the clipboard nor copies styled text to the clipboard, making the control of limited practical use. Is there a LightSwitch-compatible rich text control that does support styled text to/from the clipboard?
By Keith Gillette on
11/9/2011 5:41 PM
|
@Keith Gillette - see: http://lightswitchhelpwebsite.com/Blog/tabid/61/EntryId/48/Using-the-Telerik-Rich-Text-Editor-In-Visual-Studio-LightSwitch.aspx
By Michael Washington on
11/9/2011 8:23 PM
|
Michael, I downloaded MS expression Blend 2, SP1 and installed it. I right click on mainpage.xml and select open with Expression Blend just like the tutorial above mentions. I get an error saying Invalid XAML and a bunch of erros in the results pane. for example, richtextbox is not supported in a Silveright project line 20, column 38 and so on.
I also have silverlight 4 & 5 SDK, I can build the silverlighttexteditor fine under VS2010. Is there something else I am missing in order for MS Expression Blend to work?
Thanks
By dbdmora on
3/22/2012 11:48 AM
|
nevermind Michael, I had to get the latest Blend 4, thanks
By dbdmora on
3/22/2012 11:48 AM
|
is it possible to save rich text into database ? Thanks
By werner on
5/4/2012 5:49 AM
|
@werner - Yes this example does that.
By Michael Washington on
5/4/2012 5:49 AM
|
function rtb_ContentChanged is never called. Do you know where could be a problem ?
By werner on
5/4/2012 6:31 AM
|
I got it. I should create event in InitializeComponent() this.rtb.ContentChanged += new ContentChangedEventHandler(rtb_ContentChanged);
Thanks !
By werner on
5/4/2012 6:31 AM
|
Hi, Michael I've tried running the sample on VS2012 RC, upgrading thhe project to SL5 and changing the references to the new LS dlls. When I run it I get:
No matching constructor found on type 'SilverlightTextEditor.Strings'. [Line:17 Position:30]
There were 3 warnings during build of which:
Message 2 The type 'local:Strings' was not found. Verify that you are not missing an assembly reference and that all referenced assemblies have been built. C:\code\RichTextBox\SilverlightTextEditor\SilverlightTextEditor\SilverlightTextEditor\MainPage.xaml 17 10 SilverlightTextEditor
seems related. Can you help?
By emtopping on
7/28/2012 4:24 AM
|
@emtopping - This project was created using Silverlight 4. You should be able to run it without upgrading it. Unfortunately I wont have time to update the code to Silverlight 5.
By Michael Washington on
7/28/2012 5:13 AM
|
Ok, I'll try it as sl4. Sorry about the double post.
By emtopping on
7/28/2012 6:36 AM
|
Well it looks like I can't target SL4 if I include the reference to LightSwitch from VS 2012 RC as that requires SL% (not surprisingly) Warning 3 The primary reference "Microsoft.LightSwitch" could not be resolved because it has an indirect dependency on the .NET Framework assembly "mscorlib, Version=5.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e" which has a higher version "5.0.5.0" than the version "2.0.5.0" in the current target framework. SilverlightTextEditor
By emtopping on
7/28/2012 6:42 AM
|
@emtopping - It looks like you will have to update the source code. I regret that I wont have time to update this.
By Michael Washington on
7/28/2012 7:00 AM
|
I understand , Michael thanks for taking the time to reply.
By emtopping on
7/29/2012 6:32 AM
|
Hi, all that needed to chaange to get it running was to make this internal class public
C:\code\RichTextBox\SilverlightTextEditor\SilverlightTextEditor\SilverlightTextEditor\Strings.Designer.cs(32): internal Strings() {
hope it helps someone.
By emtopping on
7/30/2012 8:11 AM
|
@emtopping - Thank you for following-up.
By Michael Washington on
7/30/2012 9:30 AM
|
How do i run it on silverlight 5.0? Thanks!
By Trung Nguyên on
7/30/2013 8:18 PM
|
@Trung Nguyên - Sorry I have no samples.
By Michael Washington on
7/30/2013 9:19 PM
|
is there any specific reason why you removed the functionality to insert pictures and table to the Rtb? These are the only two functions I need...
By Thomas on
8/12/2015 4:26 AM
|
@Thomas - I was trying to keep the blog simple. There is a lot more involved in uploading and saving photos.
By Michael Washington on
8/12/2015 4:26 AM
|
Ok, thanks for the reply. Is the functionality to insert tables and pictures included in the original Silverlight Text Editor from the msdn Website? Unfortunately the download link at the msdn website is not working anymore. Could you please send me the original Silverlight Text Editor via email if you still have it anywhere? If not, do you have any Idea where I can get it or where ich can get a codesample how to insert a table or a picture (tables are more important)? Thomas
By Thomas on
8/17/2015 11:53 AM
|
@Thomas - I do not have the original Silverlight text editor. Perhaps you can download my code sample and see if the .dll's in it are useful? I have no other examples of how to use this code because I have not coded in Silverlight in many years (this article is 4 years ole).
By Michael Washington on
8/17/2015 11:55 AM
|