Welcome to WindowsClient.net | Sign in | Join

Rob Relyea - XAMLified

WPF, Silverlight and XAML

January 2010 - Posts

Pausing to think about next steps after making strong progress in the “Exploring: XamlPad to XamlDesigner” journey in the last 10 days. 3 major things from that Exploring post that haven’t been tackled in XamlPadSample include: Silverlight support, Designer support, and Editor richness.

I’m going to explore Designer support options with this post.

I had originally sketched out this area as:

XAML Step: PropertyGrid, Selection Model, SourcePreservation

  • Simple Property Grid
  • Selection model enabling selection in View surface or Xaml editor, and synchronized editor.
  • Source preservation of XAML with XamlDom based store

But now I’m realizing there may be a few different directions that people may want. This may be because different domains (UI, Workflow, etc…) or different users types (UI Developers, UI Designers, WorkFlow modelers, etc…).

Approaches to XamlDesign Surfaces

View only – never show XAML

A customer recently asked an associate of mine for a WPF hostable designer with a View Only Design surface. This would require a toolbox, interactions to add, move and remove controls, and ability to change values (either with a property grid or “on object” manipulations). Source code preservation may or may not be important in this scenario. Should XML comments be preserved? How about white space?

View or XAML – but never both at the same time

In VS2010 & .NET 4, Windows Workflow Foundation (WF) provides this View or XAML design experience.

View and/or XAML - splitview with interactive view

VS (via “Cider”) and Blend both offer a fully functional split view, with an interactive design canvas + property grid, and an editable XAML pane.

XAML with Preview

XamlPads offer a View which is a preview mode, and an editable XAML pane.

XAML Only

This sounds like notepad. :-) (but maybe you could have notepad with intellisense)

What is your ideal? For UI, workflow, data, other?

Would love to hear thoughts on these various approaches. 

For UI, is splitview the preferred model for devs and designers? Or does the XamlPad approach (XAML with Preview) have merit?

For Workflow, are people happy with View or XAML, but never both at the same time?

Any thoughts or feedback in this space?

Posted by Rob_Relyea | 6 comment(s)
Filed under: ,

3 major features added to XamlPadSample today! Including Alternate Views, which has not been done in any XamlPad or XamlDesigner that I’m aware of. (link to previous posts/overview & sample code available via XamlPadSample)

App.xaml Support for {StaticResource}

View pane now shows result of {StaticResource} or {DynamicResource} resolution of resources from app.xaml. Shown loading Welcome.xaml from Family.Show v3.

image

 

Assembly Loading

XAML files which include uses of classes from local: or other custom types in project class libraries now load. Shown loading PersonInfo.xaml from Family.Show v3. (note, XamlPadSample doesn’t ever call build on your project/solution.)

image

 

Alternate Views

The AlternateViews feature enables you to put something more useful in the “white blank pane” of a non-UI rooted XAML file.

Below you can see a crude UI representation of BlackResources (from Family.Show v3) showing many brushes, DataTemplates, Styles that were defined in a ResourceDictionary.

The sample also contains a simple visual representation for App.xaml and XamlPadConfig.

image

 

Detailed notes from Backlog.txt in sample code:

---------------------------------------------
2010/01/30 - posted v1f - Alternate View, app.xaml, and assembly loading
---------------------------------------------
Implemented: {StaticResource foo} will now resolve to resources in the current page or in the ApplicationDefinition xaml file (matched Blend/Cider feature)
Implemented: Assemblies from a project will now be loaded (matches Blend/Cider/XamlCruncher feature)
Implemented: Provided the start of a mechanism to provide alternate views for non-visual root elements. Lots of potential here...

XamlPadHelpers project
•ResourceProxy.cs (NEW)
◦Added ResourceProxy, a ContentControl - to hold a pointer to the App.Resources for a project. We inject this element during the parse as the real root of the tree we are building.
  This enables {StaticResources } that we parse to find resources delared in App.xaml or in a merged dictionary as well.
•AssemblyData.cs
◦In v1e, I had plumbed this class to find the right assembly. Now there is a Load() method a property of type Assembly to store the loaded assembly.
•ProjectData.cs
◦Added a ContentProperty for <ProjectData> - the AssemblyReferences property. Doesn't change the functionality of Pad.config.xaml, just the conciseness.
◦Added an ApplicationResources property which will load the corresponding app.xaml and grab the .Resources property from it.
•View.cs (NEW)
◦New class to track a Type->TemplateUri mapping. This is effectively a Dictionary, but notice the [DictionaryKeyProperty("Type")] on the class, which enables avoiding x:Key in the XAML.
  This is the same (now v4 public feature) that Style, ControlTemplate, and DataTemplate use to avoid needing a x:Key by default.
•XamlEngine.cs
◦LoadObjectsForDesign now has an appResources property, and will inject a new ResourceProxy(appResources) as the root object in the tree if appResources is not null.
◦new LoadXamlDocument routine that will use CreateReader() and LoadObjectsForDesign()
◦new LoadXamlDocumentWIthAppResources routine that will use CreateReader() and LoadObjectsForDesign(), and it will pass in appResources into LoadObjectsForDesign if we know
  of the app.xaml
•XamlPad.xaml.cs
◦XamlText_TextChanged() enhanced to attempt to load each assembly of a project before parse.
◦XamlText_TextChanged() enhanced to wire in alternate Views (via XamlPadConfig.Views mappings) for any non-UI root objects displayed in XamlPad.
  TODO: wouldn't mine cleaning up this code...I think I changed error experience badly...
•XamlPadConfig.cs
◦Added the Views property for the alternate views feature.
•XamlPadHelpers.datatemplates.xaml (NEW)
◦Added several DataTemplates that provide basic visual representations for object graphs that have the following roots: Application, ResourceDictionary, XamlPadConfig

Pad project
•MainWindow.xaml.cs
◦Added 3 default Views to plug into the default Pad.config.xaml (for AlternateViews feature)

Posted by Rob_Relyea | 1 comment(s)

2010 continues to find Silverlight/WPF in a very good place, and the beautiful thing is that we have so many people, in Microsoft, and outside, making it better.

Reading some folks on twitter pointed me towards Karl’s blog post about d:DesignInstance and d:DesignData and ondrejsv’s post about Sample Data in Blend/SketchFlow.

Blend and VS 2010 continue to grow their capabilities to make WPF/Silverlight databinding easier. The platforms have strong features, but getting great tools magnifies the impact of a strong platform.

Meanwhile Bea Stollnitz continues to do great blogging around data binding.

While I love XAML, DataBinding is likely my favorite feature in WPF/Silverlight.

Sorry for the rambling…(but I’m happy with our progress/direction here.)

biggert posts “A few good custom WPF controls found along the way” including pointers to LinkLabels, SearchTextBox, DataGrid, SplitButton, CloseableTab (hey, I need that one), Loading animation, DockPanelSplitter

Posted by Rob_Relyea | with no comments
Filed under:

There was a “XAML Serialization” thread on Channel 9 – Coffeehouse today that had an interesting use of XAML. He was using XAML as a way to dump the state of his object graph for verification, debugging, potential transformations/exports, etc…

As such, he wanted to see some R/O properties written down in XAML, that we currently judge as not interesting to write, since they are read-only…and thus can be read back in, so why write them.

If XamlServices.Save() (or the XamlObjectReader underneath the covers) did less filtering of properties that need to be written, then you would get the goodness of seeing things in XAML-style, but have all your data. [Also Dan Glick now has shown in that thread that you could override XamlSchemaContext to solve this]

Anyway, worth thinking about…

 

[the thread also discusses immutable types and the default ctor() / non-default ctor() debate.]

Posted by Rob_Relyea | 2 comment(s)
Filed under:

Added support to store which projects each XAML file is associated with, along with app.xaml and assembly reference info. Notice that I’m using XAML2009 support for Name references in XAML. I’m able to define object graphs (not just trees) via this mechanism.

Now that we have the info from the project; next, I’ll likely wire {StaticResource foo} to look in App.xaml when needed. And perhaps we’ll try loading some of these assemblies as well.

  1. <XamlPadConfig ActiveXamlDocument="3" WindowHeight="753" WindowLeft="0" WindowTop="0" WindowWidth="927" xmlns="clr-namespace:XamlPadHelpers;assembly=XamlPadHelpers" xmlns:av="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
  2.   <XamlPadConfig.Documents>
  3.     <XamlDocumentViewModel BottomRowHeight="*" TopRowHeight="2*" XamlViewState="Xaml">
  4.       <XamlDocument FileName="C:\Users\rrelyea\Documents\Visual Studio 2010\Projects\Pad\Pad\App.xaml" Project="__ReferenceID0" />
  5.     </XamlDocumentViewModel>
  6.     <XamlDocumentViewModel BottomRowHeight="*" TopRowHeight="2*">
  7.       <XamlDocument FileName="C:\Users\rrelyea\Documents\Visual Studio 2010\Projects\Pad\Pad\MainWindow.xaml" Project="__ReferenceID0" />
  8.     </XamlDocumentViewModel>
  9.     <XamlDocumentViewModel BottomRowHeight="808.013333333333*" TopRowHeight="296.026666666667*">
  10.       <XamlDocument FileName="C:\Users\rrelyea\Documents\Visual Studio 2010\Projects\Pad\Pad\PromptForClose.xaml" Project="__ReferenceID0" />
  11.     </XamlDocumentViewModel>
  12.     <XamlDocumentViewModel BottomRowHeight="788.013333333334*" TopRowHeight="316.026666666666*">
  13.       <XamlDocument FileName="C:\Users\rrelyea\Documents\Visual Studio 2010\Projects\Pad\Pad\SettingsWindow.xaml" Project="__ReferenceID0" />
  14.     </XamlDocumentViewModel>
  15.   </XamlPadConfig.Documents>
  16.   <XamlPadConfig.Projects>
  17.     <ProjectData x:Name="__ReferenceID0" ApplicationDefinition="App.xaml" FileName="C:\Users\rrelyea\Documents\Visual Studio 2010\Projects\Pad\Pad\Pad.csproj" LocalAssembly="__ReferenceID1" TargetFrameworkIdentifier=".NETFramework">
  18.       <ProjectData.AssemblyReferences>
  19.         <AssemblyData>C:\Users\rrelyea\Documents\Visual Studio 2010\Projects\Pad\XamlPadHelpers\obj\Debug\XamlPadHelpers.dll</AssemblyData>
  20.         <AssemblyData x:Name="__ReferenceID1">C:\Users\rrelyea\Documents\Visual Studio 2010\Projects\Pad\Pad\obj\x86\Debug\Pad.exe</AssemblyData>
  21.       </ProjectData.AssemblyReferences>
  22.     </ProjectData>
  23.   </XamlPadConfig.Projects>
  24.   <UserSettings EditorFontFamily="Consolas" EditorFontSize="16">
  25.     <UserSettings.SelectionBrush>
  26.       <av:SolidColorBrush Color="#FFFFFF00" Opacity="0.75" RelativeTransform="Identity" Transform="Identity" />
  27.     </UserSettings.SelectionBrush>
  28.   </UserSettings>
  29. </XamlPadConfig>

 

[overview of project: XamlPadSample page –today’s source snapshot: 2010-01-25 Source Snapshot]

 

Details from Backlog.txt in Pad Project:

--------------------------------------------- 
2010/01/25 - posted v1e - App.xaml & Assemblies
--------------------------------------------- 
Implemented: support to store which projects each XAML file is associated with, along with app.xaml and assembly reference info.

XamlPadHelpers project
•AssemblyData.cs
◦Created this type to store the fullpath to an assembly. (it was a string first, but NameReferenceConverter on a string property didn't work like magic, so I worked around with a new type.)
◦TODO: future improvement?
•ProjectData.cs
◦Renamed "Project" class to "ProjectData" as the name conflicts with some MsBuild types, etc...
◦Added support to find ApplicationDefinition XAML file, assembly fullpaths, TargetFrameworkIdentifier, etc...
•XamlDocument.cs
◦Created a ctor that takes a XamlDocumentViewModel
◦Made the Project property be a "NameReference" property via the NameReferenceConverter.
◦Created a FindOrCreateProject() method which will find the appropriate ProjectData object or create one.
◦Created a FindProjectFile() routine which does the probing that I mentioned in v1d.
•XamlPadConfig.cs
◦Added a collection of Projects

Pad project (formerly called XamlPadSample)
•MainWindow.xaml
◦Changed title to "Pad" from "XamlPadSample"
•MainWindow.xaml.cs
◦Changed config file from "config.xaml" to "Pad.config.xaml" (pattern is appname.config.xaml for now).
◦Rewired creation of default document objects to allow backpointers from XamlDocument to XamlDocumentViewModel
◦CloseDocument() will now harvest any orphaned "ProjectDatas"

I spent another 30 minutes with Seesmic Look now, and I wrote down issues I found with the UI.

Learn more (or install): http://seesmic.com/seesmic_desktop/look/ 

As I mentioned as a tweet (http://twitter.com/rrelyea/statuses/8035779666)

image

Bunch of nits:

  • no mouse way to page up. seems like when you click the top middle section of the scrollbar, it goes up 1 item, not one page.
  • want to be able to read several items at one time.  The large font for the latest post doesn't make that easy. I don’t want to have to wait to scroll between each item.  I think I like the large font, but more experimentation should be done. (and I should try it more…it may be fine).
  • when i click on an item, the dot next to it doesn't show up.
    after that, if i key arrow up or down, then the dot shows up.
  • tweets that are marked as a favorite aren't clear enough.... perhaps a better data template when an item is already a favorite…may use “gold”….
  • clicking on “toggle favorite” moves focus from list of tweets. should be more like a toolbar.
  • doing right arrow, arrow down to favorite, space, makes it a favorite, but then left doesn't work.
  • when i navigate to a person, ( to follow them), when i go back, i loose the place in the timeline.
Overall, I think it is an interesting start…
Posted by Rob_Relyea | with no comments

My Window now works exactly like I want:

  1. remembers WindowState it was in (Maximized, Restored, Minimized, FullScreen)
  2. remembers monitor is was on
  3. remembers where to restore to.

I had to use a bit more code that I would have liked, but it all is good. (Ideally, WPF Window can be improved to make this scenario work with a bit less code. Until then, the workarounds could likely be factored into a nice attached behavior…but I’m not planning on doing that. Thanks to Joe/Eric for helping me work through those issues.)

[overview of project: XamlPadSample page –today’s source snapshot: 2010-01-24 Source Snapshot]

Update to Backlog.txt in Source:

--------------------------------------------- 
2010/01/24 - posted v1d - Window - focused on more fixes to Window remembering state
--------------------------------------------- 
Fixed: Maximized or fullscreen windows on 2nd monitor will launch on primary monitor after relaunch. (thanks Joe)

XamlPadHelpers project
•XamlPad.xaml
◦Added AcceptsTab="True" to TextBox, so I can put a tab into the textbox.
   (TODO: should I add a feature to turn a tab into spaces?)

XamlPadSample project
•MainWindow.xaml
◦Removed binding to Window.WindowState. In order to fix the maximize on 2nd monitor bug, I had to move this to code.
    (Ideally Window should have worked like I tried. Bugs are opened.)

•MainWindow.xaml.cs
◦Dealt with WindowState after the window source was initialized.
◦In closing handler, worked around issue where sometimes the saved height and width was full screen, even after I Restored the window.

Today I started to teach the XamlDocument class how to find the project that a XAML file is associated with. The technique is somewhat crude right now.

[overview of project: XamlPadSample page –today’s source snapshot: 2010-01-22 Source Snapshot]

 

I look in the XAML file’s directory for a *.*proj file, then I look in the parent directory, etc…  The first project file I find is it!

I don’t currently confirm that the project file contains a reference to the XAML file.

This is the first step to being able to find the app.xaml so we can make these things work:

  • {StaticResource someResourceInTheAppResources}
  • loading assemblies so custom components/etc… work

Coding fun still happening. Little bit each day.

Detailed changes for step 1c

XamlPadHelpers project
•XamlDocument.cs
◦Added ProjectFileName property and logic to find the associated project file. This is a step towards
  supporting resources from app.xaml and loading assemblies.
•XamlEngine.cs
◦Cleaned up implementation of swapping a proxy in for a type that is specified in XAML, but that we should avoid creating (like Window/Page/Application).
◦Moved to use xamlReader.Skip() and alreadyRead bool.  (don't like where we ended up with Skip()!..shouldn't need alreadyRead #fail).
◦Added comment about why we wrap exceptions and add line info.
•XamlPadConfig.cs
◦Cleaned up my code via feedback from Steve for how a XamlDocumentViewModel gets its parent pointer to the XamlPadConfig. (Thanks Steve!)
•XamlPad.xaml.cs
◦Added creation of Dictionary<XamlType, XamlType> proxyLookup table to this code. This uses the "cleaned up implementation" I mentioned above.

XamlPadSample project
•MainWindow.xaml.cs
◦Misc clean up.
•Backlog.txt
◦Created a file to list some known issues and change log.

 

A customer asked if it was possible, for their own XAML Vocabulary, to not write down XAML with Name="foo".  Instead they wanted to write down x:Name="foo".

Here is an example of a way to use a XAML node loop (using a XamlReader and XamlWriter together and doing custom things between the reader and writer) to do that.

using System;
using System.Collections.Generic;
using System.IO;
using System.Xaml;
 
namespace SaveXamlNodeLoopSample
{
    class Program
    {
        static void Main(string[] args)
        {
            string xamlString = "<SampleTag xmlns='clr-namespace:SaveXamlNodeLoopSample;assembly=SaveXamlNodeLoopSample' Name='someName'/>";
 
            object o = XamlServices.Parse(xamlString);
 
            XamlObjectReader xor = new XamlObjectReader(o);
            StringWriter sw = new StringWriter();
            XamlXmlWriter xxw = new XamlXmlWriter(sw, xor.SchemaContext);
 
            SaveUsingXamlName(xor, xxw);
 
            Console.WriteLine(sw.ToString());
        }
 
        private static void SaveUsingXamlName(XamlObjectReader xor, XamlXmlWriter xxw)
        {
            xxw.WriteNamespace(new NamespaceDeclaration(XamlLanguage.Xaml2006Namespace, "x"));
            Stack<XamlType> xamlTypeStack = new Stack<XamlType>();
            while (xor.Read())
            {
                bool swapMember = false;
                switch (xor.NodeType)
                {
                    case XamlNodeType.StartObject:
                        xamlTypeStack.Push(xor.Type);
                        break;
                    case XamlNodeType.GetObject:
                        xamlTypeStack.Push(null); // don't need to get the real type.
                        break;
                    case XamlNodeType.EndObject:
                        xamlTypeStack.Pop();
                        break;
                    case XamlNodeType.StartMember:
                        if (xamlTypeStack.Peek().GetAliasedProperty(XamlLanguage.Name) == xor.Member)
                        {
                            swapMember = true;
                        }
                        break;
                }
 
                if (!swapMember)
                    xxw.WriteNode(xor);
                else
                    xxw.WriteStartMember(XamlLanguage.Name);
            }
        }
    }
 
    [System.Windows.Markup.RuntimeNameProperty("Name")]
    public class SampleTag 
    {
        public string Name { get; set; }
    }
}
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }

 

If you have better ways to do this with .NET 4, or any feedback, please comment.

Posted by Rob_Relyea | 5 comment(s)
Filed under:

Enjoyed the feedback I got via blog comment/email about XamlPad/XamlDesigner. I decided today to focus on some of Mike Taulty’s feedback.

Already Done

One comment from Mike Taulty was already taken care of:

Allow for quick navigation through a set of pre-loaded files. i.e. maybe I hit the -> arrow key and the next file is loaded & displayed rather than having to drag a snippet.

You already can load a set of files with Open, close the app.  Config.xaml will now contain the list of those files. Next time you run the app, it will open those.

Pressing ctrl-tab, ctrl-shift-tab will move forward/backward through the tabs that are open.

New Stuff I Coded

In my early morning coding today, I focused on three main things:

  1. Add FullScreen mode (per Mike Taulty’s suggestion). When I did that, I realized I needed to also saving WindowState into config.xaml.
  2. Tried to start saving Selections per document, partially motivated by Mike’s request to: Make it slick to show "here's a piece of XAML I'm highlighting for you & here's its effect on-screen".
    • (TODO: need to learn how to make a WPF TextBox display its selection even after it lost focus…)
  3. Fixed a bug so that closing the window would prompt to save changed documents, just like the exit button would.

I posted XamlPadSample-2010-01-21.zip with these updates. (XamlPadSample links to all the posts/samples in this series)

Detailed change list

XamlPadHelpers project

  • XamlPadConfig.cs
    • added WindowState and WindowFullScreen properties.
  • UserSettings.cs
    • added SelectionBrush property (bound to XamlPad.xaml’s TextBox.SelectionBrush).
  • XamlDocumentViewModel.cs
    • In order to enable saving the selection per document, added SelectionStart and SelectionLength properties (with DefaultValueAttribute of 0, so they won’t get written into config.xaml unless there are non-default values).
  • XamlDocument.cs
    • Added DefaultValueAttribute(null) for ExceptionMessage to avoid ExceptionMessage=”{x:Null}” in config.xaml
  • XamlPad.xaml
    • Added to TextBox: SelectionBrush="{Binding XamlPadConfig.UserSettings.SelectionBrush}"

XamlPadSample project

  • MainWindow.xaml
    • Added to Window: WindowState="{Binding WindowState, Mode=TwoWay}"
    • Put ToolBar in ToolBarTray, added new ToolBar with FullScreen button.
  • MainWindow.xaml.cs
    • Implemented FullScreen feature
      • (todo: F11/Escape support. also would be nice to make menus/tabs potentially disappear)
    • Set UserSettings.SelectionBrush in default routine (likely need a new color…)
    • Fixed bug to make Alt-F4 or window close via X call into the same handling that the Exit button does…so it asks you to save changes.
    • When creating windows to show via ShowDialog, added Topmost = this.TopMost to work in FullScreen mode too.

XamlPadSample step 1 sample code is now available for download from http://robrelyea.com/demos/XamlPadSample/XamlPadSample-2010-01-20.zip.

It requires .NET 4 (although I’m not using Beta2, if you are still on Beta2, I think it will work. Please post questions/solutions on getting it to run on Beta2…)

Intro

Yesterday I blogged about “Exploring: XamlPad to XamlDesigner” and mentioned that I was going to post some sample code for a richer XamlPad that would take advantage of .NET 4 for new capabilities.

I’m not currently planning on making it easy to install my XamlPadSample binaries. I’d prefer to share the code, and see existing XAML Tools improve, and new ones develop where interesting. My team wants to help by providing XAML API infrastructure and samples to enable more productive uses of XAML.

XamlPadSample Step 1 – What is it?

Matches the basics of XamlPad v3

  • Edit the XAML in a TextBox, as you type, see changes show up in the View pane. I’ve built a XamlPad usercontrol in XamlPadHelpers.dll.

Then adds a few more basics

  • Supports Page or Window at root with Proxy object (since Page/Window classes can’t be hosted inside a standard WPF Window). I have the basics of this working, although real WindowProxy and PageProxy classes should be built…right now I’m just using a ContentControl.
  • Strips Events – you can now have <Button Click=”foo” /> in XamlPad…and it won’t complain.  This is implemented in XamlEngine.cs in a custom Xaml Node Loop.
  • Strips x:Class – you can now have x:Class in XamlPad…and it won’t complain.  This is implemented in XamlEngine.cs in a custom Xaml Node Loop.

Xaml for Config

  • I’ve also built XamlPadConfig, UserSettings, XamlDocumentViewModel, and XamlDocument as CLR types that are both XAML Friendly and DataBinding aware.  This effectively let’s me persist (in config.xaml) settings that include user preferences, and current user state (documents open, which view per document, etc…). I blogged about this earlier in “Persistable View Models & XAML for Config”. Most of this work is done in MainWindow.xaml.cs. Go look at config.xaml.

What’s Next

I plan to discuss (and or release samples) of the numerous other steps that I mentioned in the “Exploring: XamlPad to XamlDesigner” article.

Which of those steps are most important to you?

(I have most of them built already, however I’ve rewound, rebuilding from the ground up, and improving along the way)

I’ve been exploring XamlPad and XamlDesigner features built on top of .NET 4. I plan to ship a XamlPad+ sample soon. After that, I’d like to provide guidance and/or small samples for all of the other steps to enable the Xaml Tools out there to continue to evolve at a rapid pace; hopefully with my teams help.

Who will find this useful? People who make their own XamlPad’s or Xaml based Designer’s today. People who want to learn how it could be done. Etc…

Would love to understand who finds this interesting (beyond those building XamlPad’s today). Feel free to comment or contact me directly ( rrelyea at microsoft dot com ).

I list some steps of evolution a XAML based tool can make from a simple Pad to a more powerful Designer.

[Updated 1/30/2010 with notes which of the following features are in XamlPadSample that I've posted]

XamlPad you Know and Love

XamlPad v3 -- (XamlPadSample step 1 and later contains this feature)

  • Edit the XAML in a TextBox, as you type, see changes show up in the View pane.

XAML UI Step: A few more basics -- (XamlPadSample step 1 and later contains this feature)

  • Supports Page or Window at root with Proxy object (since Page/Window classes can’t be hosted inside a standard WPF Window).
  • Strips Events
  • Strips x:Class

Next Steps to help UI (WPF/Silverlight) Scenarios

XAML UI Step: Support Application Resources -- (XamlPadSample step 1f and later contains this feature)

  • Supports {StaticResource foo} where foo is defined in App.xaml
  • Load ApplicationDefinition into ApplicationProxy class (primarily to grab app.Resources)
  • Inject resource holder as “root” element during parse with Resources property set to app.Resources

XAML UI Step: Silverlight Support

  • Use SilverlightSchemaContext (from XAML Toolkit)
  • Use a SilverlightHost control

Next Steps to help UI and non-UI Scenarios

XAML Step: Load Assemblies -- (XamlPadSample step 1f and later contains this feature)

  • Load built assembly & reference assemblies

XAML Step: Editor

  • Syntax Coloring
  • Intellisense (use XamlSchemaContext to provide type/member information)

XAML Step: PropertyGrid, Selection Model, SourcePreservation

  • Simple Property Grid
  • Selection model enabling selection in View surface or Xaml editor, and synchronized editor.
  • Source preservation of XAML with XamlDom based store

Next Steps to help non-UI Scenarios

XAML Step: Support View for non-UI XAML -- (XamlPadSample step 1f and later contains a start on this Alternate View feature)

  • Support providing a View and a Design Experience for non-UI XAML

I’m working on a XamlPad application sample using WPF4. As part of that, I’m ending up exploring ideas around persistable view models, which may end up having a lot to do with Xaml for Config.

 image

Here is the current persisted view model for my application, which you may be able to guess can open several files at one time. I happen to display them with a tabcontrol. When you close the application, it saves the window location, all the documents I had open, what mode I was viewing them in, and the position of the splitter for each.

Here is the config.xaml file for this application:

 

  1. <XamlPadConfig ActiveXamlDocument="1" WindowHeight="640" WindowLeft="1692" WindowTop="169" WindowWidth="837" xmlns="clr-namespace:XamlPadHelpers;assembly=XamlPadHelpers">
  2.   <XamlDocumentViewModel BottomRowHeight="1027*" TopRowHeight="116*">
  3.     <XamlDocument FileName="C:\Users\rrelyea\AppData\Local\Temp\temp.xaml" />
  4.   </XamlDocumentViewModel>
  5.   <XamlDocumentViewModel BottomRowHeight="330*" TopRowHeight="237*" XamlViewState="Xaml">
  6.     <XamlDocument FileName="C:\Users\rrelyea\AppData\Local\Temp\temp2.xaml" />
  7.   </XamlDocumentViewModel>
  8.   <XamlDocumentViewModel BottomRowHeight="344*" TopRowHeight="223*" XamlViewState="View">
  9.     <XamlDocument FileName="C:\Users\rrelyea\Documents\doc.xaml" />
  10.   </XamlDocumentViewModel>
  11.   <XamlDocumentViewModel BottomRowHeight="*" TopRowHeight="2*">
  12.     <XamlDocument FileName="C:\Users\rrelyea\Documents\Visual Studio 2010\Projects\XamlDesigner\XamlDesigner\ProjectExplorer.xaml" />
  13.   </XamlDocumentViewModel>
  14. </XamlPadConfig>

 

Here is my mainwindow ctor(). It loads the config file before loading MainWindow.xaml (which has bindings to config data):

  1.         public MainWindow()
  2.         {
  3.             xamlPadConfig = GetConfigData();
  4.             DataContext = xamlPadConfig;
  5.             InitializeComponent();
  6.             this.Closing += new System.ComponentModel.CancelEventHandler(MainWindow_Closing);
  7.         }

Here is a routine that loads the config file or provides a set of defaults. (these defaults could be specified as a separate XAML file that I embed in the .exe if I wanted.)

  1.         private XamlPadConfig GetConfigData()
  2.         {
  3.             XamlPadConfig configData = null;
  4.             configFile = System.Environment.CurrentDirectory + "\\config.xaml";
  5.             if (File.Exists(configFile))
  6.             {
  7.                 try
  8.                 {
  9.                     configData = (XamlPadConfig)XamlServices.Load(configFile);
  10.                 }
  11.                 catch (Exception)
  12.                 {
  13.                     //problem with settings file, ignore it, eventually replace it
  14.                 }
  15.             }
  16.             if (configData == null)
  17.             {
  18.                 configData = new XamlPadConfig()
  19.                 {
  20.                     WindowHeight = 400,
  21.                     WindowWidth = 600,
  22.                     XamlDocumentViewModels = {                    
  23.                         CreateDefaultXamlDocumentViewModel(Environment.GetEnvironmentVariable("temp") + "\\temp.xaml")
  24.                     }
  25.                 };
  26.             }
  27.             return configData;
  28.         }

Here is a routine which creates a new XamlDocumentViewModel given a file location. For new files with no location yet, I end up passing in null.

  1.         private static XamlDocumentViewModel CreateDefaultXamlDocumentViewModel(string fileName)
  2.         {
  3.             return new XamlDocumentViewModel()
  4.             {
  5.                 XamlViewState = XamlPadHelpers.XamlViewState.Split,
  6.                 XamlDocument = new XamlDocument()
  7.                 {
  8.                     FileName = fileName,
  9.                 },
  10.                 TopRowHeight = new GridLength(2, GridUnitType.Star),
  11.                 BottomRowHeight = new GridLength(1, GridUnitType.Star)
  12.             };
  13.         }

Here is a routine which runs when the window is closed and saves that config.

  1.         void MainWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e)
  2.         {
  3.             XamlServices.Save(configFile, xamlPadConfig);
  4.         }

Here is my current MainWindow.xaml:

  1. <Window x:Class="XamlPadSample.MainWindow"
  2.         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3.         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4.         xmlns:xph="clr-namespace:XamlPadHelpers;assembly=XamlPadHelpers"
  5.         Title="XamlPad Sample"
  6.         Height="{Binding WindowHeight, Mode=TwoWay}"
  7.         Width="{Binding WindowWidth, Mode=TwoWay}"
  8.         Top="{Binding WindowTop, Mode=TwoWay}"
  9.         Left="{Binding WindowLeft, Mode=TwoWay}"
  10.         >
  11.     <Grid>
  12.         <Grid.ColumnDefinitions>
  13.             <ColumnDefinition Width="20" />
  14.             <ColumnDefinition Width="*" />
  15.         </Grid.ColumnDefinitions>
  16.         <StackPanel Orientation="Horizontal" Grid.Column="0">
  17.             <StackPanel.LayoutTransform>
  18.                 <RotateTransform Angle="90" />
  19.             </StackPanel.LayoutTransform>
  20.             <Button Click="New">New</Button>
  21.             <Button Click="Open">Open</Button>
  22.             <Button Click="Save">Save</Button>
  23.             <Button>Exit</Button>
  24.         </StackPanel>
  25.         <TabControl ItemsSource="{Binding XamlDocumentViewModels}"
  26.                     SelectedIndex="{Binding ActiveXamlDocument}" Name="documentsTabControl"
  27.                     Grid.Column="1"
  28.                     >
  29.             <TabControl.ItemTemplate>
  30.                 <DataTemplate DataType="{x:Type xph:XamlDocumentViewModel}">
  31.                     <StackPanel Orientation="Horizontal">
  32.                         <StackPanel.ToolTip>
  33.                             <TextBlock Text="{Binding XamlDocument.FileName}" />
  34.                         </StackPanel.ToolTip>
  35.                         <TextBlock Text="{Binding XamlDocument.FileNameShort}"/>
  36.                         <TextBlock Text="{Binding XamlDocument.DirtyString}" />
  37.                     </StackPanel>
  38.                 </DataTemplate>
  39.             </TabControl.ItemTemplate>
  40.             <TabControl.ContentTemplate>
  41.                 <DataTemplate DataType="{x:Type xph:XamlDocumentViewModel}" >
  42.                     <xph:XamlPad x:Name="xamlPad" />
  43.                 </DataTemplate>
  44.             </TabControl.ContentTemplate>
  45.         </TabControl>
  46.     </Grid>
  47. </Window>

I’ll likely post this complete example soon. This was fun to build and sends my mind in several directions on possibilities.

I’m curious how many of you are trying to save and load your view models?

I’m considering this for my rowing team so that our coach could easily share video, with his comments, to the entire team. (anybody have a cool app for that, or something similar, already? perhaps a WPF commenting engine with a Silverlight player?)

David Sayed blogged a comprehensive set of how to publish Silverlight video using Azure posts.

Posted by Rob_Relyea | with no comments
Filed under:
Next page »
Page view counter