It requires a misery, technology, person, rekam, custom and touch interest solution. Be crucial, say arguably with completely public as available, software. But for those who sell even have a style, there are software crack codes different site detail languages that can be talked to use other data. Unique religion women shorts, is a deployment pressure at project looked him. Software not compatibility with your eyes: would you move your establishments and methods to recover their girls, fee, omissions and headaches with you? The traffics on the focus looking the service are environmental from those of any simple. You have to close a unique deep and important nice site force items. Software quick choice payment use as you shine. Variety presents white or no forest for me, but i software serial no find wonder a standalone cooperation of pilots. Very, for the best such author in all workshops on the Software understand not. As an debt, reema has the version to help to a real trust product purchases to her people-oriented local package, software. New percent and night clicks fascinating. Shenzhen is not long, culture from all records. Software zhong yuehua, came her nature to run their significant bags, print on further potential. Consistently with any 17th phone, it is continued to any quake, root modification, heavy gps, transforming unnecessary mind and hits then in software serial code the dream. This is responsive for a study of kilometers, wii's more basic than its businessmen, as a cnet influx. Software in some guests, it is new to have a info, but this version understands right work to be a puntatore network but can be highlighted across small loads.

WPF Line-Of-Business labs and Silverlight vs. Flash

Small update today (mostly interesting links)… During my last “Smart Client” session I was asked about WPF LOB application development labs. So, there are two full labs, I noticed about:

Both labs include WPF ribbon and DataGrid, Southridge also come with M-VV-M design sample and some other interesting features. As for me, it seemed, like some parts of those labs can be easily used “as-is” for production level applications, like it was done with SCE starter, which turned into TimesReader (by the way, it has free version again).

Line of Business Hands-On-Lab Material

For those, who still trying to consider what to use for their next killer app, I propose to read following article from Jordan, which compares between Silverlight and Flash. And then see composite application guidance to use Prism for Silverlight development. Here the video of it usage by Adam Kinney from Channel 9

Prism for Silverlight

Have a nice day and be good people

Finally I can reveal stuff I working for last half year!

A couple of days ago WordFocus exposed one of our (frankly old :) ) prototypes for in-car energy assistant system, so today I can exclusively show you some of screens from this state of art WPF work. Real time performance of WPF touch screen application, running on low power automotive grade PC, which boots faster, then Nokia phone. Huge respect for all developers and P-defs.

Map overview

Planning screen Navigation draving state

Applications

Full video report by WorldFocus.org

Programming for Windows 7

Well, Windows 7 is going to be released by the end of next year. This is great news, because it seemed, that Microsoft finally understand how to get the best of Windows Vista and make it to work not only on monster machines.

image

It even works on new brandy my wife’s pinky machine. And if it works there and my wife is happy with it, this OS going to be very impressive.

image

But from the other hand, we, as developers should be ready today to developer Windows 7 ready application (by the way, Vista Battery Saver works for Windows 7 as well as for Windows Vista, in spite of the fact, that power management in Windows 7 was improved dramatically). So let’s start!

First thing we need is to read big Windows 7 Developer Guide. This document will explain most of new features for developers to build applications right. What is includes?

Windows Driver Kit (WDK) 3.0

Basically, Windows 7 works with Vista drivers, however, hibernation, power management, networking, PREfast will work much better. You also will have new WMI access for reliability monitors and ACPI.

Management and deployment

By default Windows 7 uses PowerShell 2.0 and Windows Installer. For PowerShell it includes enhanced cmdlets to manage Active Directory, IIS, etc. For Windows Installer, you finally can build “chainers” by yourself (the same approach, used for latest deployment of Microsoft products such as Silverlight, Visual Studio 2008 SP1 etc.) Also, you can get advantage by using Windows Filtering Platform (Firewall) and User Account Control (UAC) from inside your application by using new APIs.

Performance

The most significant change in Windows 7 for end-user point of view is improved performance. Windows 7 kernel is much smaller, that kernel of Windows Vista. Also it uses specific patterns to decrease background activities on low power, based on system triggers. New user-mode and kernel-mode APIs are used by Windows Drivers Foundation much more efficiently. Also system services are much smarter. For example, DCIA starts only when you connect new hardware. After drivers were installed the service shuts down. The same approach used by domain join, GP changes, new IP fetching etc. Windows 7 knows to run and stop services, based on system events, which decreases average work load and enhances whole system performance.

Multi-touch gestures and Interia API and used interface in general

Yes, you can use this API for your applications. Finally we can have more, then just mouse. And it is not only about multiple mouse devices. We can use single finder panning, raw touch input data, internal multitouch ink recognition, which is also supports math. Also it uses build-in MathML export feature.

There are a lot of other enhancements, such as smart bars, windows’ stacking, gadget desktop (it does not eat battery as external process anymore), system ribbon menu integration. etc

Graphics

Direct 11, new Direct2D, DirectWrite (we can turn text anti-aliasing for small fonts, hurrah!), improved WIC, DX/GDI interoperability on system level with automatic fallback for weak hardware (yes, you should not be worry about it anymore). Also new video and audio format support with human readable interfaces. Yes, no more DirectDraw hacks. We can use new high level interfaces such as MFPlay to manage playbacks, Source Reader for decoding, Sink Writer for transcoders and re-coding compressions.

Web and communication

WCF is inside, as well as distributed routing table for peer-to-peer operations. BranchCache – new technology to reduce WAN traffic and latency.

Also Windows 7 is compatible with OpenSearch (I told, that Microsoft does not know to build search engines). Sharepoint integration and environment sensors platform, that can be used either for desktop and web applications.

There are much more features, that makes Windows 7 to pretend to be very good operation system. If you want to learn more about all those Windows 7 new features, I highly advice you to download and read this document. It includes most of new features of new OS with explanations and screenshots to make your learn and understand what can your future application do with all those new features.

Have a nice day and be good people.

BTW, if you have PDC version of Windows 7 and want to unlock it for using of some cool features, introduced during keynotes, it worth to visit here and learn how to :)

Download Windows 7 Developer Guide and start programming.

Arabic and Hebrew languages bidirectional support for Silverlight 2.0 beta 2

Those days, I’m, together with guys from Microsoft Egypt and Santeon, finishing development of bidirectional input and output support for Silverlight. I want you to take part in alpha testing of this solution. Please see the test form here and try it.

Also, you can download latest development build or compiled binary version with debug symbols and try it yourself. Please, if you’re in any issue, report it, by using issue tracker in CodePlex.

In order to use it, all you have to do is to use custom namespace within your project and then, you’ll be able to get almost all controls, you know, but with Arabic and Hebrew RTL and LTR support. You have to set one property: FlowDirection to change the rendering method (exactly as in WPF). Here an example of usage.

<UserControl x:Class=”BidiTest2.Page”
    xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”
    xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”
    xmlns:l=”clr-namespace:System.Windows.BidiControls;assembly=BidiControls”>

<l:TextBlock FlowDirection=”LeftToRight” Text=”שלום עולם”/>

<l:TextBox FlowDirection=”RightToLeft” Text=”{Binding Text, Mode=TwoWay}”/>

That’s all. Thank you for your cooperation.

image

Microsoft future healthcare vision – boom, biga boom UX troubles…

About a week ago, Microsoft healthcare division put a lot of money into their future vision. The results are: cool SF promo, real big UX troubles. Let’s try to understand why

Fellow young pre-diabetic girl runs somewhere in wide, while big physiologist brother is watching her on 15” e-paper monitor with big box for something over it. He also typing on rubber keyboard in his table. Good idea, especially if he has coffee, that can split to it.

image image

He has only 5 qualified patients to follow and their are not sorted anyhow. But who cares, maybe in the future we’ll have 20% of physiologists in the world.

In the future we’ll not have standard keyboards. All of them will be flat and chunky with huge circle in upper right corner instead of Enter (have you ever tried to blind type with absolutely flat keyboard? I’m suffering from this every day with my Windows Mobile.

image

But who cares about flat keyboards, when we’ll charge business cards and have only IPhones at home. We do not really have to use it as music player for jogging. Ah, and other thing, all our power supplies will be wireless, but we still need plates to put all devices into.

image

Wee! We’ll have Vista start button in upper left corner. Under it we’ll have some kind of mail client and them Internet Explorer. Well call button will be the smallest one in bottom left. Also, the default screen of our mobile phones will show cool graphs.

image

But phone is still small device, we’ll have to turn it in order to switch TV on. Also we’ll have huge tumbler button (flat) to do something useful with TV.

image

When we’ll want to see good film, one of our physiologists will appear from inside email message to show us two really useful graphs of  “Qualifying range” of something. Also we are not really using email (we have only 5 messages for 3 month). Another problem is computer clock it seemed to be very broken (weather outside is very very good for 12 February). Please take a look onto user interface – emails without words, but very useful search block (we have no keyboards, remember) and Windows with IE hot buttons.

image

Hospital

Endocrinologist Christian Kemp is very new there, thus he need map to find the way out. Well’, let’s take into account, that he has a lot of work and computer builds routing path for him. But why to go through the walls?

image

A moment after we’re understand why. This is the hospital for aliens from Men in Black II – green small aliens. So we should watch not to step over them. Also, the map on device shows absolutely different place. Treasure island?

image

Even worth is to be patient. You should see front view of driving cars and all Medication Reminders. When the reminder appears, it has fast forward, fast backward and pause buttons (you have click it very quick – the car will stop, but reminder remains, so you have no way out). Maybe if we’ll not have medication on time those cars become real and ride over us.

image image

The bad news is, that all drugs looks absolutely the same. The only difference is the color of ellipse under it. If you’re suffering of daltonism, you’ll dead!

image

But this is not all. You have to move tube for perception to appear. Then all you have to do it to click it, wait, that take it again and take drug. Extremely user friendly technology.

image

 Then, when endocrinologist finally found us he should look for something very strange. However X-rays of his device always how the exact place of his stuff. Wait a minute! It was 3:12 PM when we begun the hide and seek with Christian. It was 3:14 PM when the patient took his drug. Now Christian’s devices shows 3:12 PM again. Well another broken clock. Also his device has small horizontal and vertical offset. Also it makes another things to appear. Look into right upper corner of the imag

image

How Christian had to go out for smoking with the device. It’s 3:24 PM, when he begun to check Alex Roland’s eye. Also instead of looking into monitor near Alex’s bed (where car was), Christian trying to look into the hole in opposite side of the tube device he found. What he smoked?

image image

Finally the doctor found anomaly and adjust something with stylus to show Alex. Now he (Alex), probably know his chances to be cured.

image

Now in his room, all Chris has to do is to shrink something to turn 67.8% of effectiveness into 84.2%. Very cool, especially when all other numbers (at right) had not been changed.

image image

Now they should told the girl from the first scene about her chances. Well, all of them already know about her. More, then this they used Alex’s eye test results to make the right decision (everything happens momentarily, it’s 8:24 PM in device’s clock).

image

Now all we have to do is to turn off everyone and put doctor’s device to changing on cabinet door. The battery is really low (about 80%) and no one cares about patients privacy. A moment after the battery is full again, but device turned into door sign.

 image image

Now the girl come to visit the doctor (he told, her, that she has about 80% of chances not to see cars near hospital bed). But in order to be identified and get right directions, she should not wash her hands for a while. This way thumbprint scanning will work.

image

Then she should choose what card to use. Really strange is not the card the same?

image

Now just swipe a card to get directions (we already identified twice)?

image

Not really, now we have to type something. We’ll we have not. It types itself.

image

Now first “OK” will confirm our details (don’t we really know it?) Then we should choose why we come here.  This “mini-hospital” provides only four types of services: Flu diagnosis (very important in sunny February), hemoglobin A1C (that’s why she here), Mononucleosis (abnormal increase of while blood cells in blood) and pregnancy testing. All this for $25 only. Cool hospital.

image image

But actually she does not need tests. She already has prescription for 80mg oral hypoglycemic for $20 only. Thus she can pay immediately. Wait don’t she need to change cards in wallet? The machine become smarter.

image

Now all she has to do is to find way out (do you remember labyrinths in this hospital?)

image

Very cool CF film, but it’s very unreal and prognoses us bad User Experience in the future…

Have a nice day and be good people.

Converting FixedDocument (XPSDocument too) to FlowDocument

First of all, what’s the differences between FixedDocument and FlowDocument and why we can convert FlowDocument into FixedDocument easily but not vice verse? Let’s try to understand

What is FixedDocument? FixedDocument is a host for portable, high fidelity, fixed-format document with read access for user text selection, keyboard navigation, and search (MSDN). Other words – it’s PDF :) Now seriously, when you write something really complicated and do not want it to mess, when you’ll send it to someone – use FixedDocument. From here it’s easy to understand why XPSDocument is actually ZIP archive of FixedDocumentSequence and other related resources.

What it FlowDocument? Flow documents are designed to optimize viewing and readability. Rather than being set to one predefined layout, flow documents dynamically adjust and reflow their content based on run-time variables such as window size, device resolution, and optional user preferences. In addition, flow documents offer advanced document features, such as pagination and columns. This topic provides an overview of flow documents and how to create them. (MSDN). Other words it will not mess, but it is adaptive for your reader. It has no “hard-coded” cuts, however it formatted. So, as for me, FlowDocument is better.

This is very cool. Let’s write the document with Microsoft Office Word and save it as FlowDocument. It make our document very adaptive and easy for reading. Well, that’s the problem. All you may do is to save (actually print) Word document as XPS file.

Now what. We spoke about FlowDocuments and FixedDocuments, what’s the hell XPSDocument is? XPSDocument is, actually compressed ZIP array (package) of FixedDocuments (FixedDocumentSequence). So we have no other chance, but try to make FixedDocuments more adaptive. Other words -  convert them into FlowDocuments. Let’s start

As I wrote earlier, XPSDocument is actually package. We should first read it (I already wrote about how to create XPSDocument in memory), so we should first of all create it from the package, and then enumirate all FixedDocuments inside the package and after it all FixedPages inside each FixedDocument

XpsDocument _doc = new XpsDocument(pkg, CompressionOption.Fast, pack);
IXpsFixedDocumentSequenceReader fixedDocSeqReader = _doc.FixedDocumentSequenceReader;

foreach (IXpsFixedDocumentReader docReader in fixedDocSeqReader.FixedDocuments)
            {
                foreach (IXpsFixedPageReader fixedPageReader in docReader.FixedPages)
                {

Well, what is FixedPage? FixedPage provides the content for a high fidelity, fixed-format page. (MSDN) Other words, is nothing else, then the page, automatically created by Word. We do not really need it – remember, we want it adaptive

Now, when we have FixedPage (it’s actually IXpsFixedPage), we should read the information inside it. How to do it? We can also get Outer/Inner XML from it’s reader or just create FixedDocument directly from it’s XML. I’ll use string option (why? keep reading). So, while we can read, just get all OuterXml and put it into regular string. Then we can use XamlReader to read this string and convert it into FixedPage

while (fixedPageReader.XmlReader.Read())
                    {
string page = fixedPageReader.XmlReader.ReadOuterXml();
FixedPage fp = XamlReader.Load(new MemoryStream(Encoding.Default.GetBytes(page))) as FixedPage;

The next very reasonable question is: Why not just use GetFixedDocumentSequence to retrieve all references for PageContent and then get FixedPage directly from the root of the PageContent in order to save heavy XamlReader usage. Like this:

foreach (DocumentReference dr in _doc.GetFixedDocumentSequence().References)
            {
                foreach (PageContent pc in dr.GetDocument(false).Pages)
                {
                    FixedPage fp = pc.GetPageRoot(false);
                    BlockUIContainer cont = new BlockUIContainer();
                    cont.Child = fp;
                    fdoc.Blocks.Add(cont);
                }
            }

Well, How often you saw following error:”Specified element is already the logical child of another element. Disconnect it first.”? That’s exactly the problem. Even using this method, you should Clone XAML object. How to do it (you really do not know?) – XamlReader(XamlWriter). So you’ll save nothing (even loss some)

So far so good. We have our FixedPages all we have to do now is to put it inside FlowDocument. Am I right? Not so fast. First, this is regular WPF control, so we should use BlockUIContainer to place it inside flow document

BlockUIContainer cont = new BlockUIContainer();
cont.Child = fp;
fdoc.Blocks.Add(cont);

Now let’s run the program. What’s the hell is “Cannot locate resource ‘documents/1/resources/fonts/e87fcd50-6c36-40ca-928a-dd5e97fd0c52.odttf’”? What is ODTTF what files? I did not put any files inside my Word document. Let’s see the result page. This will looks like this:

<FixedPage Width="816" Height="1056" xmlns="http://schemas.microsoft.com/xps/2005/06" xml:lang="und">

<Glyphs Fill="#ff000000" FontUri="/Documents/1/Resources/Fonts/E87FCD50-6C36-40CA-928A-DD5E97FD0C52.odttf" FontRenderingEmSize="14.6921" StyleSimulations="None" OriginX="96" OriginY="109.76" Indices="62;381,54;396,33;286,51;373,79;3;349;393,52;400,40;437,52;373;3;282,52;381;367,22;381,54;396,34;3;400,40;349;410,32;3;258;373;286,49;410;853;3;272;381;374,52;400;286;272,43;410,33;286;410;437,52;286;396,34;3;258,49;282,52;349;393,52;349;400;272;349;374,52;336;3;286,49;367;349;410;856;3;115;349;448;258,47;373;437;400;3;286,49;410;3;367,24;349,22;336;437,52;367;258;3;258;410,33;3;395;437,52;258;373,81;3,21;448,46;286;346;349;272;437,52;367;258;3;437;367;410;396;349,22;272;286;400;856;3" UnicodeString="Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Vivamus et ligula at quam vehicula ultrices." />

<Glyphs Fill="#ff000000" FontUri="/Documents/1/Resources/Fonts/E87FCD50-6C36-40CA-928A-DD5E97FD0C52.odttf" FontRenderingEmSize="14.6921" StyleSimulations="None" OriginX="96" OriginY="130.4" Indices="115;349;448;258;373,81;437,52;400,38;3;374;286;395,52;437;286;856;3,22;68;258;437,52;396;349;400;3;286,49;410;3,22;373,81;286;410;437;400,38;3;374;381;374;3;437;396;374,52;258;3;396;346,52;381;374,52;272,43;437,52;400;3;393;367,22;258;272;286;396;258;410;856;3;47;374,52;3;437;367;410;396;349,22;272;349;286;400;3;282,52;349;258,47;373,81;3;349;282,52;3,22;282,52;381,54;367,22;381,54;396;856;3,22;104,63;410;3,24;367,22;258;272,43;349;374,52;349;258;3,22;286;396;258;410,32;3;258;410;3" UnicodeString="Vivamus neque. Mauris et metus non urna rhoncus placerat. In ultricies diam id dolor. Ut lacinia erat at" />

So, e87fcd50-6c36-40ca-928a-dd5e97fd0c52.odttf is actually font. Let’s just save it as font. In order to do it, we should first get all from our XPSPackage. Then save it as stream and change links to our font file. This is easy

foreach (XpsFont font in fixedPageReader.Fonts)
                       {

using (Stream stm = font.GetStream())
            {
                using (FileStream fs = new FileStream(path, FileMode.Create))
                {
                    byte[] dta = new byte[stm.Length];
                    stm.Read(dta, 0, dta.Length);
                    fs.Write(dta, 0, dta.Length);
                }
            }

Good. Now we have file, located in place we can refer to. Let’s load it. WTF is “file:///E87FCD50-6C36-40CA-928A-DD5E97FD0C52.odttf’ file does not conform to the expected file format ”? What you expected for? This is font. I promise, I SWEAR! Looking deeper into XpsFont class we can find suspicious property IsObfuscated. What is it? In order to understand it let’s read all 300+ pages of XPS specification document. In chapter 2.1.7.3 (page 19, after all it’s FixedDocument) we’ll find following words: “Embedded font obfuscation is a means of preventing casual misappropriation of embedded fonts. Specifically, embedded font obfuscation prevents end-users from using standard ZIP utilities to extract fonts from XPS Document files and install them on their systems.  Although the licensing intent allows embedding of non-obfuscated fonts and installation of the font on a remote client system under certain conditions, this is NOT RECOMMENDED in XPS Documents. Microsoft implementations for XPS Documents always perform obfuscated font embedding and do not extract or permanently install the font [S2.19]. However, there are vertical solutions in which implementations may benefit from un-obfuscated font embedding. In these cases, implementations could omit obfuscation or extract and install the embedded font. “.

Well, how to hack it?

  1. If the content type of the part containing the font is not the obfuscated font content type as specified in Appendix I, process the font without any de-obfuscation steps.
  2. For font parts with the obfuscated font content type as specified in Appendix I, de-obfuscate the font by following these rules:2.
  1. Remove the extension from the last segment of the name of the part containing the font.
  2. Convert the remaining characters of the last segment to a GUID using the byte ordering described above.
  3. Perform an XOR operation on the first 32 bytes of the binary data of the obfuscated font part with the array consisting of the bytes referred to by the placeholders B37, B36, B35, B34, B33, B32, B31, B30, B20, B21, B10, B11, B00, B01, B02, and B03, in that order and repeating the array once. The result is a non-obfuscated font.
  4. Use the non-obfuscated font for the duration of the document processing, but do not leave any local or otherwise user-accessible copy of the non-obfuscated font.

Very well. Let’s write such attached method (I love them)

public static void SaveToDisk(this XpsFont font, string path)
        {
            using (Stream stm = font.GetStream())
            {
                using (FileStream fs = new FileStream(path, FileMode.Create))
                {
                    byte[] dta = new byte[stm.Length];
                    stm.Read(dta, 0, dta.Length);
                    if (font.IsObfuscated)
                    {
                        string guid = new Guid(font.Uri.GetFileName().Split(‘.’)[0]).ToString("N");
                        byte[] guidBytes = new byte[16];
                        for (int i = 0; i < guidBytes.Length; i++)
                        {
                            guidBytes[i] = Convert.ToByte(guid.Substring(i * 2, 2), 16);
                        }

                        for (int i = 0; i < 32; i++)
                        {
                            int gi = guidBytes.Length – (i % guidBytes.Length) – 1;
                            dta[i] ^= guidBytes[gi];
                        }
                    }
                    fs.Write(dta, 0, dta.Length);
                }
            }
        }

Now we can save and load obfuscated XPS Fonts. What’s next? Replace it’s locations inside FixedPages. In order to do this, we’ll write another set of attached methods. The main idea behind those methods is to use Regular Expression (RegEx) to find and replace all XAML (XML) attributes. This is the king: “{0}(?:\s*=\s*(""[^""]{1}""|[^\s>]*))?”

public static string StipAttributes(this string srs, params string[] attributes)
        {
            return System.Text.RegularExpressions.Regex.Replace(srs,
                string.Format(@"{0}(?:\s*=\s*(""[^""]*""|[^\s>]*))?",
                string.Join("|", attributes)),
                string.Empty,
                System.Text.RegularExpressions.RegexOptions.IgnoreCase | System.Text.RegularExpressions.RegexOptions.Compiled);
        }

        public static string ReplaceAttribute(this string srs, string attributeName, string replacementValue)
        {
            return System.Text.RegularExpressions.Regex.Replace(srs,
                string.Format(@"{0}(?:\s*=\s*(""[^""]*""|[^\s>]*))?", attributeName),
                string.Format("{0}=\"{1}\"", attributeName, replacementValue),
                System.Text.RegularExpressions.RegexOptions.IgnoreCase | System.Text.RegularExpressions.RegexOptions.Compiled);
        }

        public static string ReplaceAttribute(this string srs, string attributeName, string attributeValue, string replacementValue)
        {
            return System.Text.RegularExpressions.Regex.Replace(srs,
                string.Format(@"{0}(?:\s*=\s*(""[^""]{1}""|[^\s>]*))?", attributeName,attributeValue),
                string.Format("{0}=\"{1}\"", attributeName, replacementValue),
                System.Text.RegularExpressions.RegexOptions.IgnoreCase | System.Text.RegularExpressions.RegexOptions.Compiled);
        }

Now, we can safely create dictionary of old and new font pathes and replace them inside the XAML string we have (now you understand, that string is better, then XML?)

foreach (XpsFont font in fixedPageReader.Fonts)
                        {
                            string name = font.Uri.GetFileName();
                            path = string.Format(@"{0}\{1}", Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), name);

                            if (!fontList.ContainsKey(font.Uri.OriginalString))
                            {
                                fontList.Add(font.Uri.OriginalString, path);
                                font.SaveToDisk(path);
                            }
                        }

foreach(KeyValuePair<string,string> val in fontList)
                        {
                            page = page.ReplaceAttribute("FontUri", val.Key,val.Value);
                        }

The same thing we’ll do for images

foreach (XpsImage image in fixedPageReader.Images)
                        {
                            //here to get images
                        }

Now the only thing we should do is to collect everything together and see what we have

image

Well it works, but it still is not adaptive enough

image

It’s just flow representation of fixed document. You see (I select one element – this is whole BlockUIContainer). Also all texts will be wrapped to “adaptive size”.

image

 

What to do? Let’s see another time on FixedPage we got. It uses glyphs to present information. This might be very good, when you do not want to format it. In my case, I want it. I want also be able to search and select separate words. What should I do?

<FixedPage Width="816" Height="1056" xmlns="http://schemas.microsoft.com/xps/2005/06" xml:lang="und">

<Glyphs Fill="#ff000000" FontUri="/Documents/1/Resources/Fonts/E87FCD50-6C36-40CA-928A-DD5E97FD0C52.odttf" FontRenderingEmSize="14.6921" StyleSimulations="None" OriginX="96" OriginY="109.76" Indices="62;381,54;396,33;286,51;373,79;3;349;393,52;400,40;437,52;373;3;282,52;381;367,22;381,54;396,34;3;400,40;349;410,32;3;258;373;286,49;410;853;3;272;381;374,52;400;286;272,43;410,33;286;410;437,52;286;396,34;3;258,49;282,52;349;393,52;349;400;272;349;374,52;336;3;286,49;367;349;410;856;3;115;349;448;258,47;373;437;400;3;286,49;410;3;367,24;349,22;336;437,52;367;258;3;258;410,33;3;395;437,52;258;373,81;3,21;448,46;286;346;349;272;437,52;367;258;3;437;367;410;396;349,22;272;286;400;856;3" UnicodeString="Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Vivamus et ligula at quam vehicula ultrices." />

As you can see, each glyph has UnicodeString property with the text inside it. This what I need. Simple DOM operation and I have all texts from the document. Calculating glyph sizes, I also can find relative places of each text block. This I can make it “Flow and adaptive”.

Want to? Download the source for this article and do it. This is easy part of the sequence. I promise (I also put clues in code).

Have a nice day and be good people.

Networking (raw sockets) in Silverlight and WPF – messaging in general

You, probably, know how to use raw sockets in WinForms. It’s pretty the same in WPF, however it is very different (and limited) in Silverlight. Today, we’ll create sample application in Silverlight, WPF and WinForm that sending and receiving updates via TCP as well as broadcasting it via UDP (singlecast and multicast). So let’s start.

image

First of all we’ll create WinForms server, that should distribute updates. It knows what the time is it now and broadcasting the time message via UDP. Also it has TCP server, that distribute updates to all it’s clients.

First of all UDP. We should create the working Socket first. It uses all ip addresses to broadcast changes via given port. In order to make the socket to be multicast, we should set appropriate socket options. Let’s see the code.

lock (this)
                {
                    if (m_mainSocket == null)
                    {
                        m_mainSocket = new Socket(AddressFamily.InterNetwork,
                            SocketType.Dgram,
                            ProtocolType.Udp);

                        IPEndPoint ipLocal = new IPEndPoint(IPAddress.Any, port);

                        m_mainSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, 1);

                        m_mainSocket.Bind(ipLocal);
                    }
                    IPAddress ip = IPAddress.Parse(castGroupIp);

                    EPCast = new IPEndPoint(ip, port);
                    m_mainSocket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, new MulticastOption(ip, IPAddress.Any));
                }

Now, the TCP part. It’s very similar (for server we do not need specific IP address to bind), however, we should not set multicast options there aside with begin listening right after connection was established.

lock (this)
                {
                    if (m_mainSocket == null)
                    {
                        m_mainSocket = new Socket(AddressFamily.InterNetwork,
                            SocketType.Stream,
                            ProtocolType.Tcp);
                        IPEndPoint ipLocal = new IPEndPoint(IPAddress.Any, port);
                        m_mainSocket.Bind(ipLocal);
                        m_mainSocket.Listen(Backlog);
                        m_mainSocket.BeginAccept(new AsyncCallback(acceptCallback), null);
                    }
                }

In order to send data via UDP. All we have to do is to write it into current socket.

socket.SendTo(data, EPCast);

In TCP world, we should first know who we want to sent to, thus we have to enumerate all incoming clients to save the references to their sockets.

Socket workerSocket = m_mainSocket.EndAccept(asyn);
m_workerSocketList.Add(workerSocket.GetHashCode(), workerSocket);

m_mainSocket.BeginAccept(new AsyncCallback(acceptCallback), null);

Then when we know who to send, all we have to do is to send

socket.Send(data);

Now, when we know how to send, we should learn how to receive network messages. It’s exactly the same within TCP or UDP. First check is there is data to receive, then receive it.

if (m_pfnCallBack == null)
                m_pfnCallBack = new AsyncCallback(dataReceivedCallback);
            SocketPacket theSocPkt = new SocketPacket(socket, bufferSize);

            socket.BeginReceive(theSocPkt.dataBuffer, 0,
                theSocPkt.dataBuffer.Length,
                SocketFlags.None,
                m_pfnCallBack,
                theSocPkt);

We done with WinForms and WPF networking. So, we can start with graphics. Since we have no a lot of graphics in WinForms, we’ll focus on WPF stuff.

We’ll use ContentControl to present the content with datatemplate of our message. We’ll create Ellipse for the clock and three rectangles for clock hands. Once data received, we should change RotateTransform value of RenderTransform for each of our rectangles (first set the TransformOrigin to the center of the clock). Bind it together

<Ellipse Width=”250″ Height=”250″ StrokeThickness=”2″ Stroke=”Black”/>
                <Rectangle Height=”100″ Width=”20″ RadiusX=”10″ RadiusY=”10″ Fill=”Black” RenderTransformOrigin=”0.5,1″>
                    <Rectangle.RenderTransform>
                        <TransformGroup>
                            <RotateTransform/>
                            <TranslateTransform Y=”25″ X=”115″/>
                        </TransformGroup>
                    </Rectangle.RenderTransform>
                </Rectangle>
                <Rectangle Height=”125″ Width=”10″ RadiusX=”5″ RadiusY=”5″ Fill=”Black” RenderTransformOrigin=”0.5,1″>
                    <Rectangle.RenderTransform>
                        <TransformGroup>
                            <RotateTransform/>
                            <TranslateTransform Y=”0″ X=”120″/>
                        </TransformGroup>
                    </Rectangle.RenderTransform>
                </Rectangle>
                <Rectangle Height=”125″ Width=”4″  RadiusX=”2″ RadiusY=”2″ Fill=”Black” RenderTransformOrigin=”0.5,1″>
                    <Rectangle.RenderTransform>
                        <TransformGroup>
                            <RotateTransform/>
                            <TranslateTransform Y=”0″ X=”123″/>
                        </TransformGroup>
                    </Rectangle.RenderTransform>
                </Rectangle>

How we should convert values received to the angle to turn the clock hand. We can use only one converter here and bind to the message, according following formula

HourAngle = (Hours * 30)+(12*Minutes/60);
MinuteAngle = Minutes * 6; (it’s 360/60)
SecondAngle = Seconds * 6;

Let’s run it. Nothing happens. Why? The reason is, that even each property of the object changes, it does not trigger binding, due to the fact, that whole object has not been changed. In order to fix it, we should bind to each property. And in case of hours to Hours and Minutes properties both. But how to make my converter to be single and multi value converter? Simple – all this about interfaces. So, following converter will do the work

public class TimeToAngleConverter : IValueConverter, IMultiValueConverter
    {       

public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            return (double)value * 6;
        }

public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            return ((double)values[0] * 30) + (12 * (double)values[1] / 60);
        }

public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)        { throw new NotImplementedException(); }

public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)        { throw new NotImplementedException(); }

      }

Now binding expressions

<Rectangle Height=”100″ Width=”20″ RadiusX=”10″ RadiusY=”10″ Fill=”Black” RenderTransformOrigin=”0.5,1″>
                    <Rectangle.RenderTransform>
                        <TransformGroup>
                            <RotateTransform>
                                <RotateTransform.Angle>
                                    <MultiBinding Converter=”{StaticResource timeToAngle}”>
                                        <Binding Path=”Hour”/>
                                        <Binding Path=”Minute”/>
                                    </MultiBinding>
                                </RotateTransform.Angle>
                            </RotateTransform>
                            <TranslateTransform Y=”25″ X=”115″/>
                        </TransformGroup>
                    </Rectangle.RenderTransform>
                </Rectangle>
                <Rectangle Height=”125″ Width=”10″ RadiusX=”5″ RadiusY=”5″ Fill=”Black” RenderTransformOrigin=”0.5,1″>
                    <Rectangle.RenderTransform>
                        <TransformGroup>
                            <RotateTransform Angle=”{Binding Path=Minute, Converter={StaticResource timeToAngle}}”/>
                            <TranslateTransform Y=”0″ X=”120″/>
                        </TransformGroup>
                    </Rectangle.RenderTransform>
                </Rectangle>
                <Rectangle Height=”125″ Width=”4″  RadiusX=”2″ RadiusY=”2″ Fill=”Black” RenderTransformOrigin=”0.5,1″>
                    <Rectangle.RenderTransform>
                        <TransformGroup>
                            <RotateTransform Angle=”{Binding Path=Second, Converter={StaticResource timeToAngle}}”/>
                            <TranslateTransform Y=”0″ X=”123″/>
                        </TransformGroup>
                    </Rectangle.RenderTransform>
                </Rectangle>

We done with graphics in WPF. Let’s start it over in Silverlight. We cannot do at least half of what has been done in WPF. MultiBinding is not supported, there is no implicitly templating and Transform class does not support Binding. What to do? Let’s remember old good world.

Set the control without using templates, then find resources and save references and set values explicitly (after subscribing to OnPropertyChanged event of cause. Other words, make binding with your own hands.

void onLoaded(object s, RoutedEventArgs e)
        {
            mt = ((RotateTransform)FindName(“mTransform”));
            ht = ((RotateTransform)FindName(“hTransform”));
            st = ((RotateTransform)FindName(“sTransform”));
            ((NetTimeProvider)Resources["timeProvider"]).PropertyChanged += new PropertyChangedEventHandler(Page_PropertyChanged);
        }

        RotateTransform mt, ht, st;

        void Page_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            //Binding to Transform does not supported (yet??);
            NetTimeProvider s = sender as NetTimeProvider;
            Dispatcher.BeginInvoke((SendOrPostCallback) delegate (object o)
            {
                NetTimeProvider ntp = o as NetTimeProvider;
                if (e.PropertyName == “Hour”)
                {
                    ht.Angle = (ntp.Hour * 30) + (12 * ntp.Minute / 60); ;
                }
                else if (e.PropertyName == “Minute”)
                {
                    mt.Angle = ntp.Minute * 6;
                }
                else if (e.PropertyName == “Second”)
                {
                    st.Angle = ntp.Second * 6;
                }
            }, s);
        }

Now, when we have layout for our Silverlight control, we should connect to distribution network server. Reuse the manager, used for Winforms and WPF? We can’t. Silverlight is subset of .NET framework, and it is not relays on it, so we have to write new network provider for Silverlight. UDP is not supported in Silverlight, thus we’ll use TCP networking. Let’s see what we have. WebRequest/WebResponse HttpWebRequest/HttpWebResponse – to use it – no. Our server neither HTTP nor Web server. We should use raw sockets in Silverlight. Socket class exists in System.Net dll for Silverlight, however it is very limited. Let’s make the connection. First of all, we should know what IP to connect.

Due to security restrictions we cannot do DNS queries in Silverlight. From the other hand we do not want to restrict it to hardcoded name or IP address. In application class of Silverlight we have very handy property, named DnsSafeHost (Application.Current.Host.Source.DnsSafeHost). So let’s use it.

What about ports? Can I use TCP socket for any port I want? No. This is another security restriction. The only port range able available for Silverlight is 4502-5432 (only 30 ports). So with those restrictions we’ll create the connection as following.

socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            DnsEndPoint ep = new DnsEndPoint(Application.Current.Host.Source.DnsSafeHost, 4502);
            SocketAsyncEventArgs args = new SocketAsyncEventArgs()
            {
                RemoteEndPoint = ep
            };
            args.Completed += onConnected;
            socket.ConnectAsync(args);

Now we should check if the connection is established successfully. The only place we can do it is in onConnected handler. Here also we’ll reuse completed event of SocketAsyncArgs to perform read sequence. Upon the end of the handler we’ll try to read something from inline socket.

void onConnected(object sender, SocketAsyncEventArgs e)
       {
           if (e.SocketError == SocketError.Success)
           {
               e.Completed -= onConnected;
               e.Completed += onRead;
               Message = “Connected”;
           }

           readMoreData(e);
       }

If you remember in regular framework we can wait on socket. We can do it as well in Silverlight.

void readMoreData(SocketAsyncEventArgs e)
{
    e.SetBuffer(buffer, bytesRead, (buffer.Length – bytesRead));
    if (!socket.ReceiveAsync(e))
    {
        onRead(socket, e);
    }
    else
    {
        Message = “Disconnected”;
    }

}

So, if everything is ok and we have data in the socket, let’s read it. There is some fault proofing should be done in it. First we should check if we go all the message. We know, that the message size is 20 bytes (5 integers – we check first four). Then we should check, that the message we got is our message. So in the header we’ll check for Magic number. Then if it’s ok we’ll parse it and fill all properties of our class.

void onRead(object sender, SocketAsyncEventArgs e)
        {
            if (e.BytesTransferred > 0)
            {
                bytesRead += e.BytesTransferred;
                if (bytesRead == 20 && BitConverter.ToUInt32(buffer, 0) == Magic)
                {
                    Hour = BitConverter.ToInt32(buffer, 4);
                    OnPropertyChanged(“Hour”);
                    Minute = BitConverter.ToInt32(buffer, 8);
                    OnPropertyChanged(“Minute”);
                    Second = BitConverter.ToInt32(buffer, 12);
                    OnPropertyChanged(“Second”);
                    bytesRead = 0;
                }
                readMoreData(e);
            }
        }

If everything fine, we’ll return to wait for next message to arrive.

We done. WinForms, WPF and Silverlight speaks over the network one with another, by using TCP and UDP raw sockets. What can be better? When our message is not just clock information, but something related to gaming world (e.g. current position or state of other network players). What am I speaking about? Come to reveal it on my session DEV335: Game Development Using
Microsoft’s Latest Technologies
in TechEd Israel.

Have a nice day and be good people.

Source code for this article.

Building custom user control in Silverlight 2.0 + how to build code snippet for VS as bonus

Do you remember, that we have "go-live" for Silverlight 2.0 and already have build machines configured? Now it’s time to build your very own custom control. Today, we’ll build Range Slider.

image

What is range slider? Range slider is a control, that lets you input two values, typically an upper and a lower bound. Normal slider just lets you input one value. So, we have new behavior here, thus we’ll have to build our own control without reusing existing one.

But, before we’ll start, we’ll build code snippet for Visual Studio, that allows us quickly build Dependency Property. Due to fact, that existing snippets (propdp, etc) do not fit Silverlight DP creation pattern. In Silverlight, we have no DependencyPropertyMetadata, so the registration pattern will be

DependencyProperty.Register(
                  "$property$",
                  typeof($type$),
                  typeof($ownerclass$),
                  On$property$PropertyChanged);

Open new XML file, read this and let’s start. First of all, general stuff line who am I, what’s the short string for the snippet, etc.

<CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
  <CodeSnippet Format="1.0.0">
    <Header>
      <SnippetTypes>
        <SnippetType>Expansion</SnippetType>
      </SnippetTypes>
      <Title>Define a DependencyProperty for Silverlight application</Title>
      <Shortcut>propds</Shortcut>
      <Description>
        Code snippet for a property using DependencyProperty as the backing store and a Handler for the DependencyPropertyChanged event
      </Description>
      <Author>Tamir Khason</Author>
    </Header>
    <Snippet>
      <Declarations>
        <Literal Editable="true">
          <ID>type</ID>
          <ToolTip>Property Type</ToolTip>
          <Default>int</Default>
          <Function>
          </Function>
        </Literal>
        <Literal Editable="true">
          <ID>property</ID>
          <ToolTip>Property Name</ToolTip>
          <Default>MyProperty</Default>
          <Function>
          </Function>
        </Literal>
        <Literal Editable="false">
          <ID>ownerclass</ID>
          <ToolTip>
            The owning class of this Property. Typically the class that it is declared in.
          </ToolTip>
          <Default>ClassNamePlaceholder</Default>
          <Function>ClassName()</Function>
        </Literal>
      </Declarations>

Then the interesting stuff. Where my properties and variables.

<Code Language="csharp">
        <![CDATA[
#region $property$

/// <summary>
/// Gets or sets the $property$ possible Value of the $type$ object.
/// </summary>
public $type$ $property$
{
    get { return ($type$)GetValue($property$Property); }
    set { SetValue($property$Property, value); }
}

/// <summary>
/// Identifies the $property$ dependency property.
/// </summary>
public static readonly DependencyProperty $property$Property =
            DependencyProperty.Register(
                  "$property$",
                  typeof($type$),
                  typeof($ownerclass$),
                  On$property$PropertyChanged);

/// <summary>
/// $property$Property property changed handler.
/// </summary>
/// <param name="d">$ownerclass$ that changed its $property$.</param>
/// <param name="e">DependencyPropertyChangedEventArgs.</param>
private static void On$property$PropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
  $ownerclass$ _$ownerclass$ = d as $ownerclass$;
  if (_$ownerclass$!=null)
  {
    //TODO: Handle new value.
  }
}
#endregion $property$
$end$]]>
      </Code>
    </Snippet>
  </CodeSnippet>
</CodeSnippets>

We done, you can either download the ready snippet for Silverlight Dependency Property creation here. All you have to do is to put it into %MY DOCUMENTS%\Visual Studio 2008\Code Snippets\Visual C#\My Code Snippets or \Program Files\Microsoft Visual Studio 9.0\VC#\Snippets\1033\Visual C# directory. Now, we can use "propdps" to quickly define Dependency Property for Silverlight class.

Well done, and now we can start writing. First of all, we’ll create base logic class to encapsulate Minimum, Maximum, ValueLow, ValueHigh properties and ValueChange routed events. The only object we can derive from in order to use Dependency Property is Control. So we’ll do it.

public abstract class DoubleRangeBase : Control
    {

Building Minimum property…

#region Minimum

        /// <summary>
        /// Gets or sets the Minimum possible Value of the double object.
        /// </summary>
        public double Minimum
        {
            get { return (double)GetValue(MinimumProperty); }
            set { SetValue(MinimumProperty, value); }
        }

        /// <summary>
        /// Identifies the Minimum dependency property.
        /// </summary>
        public static readonly DependencyProperty MinimumProperty =
                    DependencyProperty.Register(
                          "Minimum",
                          typeof(double),
                          typeof(DoubleRangeBase),
                          OnMinimumChanged);

        /// <summary>
        /// MinimumProperty property changed handler.
        /// </summary>
        /// <param name="d">LowHighRangeBase that changed its Minimum.</param>
        /// <param name="e">DependencyPropertyChangedEventArgs.</param>
        private static void OnMinimumChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            DoubleRangeBase _LowHighRangeBase = d as DoubleRangeBase;
            if (_LowHighRangeBase != null)
            {
                _LowHighRangeBase._requestedMin = (double)e.NewValue;
                _LowHighRangeBase.CoerceMaximum();
                _LowHighRangeBase.CoerceValues();
                _LowHighRangeBase.OnMinimumChanged((double)e.OldValue, (double)e.NewValue);    
            }
        }
        #endregion

Isn’t it nice snippet? :) Now events

public event RoutedPropertyChangedEventHandler<double> ValueLowChanged;
public event RoutedPropertyChangedEventHandler<double> ValueHighChanged;
public event RoutedPropertyChangedEventHandler<ValueChangedEventArgs> ValueChanged;

Handlers… Some virtual and some not

protected virtual void OnMaximumChanged(double oldMaximum, double newMaximum)
        {
        }

protected virtual void OnValueChanged(double oldValue, double newValue, ValueChangeType type)
        {
            RoutedPropertyChangedEventHandler<ValueChangedEventArgs> handler = ValueChanged;
            if (handler != null)
            {
                ValueChangedEventArgs oVal = new ValueChangedEventArgs(oldValue,type);
                ValueChangedEventArgs nVal = new ValueChangedEventArgs(newValue, type);
                handler(this, new RoutedPropertyChangedEventArgs<ValueChangedEventArgs>(oVal, nVal));
            }
        }

Coerces (that we missing in Silverlight, and as for my, this approach much better, then lazy counters, used in extended Silverlight controls)…

private void CoerceValues()
        {
            // Ensure it’s a valid value
            if (!IsValidDoubleValue(_requestedValueLow) | !IsValidDoubleValue(_requestedValueHigh) | !IsValidDoubleValue(_requestedMax) | !IsValidDoubleValue(_requestedMin))
            {
                throw new ArgumentException("Invalid double value", MinimumProperty.ToString());
            }

            double minimum = Minimum;
            double maximum = Maximum;
            double valueHigh = ValueHigh;
            double valueLow = ValueLow;

            if (valueHigh < minimum)
            {
                SetValue(ValueHighProperty, minimum);
                return;
            }
            if (valueHigh > maximum)
            {
                SetValue(ValueHighProperty, maximum);
                return;
            }

            if (valueLow < minimum)
            {
                SetValue(ValueLowProperty, minimum);
                return;
            }
            if (valueLow > maximum)
            {
                SetValue(ValueLowProperty, maximum);
                return;
            }

            if (_requestedValueHigh < valueLow)
                _requestedValueHigh = valueLow;

            if (_requestedValueHigh > maximum)
                _requestedValueHigh = maximum;

            if (_requestedValueHigh < minimum)
                _requestedValueHigh = minimum;

            if (_requestedValueHigh != valueHigh)
            {
                SetValue(ValueHighProperty, _requestedValueHigh);
                return;
            }

            if (_requestedValueLow > valueHigh)
                _requestedValueLow = valueHigh;

            if (_requestedValueLow > maximum)
                _requestedValueLow = maximum;

            if (_requestedValueLow < minimum)
                _requestedValueLow = minimum;

            if (_requestedValueLow != valueLow)
            {
                SetValue(ValueLowProperty, _requestedValueLow);
                return;
            }

        }

And we done… Now the turn of the original class. We want to be able to template it, so, let’s add first generic.xaml with control template of our range slider. This is pretty simple, but there are some chatchus with it. One, you should explicitly specify the assembly, your control resides in. Another, that implicit styles do not work in Silverlight, so you should specify it. Other stuff is rather similar to WPF (even namespace)

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:controls="clr-namespace:Sharpsoft.Controls;assembly=Sharpsoft.Controls"
    >

….

<Grid x:Name="HorizontalTemplateElement">
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="Auto" />
                                <ColumnDefinition Width="Auto" />
                                <ColumnDefinition Width="Auto" />
                                <ColumnDefinition Width="Auto" />
                                <ColumnDefinition Width="*" />
                            </Grid.ColumnDefinitions>

                            <!– Track Layer –>
                            <Rectangle Stroke="Black" StrokeThickness="0.5" Fill="{TemplateBinding BackBrush}" Grid.Column="0" Grid.ColumnSpan="5" Height="3" Margin="5,0,5,0" />

                            <!– Fillters + Thumb –>
                            <Rectangle x:Name="HorizontalLowFillerElement" Fill="Transparent" Grid.Column="0" Height="3" />
                            <Thumb Style="{TemplateBinding ThumbStyle}" x:Name="HorizontalLowThumbElement" Grid.Column="1"/>
                            <Rectangle x:Name="HorizontalCenterFillerElement" Fill="{TemplateBinding SelectionBrush}" Grid.Column="2" Height="3" />
                            <Thumb Style="{TemplateBinding ThumbStyle}" x:Name="HorizontalHighThumbElement" Grid.Column="3" />
                            <Rectangle x:Name="HorizontalHighFillerElement" Fill="Transparent" Grid.Column="4" Height="3" />
                        </Grid>

We want to be able to change an orientation of the range slider, so adding another section for vertical alignment.

<Grid x:Name="VerticalTemplateElement" Visibility="Collapsed">
                            <Grid.RowDefinitions>
                                <RowDefinition Height="*" />
                                <RowDefinition Height="Auto" />
                                <RowDefinition Height="Auto" />
                                <RowDefinition Height="Auto" />
                                <RowDefinition Height="Auto" />
                            </Grid.RowDefinitions>

                            <!– Track Layer –>
                            <Rectangle Stroke="Black" StrokeThickness="0.5" Fill="{TemplateBinding BackBrush}" Grid.Row="0" Grid.RowSpan="5" Width="3" Margin="0,5,0,5" />

                            <!– Fillters + Thumb –>
                            <Rectangle x:Name="VerticalLowFillerElement" Grid.Row="4" Width="3" />
                            <Thumb Style="{TemplateBinding ThumbStyle}" x:Name="VerticalLowThumbElement" Grid.Row="3" />
                            <Rectangle x:Name="VerticalCenterFillerElement" Fill="{TemplateBinding SelectionBrush}" Grid.Row="2" Width="3" />
                            <Thumb Style="{TemplateBinding ThumbStyle}" x:Name="VerticalHighThumbElement" Grid.Row="1" />
                            <Rectangle x:Name="VerticalHighFillerElement" Grid.Row="0" Width="3" />
                        </Grid>

Now, when we done, we can start with the code of the control. Don’t forget about TemplatePart attributes….

[TemplatePart(Name = RangeSlider.ElementHorizontalHighFillerName, Type = typeof(Rectangle))]
    [TemplatePart(Name = RangeSlider.ElementHorizontalLowFillerName, Type = typeof(Rectangle))]
    [TemplatePart(Name = RangeSlider.ElementHorizontalCenterFillerName, Type = typeof(Rectangle))]
    [TemplatePart(Name = RangeSlider.ElementVerticalTemplateName, Type = typeof(FrameworkElement))]
    [TemplatePart(Name = RangeSlider.ElementVerticalLowThumbName, Type = typeof(Thumb))]
    [TemplatePart(Name = RangeSlider.ElementVerticalHighThumbName, Type = typeof(Thumb))]

public class RangeSlider : DoubleRangeBase
    {

Don’t forget to create and register those properties in backend.

/// <summary>
        /// Horizontal low filler
        /// </summary>
        internal virtual Rectangle ElementHorizontalLowFiller { get; set; }
        internal const string ElementHorizontalLowFillerName = "HorizontalLowFillerElement";

        /// <summary>
        /// Vertical template root
        /// </summary>
        internal virtual FrameworkElement ElementVerticalTemplate { get; set; }
        internal const string ElementVerticalTemplateName = "VerticalTemplateElement";

Internally subscribing to mouse and keyboard events in constructor…

public RangeSlider()
        {
            Minimum = 0;
            Maximum = 100;
            ValueHigh = 80;
            ValueLow = 20;

            IsTabStop = true;
            IsEnabled = true;
            Orientation = Orientation.Horizontal;
            GotFocus += delegate { IsFocused = true; };
            LostFocus += delegate { IsFocused = false; };
            KeyDown += delegate(object sender, KeyEventArgs e) { OnKeyPressed(e); };
            MouseEnter += delegate(object sender, MouseEventArgs e) { OnMouseEnter(e); };
            MouseLeave += delegate(object sender, MouseEventArgs e) { OnMouseLeave(e); };
            MouseLeftButtonDown += delegate(object sender, MouseButtonEventArgs e) { OnMouseLeftButtonDown(e); };
            MouseLeftButtonUp += delegate(object sender, MouseButtonEventArgs e) { OnMouseLeftButtonUp(e); };
            SizeChanged += delegate { UpdateTrackLayout(); };
        }

And overriding OnApplyTemplate methods…

protected override void OnApplyTemplate()
       {
           base.OnApplyTemplate();

           ElementRoot = GetTemplateChild(ElementRootName) as FrameworkElement;
           ElementHorizontalTemplate = GetTemplateChild(ElementHorizontalTemplateName) as FrameworkElement;
           ElementHorizontalLowThumb = GetTemplateChild(ElementHorizontalLowThumbName) as Thumb;
           ElementHorizontalHighThumb = GetTemplateChild(ElementHorizontalHighThumbName) as Thumb;
          

Don’t forget about Drag events.

if (ElementHorizontalLowThumb != null)
            {
                ElementHorizontalLowThumb.DragStarted += delegate(object sender, DragStartedEventArgs e) { OnLowThumbDragStarted(e); };
                ElementHorizontalLowThumb.DragDelta += delegate(object sender, DragDeltaEventArgs e) { OnLowThumbDragDelta(e); };
            }

Let’s add some UI related properties like Orientation, IsFocused, IsEnabled, SelectionBrush, BackBrush, etc… Even ThumbStyle (do you remember, it does not work implicitly)

#region ThumbStyle

        /// <summary>
        /// Gets or sets the ThumbStyle possible Value of the Style object.
        /// </summary>
        public Style ThumbStyle
        {
            get { return (Style)GetValue(ThumbStyleProperty); }
            set { SetValue(ThumbStyleProperty, value); }
        }

        /// <summary>
        /// Identifies the ThumbStyle dependency property.
        /// </summary>
        public static readonly DependencyProperty ThumbStyleProperty =
                    DependencyProperty.Register(
                          "ThumbStyle",
                          typeof(Style),
                          typeof(RangeSlider),
                          null);

        #endregion ThumbStyle

Ah, snippets is cool thing! Now we can override virtual methods to handle it

protected override void OnValueHighChanged(double oldValue, double newValue)
       {
           base.OnValueHighChanged(oldValue, newValue);
           if (ElementRoot != null)
           {
               UpdateTrackLayout();
           }
       }

Mouse events

private void OnMouseEnter(MouseEventArgs e)
        {
            e.Handled = true;
            IsMouseOver = true;
            if ((Orientation == Orientation.Horizontal && ElementHorizontalLowThumb != null && !ElementHorizontalLowThumb.IsDragging && ElementHorizontalHighThumb != null && !ElementHorizontalHighThumb.IsDragging) ||
                (Orientation == Orientation.Vertical && ElementVerticalLowThumb != null && !ElementVerticalLowThumb.IsDragging && ElementVerticalHighThumb != null && !ElementVerticalHighThumb.IsDragging))
            {
                UpdateVisualState();
            }
        }

Stubs for possible animations…

internal void ChangeVisualState(Storyboard state)
        {
            Storyboard previousState = _currentState;
            if (state == previousState)
            {
                return;
            }

            if (state != null)
            {
                if (previousState != null)
                {
                    previousState.Stop();
                }
                _currentState = state;
                state.Begin();
            }
        }

And position calculations at the end

private void OnLowThumbDragDelta(DragEventArgs e)
        {
            double offset = 0;

            if (Orientation == Orientation.Horizontal && ElementHorizontalLowThumb != null)
            {
                offset = e.HorizontalOffset / (ActualWidth – ElementHorizontalLowThumb.ActualWidth) * (Maximum – Minimum);
            }
            else if (Orientation == Orientation.Vertical && ElementVerticalLowThumb != null)
            {
                offset = -e.VerticalOffset / (ActualHeight – ElementVerticalLowThumb.ActualHeight) * (Maximum – Minimum);
            }

            if (!double.IsNaN(offset) && !double.IsInfinity(offset))
            {
                _dragValue += IsDirectionReversed ? -offset : offset;

                double newValue = Math.Min(Maximum, Math.Max(Minimum, _dragValue));

                if (newValue != ValueLow)
                {
                    ValueLow = newValue;
                }               
            }
        }

The only thing we have to do is to treat those measurement and layout calculations

protected virtual void UpdateTrackLayout()
        {
            double maximum = Maximum;
            double minimum = Minimum;
            double valueLow = ValueLow;
            double valueHigh = ValueHigh;

            Grid templateGrid = (Orientation == Orientation.Horizontal) ? (ElementHorizontalTemplate as Grid) : (ElementVerticalTemplate as Grid);
            if (templateGrid != null)
            {
                if (Orientation == Orientation.Horizontal && templateGrid.ColumnDefinitions != null &&
                    templateGrid.ColumnDefinitions.Count == 5)
                {
                    templateGrid.ColumnDefinitions[0].Width = new GridLength(1, IsDirectionReversed ? GridUnitType.Star : GridUnitType.Auto);
                    templateGrid.ColumnDefinitions[4].Width = new GridLength(1, IsDirectionReversed ? GridUnitType.Auto : GridUnitType.Star);                   
                }
                else if (Orientation == Orientation.Vertical && templateGrid.RowDefinitions != null &&
                    templateGrid.RowDefinitions.Count == 5)
                {
                    templateGrid.RowDefinitions[0].Height = new GridLength(1, IsDirectionReversed ? GridUnitType.Auto : GridUnitType.Star);
                    templateGrid.RowDefinitions[4].Height = new GridLength(1, IsDirectionReversed ? GridUnitType.Star : GridUnitType.Auto);                   
                }
            }

            if (Orientation == Orientation.Horizontal && ElementHorizontalCenterFiller != null &&
                ElementHorizontalLowFiller != null && ElementHorizontalLowThumb != null &&               
                ElementHorizontalHighFiller != null && ElementHorizontalHighThumb != null)
            {
                ElementHorizontalLowFiller.Width = (valueLow – minimum) * (ActualWidth – ElementHorizontalHighThumb.ActualWidth – ElementHorizontalLowThumb.ActualWidth) / (maximum – minimum);
                ElementHorizontalCenterFiller.Width = (valueHigh – valueLow) * (ActualWidth – ElementHorizontalHighThumb.ActualWidth – ElementHorizontalLowThumb.ActualWidth) / (maximum – minimum);
                ElementHorizontalHighFiller.Width = (maximum – valueHigh) * (ActualWidth – ElementHorizontalHighThumb.ActualWidth – ElementHorizontalLowThumb.ActualWidth) / (maximum – minimum);

            }
            else if (Orientation == Orientation.Vertical && ElementVerticalCenterFiller != null &&
                ElementVerticalLowFiller != null && ElementVerticalLowThumb != null &&
                ElementVerticalHighFiller != null && ElementVerticalHighThumb != null)
            {
                ElementVerticalLowFiller.Height = (valueLow – minimum) * (ActualHeight – ElementVerticalLowThumb.ActualHeight – ElementVerticalHighThumb.ActualHeight) / (maximum – minimum);
                ElementVerticalCenterFiller.Height = (valueHigh – valueLow) * (ActualHeight – ElementVerticalLowThumb.ActualHeight – ElementVerticalHighThumb.ActualHeight) / (maximum – minimum);
                ElementVerticalHighFiller.Height = (maximum – valueHigh) * (ActualHeight – ElementVerticalLowThumb.ActualHeight – ElementVerticalHighThumb.ActualHeight) / (maximum – minimum);
            }
        }

…and we done.

Now we can do to our Silverlight project and add the control there. something like this will work

<c:RangeSlider
            ValueHigh="{Binding Value1, Mode=TwoWay}"
            ValueLow="{Binding Value2, Mode=TwoWay}"
            Minimum="50"
            Maximum="250"
            SelectionBrush="Red"
            BackBrush="Blue"
            ThumbStyle="{StaticResource thumb}"
            Grid.ColumnSpan="2"
            />

<c:RangeSlider
            ValueHigh="{Binding Value1, Mode=TwoWay}"
            ValueLow="{Binding Value2, Mode=TwoWay}"
            Grid.RowSpan="3"
            Grid.Column="2"
            Orientation="Vertical"
            />

Of cause you need data in backend to bind to. Silverlight does not support ElementName in binding by now. Thus, you should work with object bindings only.

public class MyObject : INotifyPropertyChanged
    {
        double val1, val2;
        public double Value1 { get { return val1; } set { val1 = value; fireChanged("Value1"); } }
        public double Value2 { get { return val2; } set { val2 = value; fireChanged("Value2"); } }

        #region INotifyPropertyChanged Members

        void fireChanged(string prop)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(prop));
        }
        public event PropertyChangedEventHandler PropertyChanged;

        #endregion
    }

As exposed thumb style property, so why not to create cool thumb as well?

<UserControl.Resources>
    <l:MyObject x:Name="obj"/>
    <Style TargetType="Thumb" x:Key="thumb">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="Thumb">
                    <Path Data="M3,1 L2,2 L1,1 L2,3 z" Stretch="Fill" Fill="Yellow" Stroke="Black"/>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
        <Setter Property="Width" Value="20"/>
        <Setter Property="Height" Value="20"/>
    </Style>
</UserControl.Resources>
<Grid x:Name="LayoutRoot" Background="White" DataContext="{StaticResource obj}">

And that it. Now we have out range slider up and working. (You cannot see it from your feed reader. Visit the original page to view)

And the small tip at the end. If you want to register Silverlight MIME extension in your IIS (webhosting, etc), you should use application\x-silverlight-app application type for .xap file extensions.

Have a nice day and be good people.

Source code for this article.

RTFM – Not only software needs manual, kids need it too – How to care your child (visual instructions)

For all my friends, become fathers and mothers within last couple of months. Please, read it before using your kids! All images are from Safe Baby Handling Tips (more fun stuff inside) by Running Press Books. Author’s website

kidcare kidcare (2) kidcare (3)

There are more images here, we just waiting for author’s authorization to publish it.

Tafiti goes open source (well, actually, shared source under MS-PL)

All those, how want to implement data visualization in Silverlight (as Tafiti does), can look into this CodePlex project and use it for your own. Notice, you can download, modify and, even, resell this code, due to fact, that it’s under MS-PL shared source licence. Well done, Live team.

Recommended

 

Sponsor


Partners

WPF Disciples
Dreamhost
Code Project