XamlHack: A Better XAMLPad

| 0 comments

XamlHack is a little XAML authoring tool which I use in my daily WPF life. whenever I want to author some small pieces of XAML code, I use this tool instead of Visual Studio, becauese this tool is more lightweight and easier to work with when writing some trivial XAML testing code, and the following is some of the features which this version of XamlHack supports:

1. Basic text editing features & syntax highlighting for XAML

Writing a text editor which directly supports syntax highlight is really difficult, fortunately SharpDevelop project already has a decent text editing control, so without reinventing the wheel, I use this control instead, so I can get syntax highlighting, line numbering, folding and unfolding etc at free. I also add the search and replace capability which is essential to any text editor.

2. XAML preview with element tree viewing capability using "Element Tree Explorer"   

In the XAML preview window(aka the "Design" tab shown below), You can examine the definition of the visual tree and logical tree of the root element. I think this feature is very important, since the element tree is a key player in a lot of WPF features for instance resource lookup, property inheritance and routed events etc. By default, the "Element Tree Explorer" is turened off, you can turn it on by checking it from the "View" menu.

3. Examine the default value of DPs using "Property Explorer"

The ability to examine the default value of dependency properties is a vital feature, in particular, when you want to know the default XAML definition for a control's ControlTemplate and Style property, XamlHack has this feature built in, so you don't need to go a long way to use Expression Blend to find out such kind of info, and another plus of this tool is that it enables you to add third party assemblies for examination.

4. Convert BAML to XAML using "Resource Explorer"

I use reflector quite a lot to "reverse engineer" the code written by other poeple, reflector can let you decompile the IL code, but not BAML code, so in order to "reverse engineer" BAML code, I create this tool (at the time of this writing, Reflector already has this feature.)

5. Last but not least, peculiar error warning.

When your XAML code contains some errors, XamlHack will show you a hilarious error warning message in "Design" tab, and when you click the message, it will turn you back to your xaml code, and directly highlight the source of error for you.

If XamlHack and the features it provides make some sense to you, you can download it here and have a try on it, any feedback and suggestions are greatly appreciated.

Attachment: XamlHack.zip

Ribbon Style Ⅱ

| 2 comments

As a follow-up to my previous post, I continue my work on creating ribbon styled controls, It seems that someone else has already take on the adventure, and what he has created is really cool indeed.

Anyway, the following screenshot demonstrates the current progress I am at:

Currently I cannot upload the source to my server, I promise when it get fixed, I will update this post to include the download link.

Edit: Source is uploaded, you can download the vs project here.

How To Reference Nested Types In XAML?

| 0 comments

This is actually an undocumented trick, but it really works:

namespace ReferenceNestedTypeDemo
{
    public class MyClass
    {
        public enum MyEnum { Value1, Value2, Value3 };
    }
}

<ComboBox>
  <
ComboBoxItem Tag="{x:Static app:MyClass+MyEnum.Value1}">Value 1</ComboBoxItem>
  <
ComboBoxItem Tag="{x:Static app:MyClass+MyEnum.Value2}">Value 2</ComboBoxItem>
</
ComboBox>

 

Ribbon Style Ⅰ

| 0 comments

Recently, I have some fun spicing up the standard WPF controls to make them looks like the flashy ribbon style which is available in the Office 2007. I'm so stunned by how easy you can do it in WPF using styling and control templating:

For those of you who are interested in this, you can download source from here.

Don And Chris Are Hilarious!

Don Box and Chris Anderson two of Microsoft genius software architects just shown on Channel9 video fumbling with their "terrible" singing voice, although they are not good singers, or should they be, but the lyrics of the song is really rhyming:

Vista, we shipped it,
Vista, we shipped it,
Vista, we shipped it,
Better late than not.

Vista, you'll love it,
Vista, you'll love it,
Vista, you'll love it,
It's the best we've got.

[Here] we've got Indigo,
and it will really glow,
when you've got avalon,
spicing up the show,

Sure there's no WinFS,
but we've got RSS,
and search and indexing will sort out the rest,

Use - er Ac - count Con - trol
UAT, and I'm no admin,
UAT, and you're no admin,
UAT, and she's no admin,
UAT, and he's no admin,

Which is whyyyyyyyyyyyy!

We're happy again.

I Have Some Fun With FormattedText

| 2 comments

Recently I've been trying the rich text sample code in the WPF documentation, the following custom control is something I come up with when playing with the FormattedText class:

using System;
using System.Xml;
using System.Text;

using System.Threading;
using System.Windows;
using System.Windows.Media;
using System.Windows.Markup;
using System.Windows.Shapes;
using System.Windows.Controls;
using System.Windows.Documents;

using Sheva.Internal;

namespace Sheva.Windows.Controls
{
    public class OutlinedText : FrameworkElement
    {
        private FormattedText formattedText;

        public static DependencyProperty FillProperty;
        public static DependencyProperty StrokeProperty;
        public static DependencyProperty StrokeThicknessProperty;
        public static DependencyProperty FontFamilyProperty;
        public static DependencyProperty FontSizeProperty;
        public static DependencyProperty FontStretchProperty;
        public static DependencyProperty FontStyleProperty;
        public static DependencyProperty FontWeightProperty;
        public static DependencyProperty RenderHighlightProperty;
        public static DependencyProperty TextProperty;
        public static DependencyProperty TextGeometryProperty;
        public static DependencyProperty TextHighlightGeometryProperty;
        private static DependencyPropertyKey TextGeometryPropertyKey;
        public static DependencyPropertyKey TextHighlightGeometryPropertyKey;

        static OutlinedText()
        {
            FillProperty = DependencyProperty.Register(
                "Fill",
                typeof(Brush),
                typeof(OutlinedText),
                new FrameworkPropertyMetadata(Brushes.Black, FrameworkPropertyMetadataOptions.AffectsRender));

            StrokeProperty = DependencyProperty.Register(
                "Stroke",
                typeof(Brush),
                typeof(OutlinedText),
                new FrameworkPropertyMetadata(Brushes.Black, FrameworkPropertyMetadataOptions.AffectsRender));

            StrokeThicknessProperty = DependencyProperty.Register(
                "StrokeThickness",
                typeof(Double),
                typeof(OutlinedText),
                new FrameworkPropertyMetadata(
                    0.0d,
                    FrameworkPropertyMetadataOptions.AffectsRender |
                    FrameworkPropertyMetadataOptions.AffectsMeasure));

            FontFamilyProperty = DependencyProperty.Register(
                "FontFamily",
                typeof(FontFamily),
                typeof(OutlinedText),
                new FrameworkPropertyMetadata(
                    SystemFonts.MessageFontFamily,
                    FrameworkPropertyMetadataOptions.AffectsRender |
                    FrameworkPropertyMetadataOptions.AffectsMeasure),
                    new ValidateValueCallback(IsValidFontFamily));

            FontStyleProperty = DependencyProperty.Register(
                "FontStyle",
                typeof(FontStyle),
                typeof(OutlinedText),
                new FrameworkPropertyMetadata(
                    SystemFonts.MessageFontStyle,
                    FrameworkPropertyMetadataOptions.AffectsRender |
                    FrameworkPropertyMetadataOptions.AffectsMeasure));

            FontWeightProperty = DependencyProperty.Register(
                "FontWeight",
                typeof(FontWeight),
                typeof(OutlinedText),
                new FrameworkPropertyMetadata(
                    SystemFonts.MessageFontWeight,
                    FrameworkPropertyMetadataOptions.AffectsRender |
                    FrameworkPropertyMetadataOptions.AffectsMeasure));

            FontStretchProperty = DependencyProperty.Register(
                "FontStretch",
                typeof(FontStretch),
                typeof(OutlinedText),
                new FrameworkPropertyMetadata(
                    FontStretches.Normal,
                    FrameworkPropertyMetadataOptions.AffectsRender |
                    FrameworkPropertyMetadataOptions.AffectsMeasure));

            FontSizeProperty = DependencyProperty.Register(
                "FontSize",
                typeof(Double),
                typeof(OutlinedText),
                new FrameworkPropertyMetadata(
                    SystemFonts.MessageFontSize,
                    FrameworkPropertyMetadataOptions.AffectsRender |
                    FrameworkPropertyMetadataOptions.AffectsMeasure));

            TextProperty = DependencyProperty.Register(
                "Text",
                typeof(String),
                typeof(OutlinedText),
                new FrameworkPropertyMetadata(
                    String.Empty,
                    FrameworkPropertyMetadataOptions.AffectsRender |
                    FrameworkPropertyMetadataOptions.AffectsMeasure));

            RenderHighlightProperty = DependencyProperty.Register(
                "RenderHighlight",
                typeof(Boolean),
                typeof(OutlinedText),
                new FrameworkPropertyMetadata(
                BooleanBoxes.FalseBox,
                FrameworkPropertyMetadataOptions.AffectsRender |
                FrameworkPropertyMetadataOptions.AffectsMeasure));

            TextGeometryPropertyKey = DependencyProperty.RegisterReadOnly(
                "TextGeometry",
                typeof(Geometry),
                typeof(OutlinedText),
                new FrameworkPropertyMetadata(null));
            TextGeometryProperty = TextGeometryPropertyKey.DependencyProperty;

            TextHighlightGeometryPropertyKey = DependencyProperty.RegisterReadOnly(
                "TextHighlightGeometry",
                typeof(Geometry),
                typeof(OutlinedText),
                new FrameworkPropertyMetadata(null));
            TextHighlightGeometryProperty = TextHighlightGeometryPropertyKey.DependencyProperty;
        }

        public Brush Fill
        {
            get { return (Brush)base.GetValue(FillProperty); }
            set { base.SetValue(FillProperty, value); }
        }

        public Brush Stroke
        {
            get { return (Brush)base.GetValue(StrokeProperty); }
            set { base.SetValue(StrokeProperty, value); }
        }

        public Double StrokeThickness
        {
            get { return (Double)base.GetValue(StrokeThicknessProperty); }
            set { base.SetValue(StrokeThicknessProperty, value); }
        }

        public FontFamily FontFamily
        {
            get { return (FontFamily)base.GetValue(FontFamilyProperty); }
            set { base.SetValue(FontFamilyProperty, value); }
        }

        public Double FontSize
        {
            get { return (Double)base.GetValue(FontSizeProperty); }
            set { base.SetValue(FontSizeProperty, value); }
        }

        public FontStyle FontStyle
        {
            get { return (FontStyle)base.GetValue(FontStyleProperty); }
            set { base.SetValue(FontStyleProperty, value); }
        }

        public FontStretch FontStretch
        {
            get { return (FontStretch)base.GetValue(FontStretchProperty); }
            set { base.SetValue(FontStretchProperty, value); }
        }

        public FontWeight FontWeight
        {
            get { return (FontWeight)base.GetValue(FontWeightProperty); }
            set { base.SetValue(FontWeightProperty, value); }
        }

        public String Text
        {
            get { return (String)base.GetValue(TextProperty); }
            set { base.SetValue(TextProperty, value); }
        }

        public Boolean RenderHighlight
        {
            get { return (Boolean)base.GetValue(RenderHighlightProperty); }
            set { base.SetValue(RenderHighlightProperty, BooleanBoxes.Box(value)); }
        }

        public Geometry TextGeometry
        {
            get { return (Geometry)base.GetValue(TextGeometryProperty); }
        }

        public Geometry TextHighlightGeometry
        {
            get { return (Geometry)base.GetValue(TextHighlightGeometryProperty); }
        }

        protected override Size MeasureOverride(Size availableSize)
        {
            EnsureTextGeometry();
            Size geometrySize = GetNaturalSize();
            Double width = availableSize.Width;
            Double Height = availableSize.Height;
            if (Double.IsInfinity(width) && Double.IsInfinity(Height))
            {
                return geometrySize;
            }

            if (Double.IsInfinity(width))
            {
                width = geometrySize.Width;
            }

            if (Double.IsInfinity(Height))
            {
                Height = geometrySize.Height;
            }

            if (width > geometrySize.Width && Height > geometrySize.Height)
            {
                return geometrySize;
            }

            return new Size(width, Height);
        }

        protected override Size ArrangeOverride(Size finalSize)
        {
            AdjustTextGeometry(finalSize);
            return finalSize;
        }

        protected override void OnRender(DrawingContext drawingContext)
        {
            if (RenderHighlight)
            {
                drawingContext.DrawGeometry(Fill, GetPen(), TextHighlightGeometry);
            }

            drawingContext.DrawGeometry(Fill, GetPen(), TextGeometry);
        }

        protected virtual void AdjustTextGeometry(Size arrangedSize)
        {
            Size geometrySize = GetNaturalSize();
            Double aspectRatio = geometrySize.Width / geometrySize.Height;
            Double scaleX = arrangedSize.Width / geometrySize.Width;
            Double scaleY = arrangedSize.Height / geometrySize.Height;
            ScaleTransform scaleTransform = new ScaleTransform(scaleX, scaleY, 0, 0);
            TextGeometry.Transform = scaleTransform;
            if (RenderHighlight)
            {
                TextHighlightGeometry.Transform = scaleTransform;
            }
        }

        protected virtual void EnsureTextGeometry()
        {
            FlowDirection flowDirection = Thread.CurrentThread.CurrentUICulture.TextInfo.IsRightToLeft ? FlowDirection.RightToLeft : FlowDirection.LeftToRight;
            formattedText = new FormattedText(
                Text,
                Thread.CurrentThread.CurrentUICulture,
                flowDirection,
                new Typeface(FontFamily, FontStyle, FontWeight, FontStretch, new FontFamily("Segeo UI")),
                FontSize,
                Brushes.Black);

            base.SetValue(TextGeometryPropertyKey, formattedText.BuildGeometry(new Point(0, 0)));
            if (RenderHighlight)
            {
                base.SetValue(TextHighlightGeometryPropertyKey, formattedText.BuildHighlightGeometry(new Point(0, 0)));
            }
        }

        private static Boolean IsValidFontFamily(Object value)
        {
            FontFamily fontFamily = value as FontFamily;
            return (fontFamily != null);
        }

        private Size GetNaturalSize()
        {
            Geometry definingGeometry = RenderHighlight ? TextHighlightGeometry : TextGeometry;
            Pen pen = this.GetPen();
            Rect rect = definingGeometry.GetRenderBounds(pen);
            return new Size(Math.Max(rect.Right, 0), Math.Max(rect.Bottom, 0));
        }

        private Pen GetPen()
        {
            return new Pen(this.Stroke, this.StrokeThickness);
        }
    }
}

 

And here is a little programme which demonstrates how to use this custom control:

<Window x:Class="OutlinedTextDemo.Window1"
   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   xmlns:cc="clr-namespace:Sheva.Windows.Controls"
  
Title="OutlinedTextDemo"
    >
  <
DockPanel>
    <
CheckBox DockPanel.Dock="Top" Content="Render Highlight" Name="checkBox"/>
    <
cc:OutlinedText
    
Margin="5"
     
Text="OutlinedText"
     
FontFamily="Vineta BT"
     
FontSize="108"
     
FontWeight="Bold"
     
StrokeThickness="4"
      Fill="Gold"
      Stroke="Green"
      RenderHighlight="{Binding Path=IsChecked, ElementName=checkBox}"/>
  </
DockPanel>
</
Window>

  After compiling and running the above code, you should see something like the following:

Longest Method Name In .NET Framework

There is a method called GetTextEffectCharacterIndexFromTextSourceCharacterIndex under System.Windows.Media.TextFormatting.TextSource which counts 55 in character length, I guess this is the lengthiest method name in .NET Framework, Sounds like that the Framework Design Guidelines actually encourage this kind of naming practice:)