Archive

Posts Tagged ‘MoXAML’

Adding to MoXAML.

September 13, 2011 1 comment

In my last post, I talked about the enhancements and new architecture I have put into place for the new version of MoXAML Power Toys. I also mentioned that I’d talk about adding a new command. Well, in this post I’m going to cover how I coded the Scrubber command that’s available in the new version.

One of the first things I did was break the Scrubber options from the actual Scrubber command. By doing this, the user no longer needs to set the options every time they need to run Scrubber. So, I created a traditional model for the options which could be used by the Scrubber commands and the Scrubber options dialog. This model looks like this:

using System.ComponentModel;
using System.IO;
using System.IO.IsolatedStorage;
using System.Linq;

namespace MoXAML.Scrubber.Model
{
    public class ScrubberOptionsModel : INotifyPropertyChanged
    {
        private const string FILENAME = "MoXAMLSettings.dat";

        private int _attributeCountTolerance = 3;
        private bool _reorderAttributes = true;
        private bool _reducePrecision = true;
        private int _precision = 3;
        private bool _removeCommonDefaults = true;
        private bool _forceLineMinimum = true;
        private int _spaceCount = 2;
        private bool _convertTabsToSpaces = true;

        public ScrubberOptionsModel()
        {
            LoadModel();
        }

        public bool ConvertTabsToSpaces
        {
            get
            {
                return _convertTabsToSpaces;
            }
            set
            {
                if (_convertTabsToSpaces == value) return;
                _convertTabsToSpaces = value;
                OnChanged("ConvertTabsToSpaces");
            }
        }

        public int SpaceCount
        {
            get
            {
                return _spaceCount;
            }
            set
            {
                if (_spaceCount == value) return;
                _spaceCount = value;
                OnChanged("SpaceCount");
            }
        }

        public bool ForceLineMinimum
        {
            get
            {
                return _forceLineMinimum;
            }
            set
            {
                if (_forceLineMinimum == value) return;
                _forceLineMinimum = value;
                OnChanged("ForceLineMinimum");
            }
        }

        public bool RemoveCommonDefaults
        {
            get
            {
                return _removeCommonDefaults;
            }
            set
            {
                if (_removeCommonDefaults == value) return;
                _removeCommonDefaults = value;
                OnChanged("RemoveCommonDefaults");
            }
        }

        public int Precision
        {
            get
            {
                return _precision;
            }
            set
            {
                if (_precision == value) return;
                _precision = value;
                OnChanged("Precision");
            }
        }

        public bool ReducePrecision
        {
            get
            {
                return _reducePrecision;
            }
            set
            {
                if (_reducePrecision == value) return;
                _reducePrecision = value;
                OnChanged("ReducePrecision");
            }
        }

        public bool ReorderAttributes
        {
            get
            {
                return _reorderAttributes;
            }
            set
            {
                if (_reorderAttributes == value) return;
                _reorderAttributes = value;
                OnChanged("ReorderAttributes");
            }
        }

        public int AttributeCountTolerance
        {
            get { return _attributeCountTolerance; }
            set
            {
                if (_attributeCountTolerance == value) return;
                _attributeCountTolerance = value;
                OnChanged("AttributeCountTolerance");
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        private void OnChanged(string propertyName)
        {
            var handler = PropertyChanged;
            if (handler == null) return;
            handler(this, new PropertyChangedEventArgs(propertyName));
        }

        private void LoadModel()
        {
            using (IsolatedStorageFile file = IsolatedStorageFile.GetUserStoreForAssembly())
            {
                if (file.GetFileNames(FILENAME).Count() == 0) return;

                using (IsolatedStorageFileStream stream = new IsolatedStorageFileStream(FILENAME, System.IO.FileMode.Open, file))
                {
                    using (StreamReader sr = new StreamReader(stream))
                    {
                        _attributeCountTolerance = ConvertInt(sr.ReadLine());
                        _reorderAttributes = ConvertBool(sr.ReadLine());
                        _reducePrecision = ConvertBool(sr.ReadLine());
                        _precision = ConvertInt(sr.ReadLine());
                        _removeCommonDefaults = ConvertBool(sr.ReadLine());
                        _forceLineMinimum = ConvertBool(sr.ReadLine());
                        _spaceCount = ConvertInt(sr.ReadLine());
                        _convertTabsToSpaces = ConvertBool(sr.ReadLine());
                    }
                }
            }
        }

        public void SaveModel()
        {
            using (IsolatedStorageFile file = IsolatedStorageFile.GetUserStoreForAssembly())
            {
                using (IsolatedStorageFileStream stream = new IsolatedStorageFileStream(FILENAME, System.IO.FileMode.Create, file))
                {
                    using (StreamWriter sr = new StreamWriter(stream))
                    {
                        sr.WriteLine(_attributeCountTolerance);
                        sr.WriteLine(_reorderAttributes);
                        sr.WriteLine(_reducePrecision);
                        sr.WriteLine(_precision);
                        sr.WriteLine(_removeCommonDefaults);
                        sr.WriteLine(_forceLineMinimum);
                        sr.WriteLine(_spaceCount);
                        sr.WriteLine(_convertTabsToSpaces);
                    }
                }
            }
        }

        private int ConvertInt(string value)
        {
            int retVal = 0;
            if (int.TryParse(value, out retVal))
            {
                return retVal;
            }
            return 0;
        }

        private bool ConvertBool(string value)
        {
            bool retVal = false;
            if (bool.TryParse(value, out retVal))
            {
                return retVal;
            }
            return false;
        }
    }
}

As you can see, there’s nothing remarkable about it. It’s a straightforward model implementation, and there’s nothing special about using this inside MoXAML (the point I’m making here is that you can mix and match your MoXAML implementation with standard .NET code).

OK Pete, let’s have a look at actually hooking this into MoXAML. Well, as I mentioned in the MoXAML page, I wanted to have two versions of Scrubber, one for the current file and one for the project files. In order to do this, it made sense to pull the core Scrubber functionality into a base class which the actual commands would hook into:

using MoXAML.Infrastructure;
using MoXAML.Scrubber.Model;
using System.IO;
using System.Xml;
using System.Collections.Generic;
using System;
namespace MoXAML.Scrubber
{
    public partial class ScrubberCommandBase : CommandBase
    {
        private ScrubberOptionsModel _model;
        public ScrubberCommandBase() : base()
        {
            _model = new ScrubberOptionsModel();
        }

        protected void ParseFile(string file)
        {
            string text = File.ReadAllText(file);
            text = Perform(text);
            File.WriteAllText(file, text);
        }

        private string Perform(string text)
        {
            text = Indent(text);
            return ReducePrecision(text);
        }

        private string IndentString
        {
            get
            {
                if (_model.ConvertTabsToSpaces)
                {
                    string spaces = string.Empty;
                    spaces = spaces.PadRight(_model.SpaceCount, ' ');

                    return spaces;
                }
                else
                {
                    return "\t";
                }
            }
        }

        private string ReducePrecision(string s)
        {
            string old = s;

            if (_model.ReducePrecision)
            {
                int begin = 0;
                int end = 0;

                while (true)
                {
                    begin = old.IndexOf('.', begin);
                    if (begin == -1) break;

                    // get past the period
                    begin++;

                    for (int i = 0; i < _model.Precision; i++)
                    {
                        if (old[begin] >= '0' && old[begin] <= '9') begin++;
                    }

                    end = begin;

                    while (end < old.Length && old[end] >= '0' && old[end] <= '9') end++;

                    old = old.Substring(0, begin) + old.Substring(end, old.Length - end);

                    begin++;
                }
            }

            return old;
        }

        public string Indent(string s)
        {
            string result;

            s = s.Replace("&", "¬¬");
            using (MemoryStream ms = new MemoryStream(s.Length))
            {
                using (StreamWriter sw = new StreamWriter(ms))
                {
                    sw.Write(s);
                    sw.Flush();

                    ms.Seek(0, SeekOrigin.Begin);

                    using (StreamReader reader = new StreamReader(ms))
                    {
                        XmlReaderSettings settings = new XmlReaderSettings();
                        settings.CheckCharacters = false;
                        settings.ConformanceLevel = ConformanceLevel.Auto;
                        //XmlReader xmlReader = XmlReader.Create(reader.BaseStream, settings);
                        XmlTextReader xmlReader = new XmlTextReader(reader.BaseStream);
                        xmlReader.Normalization = false;
                        xmlReader.Read();
                        xmlReader.Normalization = false;

                        string str = "";

                        while (!xmlReader.EOF)
                        {
                            string xml;
                            int num;
                            int num6;
                            int num7;
                            int num8;

                            switch (xmlReader.NodeType)
                            {
                                case XmlNodeType.Element:
                                    xml = "";
                                    num = 0;
                                    goto Element;

                                case XmlNodeType.Text:
                                    {
                                        string str4 = xmlReader.Value.Replace("&", "&").Replace("<", "<").Replace(">", ">").Replace("\"", """);
                                        str = str + str4;
                                        xmlReader.Read();
                                        continue;
                                    }
                                case XmlNodeType.ProcessingInstruction:
                                    xml = "";
                                    num7 = 0;
                                    goto ProcessingInstruction;

                                case XmlNodeType.Comment:
                                    xml = "";
                                    num8 = 0;
                                    goto Comment;

                                case XmlNodeType.Whitespace:
                                    {
                                        xmlReader.Read();
                                        continue;
                                    }
                                case XmlNodeType.EndElement:
                                    xml = "";
                                    num6 = 0;
                                    goto EndElement;

                                default:
                                    goto Other;
                            }

                        Label_00C0:
                            xml = xml + IndentString;
                            num++;

                        Element:
                            if (num < xmlReader.Depth)
                            {
                                goto Label_00C0;
                            }

                            string elementName = xmlReader.Name;

                            string str5 = str;
                            str = str5 + "\r\n" + xml + "<" + xmlReader.Name;
                            bool isEmptyElement = xmlReader.IsEmptyElement;

                            if (xmlReader.HasAttributes)
                            {
                                // construct an array of the attributes that we reorder later on
                                List<AttributeValuePair> attributes = new List<AttributeValuePair>(xmlReader.AttributeCount);

                                for (int k = 0; k < xmlReader.AttributeCount; k++)
                                {
                                    xmlReader.MoveToAttribute(k);

                                    string value = xmlReader.Value;

                                    if (_model.RemoveCommonDefaults)
                                    {
                                        if (!AttributeValuePair.IsCommonDefault(elementName, xmlReader.Name, value))
                                        {
                                            attributes.Add(new AttributeValuePair(elementName, xmlReader.Name, value));
                                        }
                                    }
                                    else
                                    {
                                        attributes.Add(new AttributeValuePair(elementName, xmlReader.Name, value));
                                    }
                                }

                                if (_model.ReorderAttributes)
                                {
                                    attributes.Sort();
                                }

                                xml = "";
                                string str3 = "";
                                int depth = xmlReader.Depth;

                                //str3 = str3 + IndentString;

                                for (int j = 0; j < depth; j++)
                                {
                                    xml = xml + IndentString;
                                }

                                foreach (AttributeValuePair a in attributes)
                                {
                                    string str7 = str;

                                    if (attributes.Count > _model.AttributeCountTolerance && !AttributeValuePair.ForceNoLineBreaks(elementName))
                                    {
                                        // break up attributes into different lines
                                        str = str7 + "\r\n" + xml + str3 + a.Name + "=\"" + a.Value + "\"";
                                    }
                                    else
                                    {
                                        // attributes on one line
                                        str = str7 + " " + a.Name + "=\"" + a.Value + "\"";
                                    }
                                }

                            }
                            if (isEmptyElement)
                            {
                                str = str + "/";
                            }
                            str = str + ">";
                            xmlReader.Read();
                            continue;
                        Label_02F4:
                            xml = xml + IndentString;
                            num6++;
                        EndElement:
                            if (num6 < xmlReader.Depth)
                            {
                                goto Label_02F4;
                            }
                            string str8 = str;
                            str = str8 + "\r\n" + xml + "</" + xmlReader.Name + ">";
                            xmlReader.Read();
                            continue;
                        Label_037A:
                            xml = xml + "    ";
                            num7++;
                        ProcessingInstruction:
                            if (num7 < xmlReader.Depth)
                            {
                                goto Label_037A;
                            }
                            string str9 = str;
                            str = str9 + "\r\n" + xml + "<?Mapping " + xmlReader.Value + " ?>";
                            xmlReader.Read();
                            continue;

                        Comment:

                            if (num8 < xmlReader.Depth)
                            {
                                xml = xml + IndentString;
                                num8++;
                            }
                            str = str + "\r\n" + xml + "<!--" + xmlReader.Value + "-->";

                            xmlReader.Read();
                            continue;

                        Other:
                            xmlReader.Read();
                        }

                        xmlReader.Close();

                        result = str;
                    }
                }
            }
            return result.Replace("¬¬", "&");

        }

        private class AttributeValuePair : IComparable
        {
            public string Name = "";
            public string Value = "";
            public AttributeType AttributeType = AttributeType.Other;

            public AttributeValuePair(string elementname, string name, string value)
            {
                Name = name;
                Value = value;

                // compute the AttributeType
                if (name.StartsWith("xmlns"))
                {
                    AttributeType = AttributeType.Namespace;

                }
                else
                {
                    switch (name)
                    {
                        case "Key":
                        case "x:Key":
                            AttributeType = AttributeType.Key;
                            break;

                        case "Name":
                        case "x:Name":
                            AttributeType = AttributeType.Name;
                            break;

                        case "x:Class":
                            AttributeType = AttributeType.Class;
                            break;

                        case "Canvas.Top":
                        case "Canvas.Left":
                        case "Canvas.Bottom":
                        case "Canvas.Right":
                        case "Grid.Row":
                        case "Grid.RowSpan":
                        case "Grid.Column":
                        case "Grid.ColumnSpan":
                            AttributeType = AttributeType.AttachedLayout;
                            break;

                        case "Width":
                        case "Height":
                        case "MaxWidth":
                        case "MinWidth":
                        case "MinHeight":
                        case "MaxHeight":
                            AttributeType = AttributeType.CoreLayout;
                            break;

                        case "Margin":
                        case "VerticalAlignment":
                        case "HorizontalAlignment":
                        case "Panel.ZIndex":
                            AttributeType = AttributeType.StandardLayout;
                            break;

                        case "mc:Ignorable":
                        case "d:IsDataSource":
                        case "d:LayoutOverrides":
                        case "d:IsStaticText":

                            AttributeType = AttributeType.BlendGoo;
                            break;

                        default:
                            AttributeType = AttributeType.Other;
                            break;
                    }
                }
            }

            #region IComparable Members

            public int CompareTo(object obj)
            {
                AttributeValuePair other = obj as AttributeValuePair;

                if (other != null)
                {
                    if (this.AttributeType == other.AttributeType)
                    {
                        // some common special cases where we want things to be out of the normal order

                        if (this.Name.Equals("StartPoint") && other.Name.Equals("EndPoint")) return -1;
                        if (this.Name.Equals("EndPoint") && other.Name.Equals("StartPoint")) return 1;

                        if (this.Name.Equals("Width") && other.Name.Equals("Height")) return -1;
                        if (this.Name.Equals("Height") && other.Name.Equals("Width")) return 1;

                        if (this.Name.Equals("Offset") && other.Name.Equals("Color")) return -1;
                        if (this.Name.Equals("Color") && other.Name.Equals("Offset")) return 1;

                        if (this.Name.Equals("TargetName") && other.Name.Equals("Property")) return -1;
                        if (this.Name.Equals("Property") && other.Name.Equals("TargetName")) return 1;

                        return Name.CompareTo(other.Name);
                    }
                    else
                    {
                        return this.AttributeType.CompareTo(other.AttributeType);
                    }
                }

                return 0;
            }

            public static bool IsCommonDefault(string elementname, string name, string value)
            {

                if (
                    (name == "HorizontalAlignment" && value == "Stretch") ||
                    (name == "VerticalAlignment" && value == "Stretch") ||
                    (name == "Margin" && value == "0") ||
                    (name == "Margin" && value == "0,0,0,0") ||
                    (name == "Opacity" && value == "1") ||
                    (name == "FontWeight" && value == "{x:Null}") ||
                    (name == "Background" && value == "{x:Null}") ||
                    (name == "Stroke" && value == "{x:Null}") ||
                    (name == "Fill" && value == "{x:Null}") ||
                    (name == "Visibility" && value == "Visible") ||
                    (name == "Grid.RowSpan" && value == "1") ||
                    (name == "Grid.ColumnSpan" && value == "1") ||
                    (name == "BasedOn" && value == "{x:Null}") ||
                    (elementname != "ColumnDefinition" && elementname != "RowDefinition" && name == "Width" && value == "Auto") ||
                    (elementname != "ColumnDefinition" && elementname != "RowDefinition" && name == "Height" && value == "Auto")

                    )
                {
                    return true;
                }

                return false;
            }

            public static bool ForceNoLineBreaks(string elementname)
            {
                if (
                    (elementname == "RadialGradientBrush") ||
                    (elementname == "GradientStop") ||
                    (elementname == "LinearGradientBrush") ||
                    (elementname == "ScaleTransfom") ||
                    (elementname == "SkewTransform") ||
                    (elementname == "RotateTransform") ||
                    (elementname == "TranslateTransform") ||
                    (elementname == "Trigger") ||
                    (elementname == "Setter")
                    )
                {
                    return true;
                }
                else
                {
                    return false;
                }

            }

            #endregion
        }

        // note that these are declared in priority order for easy sorting
        private enum AttributeType
        {
            Key = 10,
            Name = 20,
            Class = 30,
            Namespace = 40,
            CoreLayout = 50,
            AttachedLayout = 60,
            StandardLayout = 70,
            Other = 1000,
            BlendGoo = 2000
        }
    }
}

I appreciate that this is a long listing, but don’t worry about what’s going on inside. To hook into the MoXAML plugin architecture, only one line in there is really important:to be picked up

public partial class ScrubberCommandBase : CommandBase

By inheriting from CommandBase, MoXAML picks the command up because CommandBase implements ICommandBase. The cunning thing about MoXAML is that it uses MEF which allows you to mark interfaces so that any implementations of the interface will automatically be picked up. Well, we have most of the infrastructure in place – all we actually need to do is write the actual command. You’ll be surprised how little that actually takes:

using MoXAML.Infrastructure;

namespace MoXAML.Scrubber
{
    public class ScrubFileCommand : ScrubberCommandBase
    {
        public ScrubFileCommand()
            : base()
        {
            CommandName = "ScrubFile";
            Caption = "Scrubber";
            ParentCommandBar.Add(CommandBarType.XamlContextMenu);
        }

        public override void Execute()
        {
            base.Execute();
            ParseFile(Application.ActiveDocument.FullName);
        }
    }
}

Let’s break it down. In the constructor, we’re giving the command a unique name that MoXAML uses to track whether or not the command was previously installed. The Caption is what will actually appear in the menu, and the line ParentCommandBar.Add is used to add the command to the appropriate menu.

Finally, we actually need our command to do something, and that’s where the Execute method comes in – MoXAML uses this method to execute the command, so it’s the place to hook our command logic to. In this case, we’re hooking into the ParseFile method in the class we inherit from.

MoXAML goes MefXAML

September 6, 2011 1 comment

First of all, I must apologise that it’s taken me so long to release the new version of MoXAML. Unfortunately it’s taken a back burner to other projects that I have going on, so it’s been lower down on my priority list than I would have liked. Saying that, I have been tinkering with a new version and making changes to the internal architecture to make it easier for me to add new functionality to it. MoXAML has now got the MEF mojo underpinning it.

A feature of the original version of MoXAML that I was never happy with was the way I had to register commands so that they will appear in the menus. To be honest, the code was a complete mess and it offended my sensibilities whenever I looked at it. Well, the new version has completely changed that. I’ve added a MoXAML.Infrastructure library that provides a lot of the underpinnings of MoXAML registration; all we need to do is derive from the CommandBase class in this library and with just a couple of commands we are good to go.

First of all, we need to add a unique command name, the menu text and the parent command that we want to show this command in. This just gets added into the constructor likes so:

public MyConstructor()
{
  CommandName = "MyUniqueCommandName";
  Caption = "Menu text";
  ParentCommandBar.Add(CommandBarType.SolutionContextMenu);
}

Now, to add the code to actually do the work, just override the Execute method and add in the functionality that you want to perform.

In a future post, I’ll cover creating an add-in from scratch and talk about the API that’s now been exposed in MoXAML. To get the latest version of MoXAML, please check it out here.

Categories: MoXAML Tags: ,

MoXAML 2.4 Released

February 22, 2009 2 comments

I’ve just uploaded the newest version of MoXAML Power Toys. MoXAML now includes a version of Scrubber that runs inside Visual Studio – Scrubber was introduced to the world by Robby Ingebretsen in his wonderful Kaxaml tool. Go on – beautify all the XAML in your projects with one simple menu option.

MoXAML 2.1 Released – AKA Iona

October 15, 2008 5 comments

I’ve just finished coding up a new version of MoXAML Power Toys. This release adds a new keyword search function and tidies up the commenting functionality based on feedback.

Keyword search

Highlight a word in the source and select Lookup keyword from the menu, and voila – a Google and Live search are performed based on the keyword (using the appropriate language type as well).

Menu in action

Search window in operation

Commenting

The comment feature now places nicely with the existing comment command, so if you have an ordinary XAML comment in place, running the MoXAML commenter on it will handle it just as if the original comment had been done with MoXAML.

Another new feature in the Commenter is the ability to add an empty <!– –> comment so you can add your own comment text in.

Downloads

After downloading, you’ll need to change the extension from .doc to .zip. This is a requirement of WordPress.com

Installer – no source: moxaml21releasezip

Source code: moxamlpowertoys21zip

As always, keep your comments and requests coming in. No idea goes unconsidered.

XAML Power Toys & MoXAML – the one-two knockout punch.

October 10, 2008 6 comments

In this post, I’d like to talk about how MoXAML and XAML Power Toys can work together to produce applications quickly and easily. We’re going to look at how to create a working fully databound datagrid in Silverlight, in 1 minute.

Important note:
If you’re running Visual Studio on Vista, please run it as Administrator to follow this tutorial.

So, now that we know what we’re trying to do, let’s start off by creating a Silverlight application in Visual Studio 2008. For this run through, we need to use C# because we are going to use the Notify Property command which works against automatic properties, which are only a feature of C# (unfortunately). For this sample, I’m adding a new ASP.NET web project to host Silverlight, and I’ve set the Project Type to ASP.NET Web Application Project.

Right, now that we’ve created the basic application, we’re going to add a new class to the Silverlight control project which will be the model we’re planning on adding. Normally, we’d create a new DLL for the model, but for the sake of simplicity I’m adding it directly to the control. I’m calling this class Person, and it will consist of 4 properties; Title, Name, Age and Nickname. The class looks like this:

Now, we want to convert the class so that the properties use the PropertyChanged event handler. To do this, I’m going to add the INotifyPropertyChanged interface to the class definition and then implement the interface. (You will need to add using System.ComponentModel; to your class). At this stage, the class looks like:

The problem with the code as it stands is that it won’t properly participate in databinding, because it’s not going to notify bound items of any changes. That’s where the PropertyChanged event comes in. I love automatic properties, but I was so frustrated that they didn’t internally implement this – this was the reason that I wrote the Notify Property command. So, it’s time to fire up MoXAML and rectify the “deficiencies”.

Note:
Before you continue, it’s important to make sure that you have the latest versions of XAML Power Toys and MoXAML Power Toys, and that they are running as an add-in in Visual Studio.

Right click on the Name property and click MoXAML Power Toys > Make Notify Property from the menu. This adds the necessary “plumbing” to make this a notify property.

MoXAML menu

MoXAML converted code

Repeat this with the other properties, to add the relevant implementation into each property. Now we’re going to move onto the Silverlight control. At this stage, it is vital that you build your project, and ensure that it compiles successfully because XAML Power Toys uses reflection to work out what is available in your class.

Once you’ve built the project, right click on the class in the solution explorer and choose XAML Power Toys > Create Form, ListView or Data Grid For Class. When the dialog appears, choose Silverlight Data Grid in the Select Object To Create dropdown.

XAML Power Toys form in action.

Now, we can drag and drop the items we want to appear in the grid. I’m going to add them in the order Title, Name, Nickname and Age. For more information on the template items available in the dialog, please see the videos that Karl has most helpfully produced, but for the moment, please ensure that the mode is set to TwoWay for each item.

Items being added to the datagrid.

Once you’ve added the fields you want, click Create. If this is the first time you’ve used XAML Power Toys, you should see an information box with the message: “Your settings file has been created for you. You can configure your settings using the Set Control Defaults command.” Click OK.

You’ll now see an information box that tells you that you can now paste your XAML in.

Once you’ve pasted your grid into the Page.xaml file, you may notice that the DataGrid has lots of wavy underlines. This is because the System.Windows.Controls.Data assembly isn’t referenced in your project, and the namespace hasn’t been added to the UserControl attributes. To fix this, add the reference into your project, and copy the definition xmlns:data=”clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data” into the UserControl attributes.

We’re going to give our datagrid a name. Let’s call it xamlGrid. To do this, add x:Name=”xamlGrid” to the datagrid. We have done this so that we can hook the grid up with some data. So now, let’s add the Loaded event to our usercontrol. To do this, add Loaded=”UserControl_Loaded” into the control definition (if you type Loaded= into Visual Studio, and press enter when the <New Event Handler> is highlighted, the event handler is added into both the XAML and the codebehind.

Now, open up Page.xaml.cs and take a look at the code. The UserControl_Loaded handler should be present, and hooks up to a RoutedEvent. It’s now time to add some data and bind it in. First of all, let’s add a list of Person objects as a class member. Once this has been done, add in some code to add new Person items to the list and then bind the list to the datagrid ItemsSource. Here’s my code:

If you build and run this project, you’ve got a fully databound grid which displays the items you entered. Change some values, and the properties update as you’d expect. If you want to test this, and I strongly suggest you do because it’s so cool, create a copy of your first grid in the XAML, change it’s name and bind it to the same list. Rerun the project, and change a value in one of the grids – if you’ve done everything right, the other grid will display your updated values.

That’s all there is to getting started with using MoXAML and XAML Power Toys to quickly create a databound Silverlight application. It really is that easy, and I’d like to thank Karl for his hard work in making it so that it is that easy.

Download

You can download the sample here. As always, you’ll need to rename the .doc file to .zip before you can extract it.

samplesilverlightappzip

MoXAML 2.0 Released.

October 7, 2008 8 comments

Well – it’s taken me quite a while, but I’ve finally finished the new version of MoXAML Power Toys. This has been quite an undertaking, and has been the most fun I’ve had coding in quite a while. Anyway, what’s new in MoXAML?

AppWizard

As I’ve already intimated, there’s a new AppWizard in MoXAML. This command allows you to add a status bar, toolbar and menu to your application.

Calling the AppWizard

The AppWizard brings up a dialog where you choose whether or not you want to see a toolbar, a menu or a statusbar. If you choose to add a toolbar or menu, you even get standard icons added into your project. The CommandBindings and App.Resources are set up for you, and the relevant user controls are added into your main window. The statusbar hooks up to the Caps Lock, Scroll Lock, Insert and Num Lock keys to reflect the state of them. It also adds in a date and time which updates every second. I love WPF.

The AppWizard in action

The AppWizard in action

Behind the scenes, some of the code injected into your application is C#, but being a nice chap I’ve added a converter in there which translates the C# to VB.NET before it gets added to your project if it detects that your project is VB.NET.

I’ve tested this as well as I can, but I’d appreciate feedback on how you find it.

DependencyProperty

I’d like to thank Jeremy Robertson, aka Hero, for this one. A couple of weeks back he emailed me to say that he’d come up with an addition to MoXAML, and he sent me the code for the DependencyProperty command. In his own words:

“It’s similar to PropertyManager, except it works on Dependency Properties.
Highlight a group of dependency properties, run the tool, and it will put CLR properties for each dependency property on the clipboard.”

Thanks for that Jeremy – it’s much appreciated.

Downloads

Downloads available here.

Next steps

Well, the next step for me is to produce detailed instructions on how to use MoXAML and XAML Power Toys together to produce a Silverlight application. It’s pretty powerful stuff, and I owe a great debt of gratitude to Karl Shifflett for XAML Power Toys. When you see the combination in action, you can see why we’re doing this.

Beyond that, I’m going to be revisiting the commenting code as per Logan’s requests, and I’m also going to be adding in a new command to convert code from one language to another. Another feature on my wishlist that I’ll be looking at soon is selecting a keyword in your source or XAML and then it will search Google, Live, and so on, to get you help on the keyword.

As always, keep your comments coming in and thanks for your feedback so far.

Parsing XAML woes

October 2, 2008 Leave a comment

So, I’ve been sitting here for a couple of hours trying to figure out why the following XML query didn’t actually work when parsing my XAML for the following item:

<Image Height=”16″ Width=”16″ Source=”Images/MyImage.png” x:Key=”CommandNew” />

Query:

//Application.Resources/Image[@Key=’CommandNew’]

The XAML loaded into an XML document just fine. It’s well formed, and the Image item does exist inside the Application.Resources section. I just couldn’t figure out what the heck was going on. Then, it hit me – in a flash of the blinding, bleeding obvious. These tags don’t actually exist on their own. They are part of the XAML namespaces, which opens up a whole new line of things you need to do. Basically, in order to perform this query, I needed to import the same XAML namespaces into my XML document – and then I should be good to go. Right?

Well, not quite. The above query also needs to change slightly. Without, the namespaces in, this query still doesn’t work. So the first thing we need to do is add the namespaces into the query and we get:

//presentation:Application.Resources/presentation:Image[@xaml:Key=’CommandNew’]

and the code to load the namespaces in:

private static XmlNamespaceManager GetNamespace(XmlDocument doc)
{
 
XmlNamespaceManager mgr = new XmlNamespaceManager(doc.NameTable);
  mgr.AddNamespace(
“presentation”, http://schemas.microsoft.com/winfx/2006/xaml/presentation);
  mgr.AddNamespace(
“xaml”, http://schemas.microsoft.com/winfx/2006/xaml);
  return mgr;
}

Note how the namespaces need to prefix each item in the query. It doesn’t matter what we call them because they are mapped over to the relevant namespace as appropriate – the important thing is the Uri, not the name.

There, now we can query our XAML to our hearts content. I hope this has been of some benefit to you because it was really bugging me.;->

 

 

The Canny Coder

Java 8 Functional Programming with Lambda Expressions

pihole.org

Adventures in theoretical computer science, with your host, chaiguy1337

Confessions of a coder

Confessions of a WPF lover

WordPress.com

WordPress.com is the best place for your personal blog or business site.

Follow

Get every new post delivered to your Inbox.

Join 38 other followers