How to Create Control from External Definition file in WPF

No.of Views769
Bookmarked0 times
Downloads 
Votes0
By  abhi2434   On  19 Nov 2010 10:11:51
Tag : WPF , XAML
In this article, i will discuss about Create Control from External Definition file in WPF and Save Control XAML source into external file as well.
emailbookmarkadd commentsprint

Images in this article missing? We recently lost them in a site migration. We're working to restore these as you read this. Should you need an image in an emergency, please contact us at info@codegain.com

 

Introduction

In this article, i will discuss about Create Control from External Definition file in WPF and Save Control XAML source into external file as well.XAML is the most flexible language built ever. More I see XAML, more I know about it. Today while tweaking around with XAML code, I found XAML could be loaded dynamically from any XML string. That means if you have a xaml in a xml file you can probably load the part of the XAML into your ContentControl or to any control element you want and the UI will appear instantly.

Once you compile a XAML it produces BAML. BAML is in binary format for the XML, so if you can pass a BAML into the UI separately somehow during runtime,you would be seeing the content instantly in the Window.

What is XamlReader and XamlWriter?

If you look into the implementation of these classes you could wonder how flexible these are. They are highly capable of parsing the whole content of the file. It uses a XAMLDictionary which holds all the XAML elements that a XAML can see. The Reader parses the Xml content very cautiously to ensure it makes the XAML file to contain no reference of outside. Thus the class is used to Refactor the XAML from outside and hence allows you to put the content anywhere such that everything will be applied on that instantly.

XamlReader exposes methods like Load / Parse which allows you to parse a file content into BAML. Hence each of them returns an binary object which you can put into the Content.

The sample application implements these features to store the Xaml content into an external file and later on it loads the same content from the file to show up the content again. 

Image Loading

The UI looks straight forward, you have a Button telling you to OpenFile. When you click and open a file with content :

<StackPanel Orientation="Vertical" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
        <Button>This is My Button</Button>
        <Border Width="525" Height="250">
            <Border.Background>
                <LinearGradientBrush>
                    <LinearGradientBrush.GradientStops>
                        <GradientStop Color="#FF008000" Offset="0" />
                        <GradientStop Color="#FF0000FF" Offset="0.5" />
                        <GradientStop Color="#FFFF0000" Offset="1" />
                    </LinearGradientBrush.GradientStops>
                </LinearGradientBrush>
            </Border.Background>
            <Border.Triggers>
                <EventTrigger RoutedEvent="FrameworkElement.Loaded">
                    <BeginStoryboard>
                        <Storyboard>
                            <Storyboard.Children>
                                <ColorAnimation From="#FF008000" To="#FFFFFF00" AutoReverse="True" BeginTime="00:00:00" Duration="00:00:05" Storyboard.TargetProperty="(Panel.Background).(GradientBrush.GradientStops)[0].(GradientStop.Color)" />
                                <ColorAnimation From="#FF0000FF" To="#FFFF0000" AutoReverse="True" BeginTime="00:00:00" Duration="00:00:05" Storyboard.TargetProperty="(Panel.Background).(GradientBrush.GradientStops)[1].(GradientStop.Color)" />
                                <ColorAnimation From="#FFFF0000" To="#FF008000" AutoReverse="True" BeginTime="00:00:00" Duration="00:00:05" Storyboard.TargetProperty="(Panel.Background).(GradientBrush.GradientStops)[2].(GradientStop.Color)" />
                            </Storyboard.Children>
                        </Storyboard>
                    </BeginStoryboard>
                </EventTrigger>
            </Border.Triggers>
        </Border>
    </StackPanel>

It will eventually load a Button and the Border element with ColorAnimation running. 

Image Loading

On the other hand say If I create the same code for the ContentControl and click on the SaveContent Button, it will produce the reverse.
For this purpose I have created  a simple utility class :

public class XamlUtility
{public string FilePath { get; set; }public object Content { get; set; }public void LoadContent()
    {
        OpenFileDialog dlg = new OpenFileDialog();
        dlg.Filter = "XAML Files|*.xaml";bool? retval = dlg.ShowDialog();if (retval.HasValue && retval.Value)
        {this.FilePath = dlg.FileName;using (FileStream stream = new FileStream(dlg.FileName, FileMode.Open))
            {object content = XamlReader.Load(stream);this.Content = content;
            }
        }
    }public void SaveContent()
    {
        SaveFileDialog dlg = new SaveFileDialog();
        dlg.Filter = "XAML Files|*.xaml";bool? retval = dlg.ShowDialog();if (retval.HasValue && retval.Value)
        {using (FileStream stream = new FileStream(dlg.FileName, FileMode.Create))
            {
                XamlWriter.Save(this.Content, stream);this.Content = null;
            }
        }
    }
}

 The class exposes few methods like LoadContent which itself calls the XamlReader.Load to load the Stream into Content. When the XamlLoads the Xaml Parser takes care of the whole Xml content and load only the element which are meaningful to the compiler. Hence if you put arbitrary attributes for say Button, it will not load the attribute in XAML content.

On the other hand, while SaveContent, the Parser automatically parses the content based on the Dictionary and writes only the content that doesnot hold information for outside. Hence if you have Triggers enabled for your Border element, as we do have for the sample, the RoutedEvent will automatically changed from Border to FrameworkElement, also the reference to the TargetProperty is used to be a Panel rather than the Border itself. Another good thing that I found is, it automatically removes any external eventhandlers from the written Xaml output.

For each WPF application, the XamlReader and XamlWriter are the main componenet to load the UI. Other than normal loading the XamlContent these classes also exposes methods to define your custom  ParserContext which allows you to define the metadata for the Xaml.

Both Reader and Writer also exposes methods to load Xaml asynchronously. The methods lile LoadAsync, CancelAsync may come very handy for loading Large Xaml files into the UI.

Download Sample Project

Download source files -55 kb

Conclusion

This is truly a flexible way to load your XAML UI or to store the XAML UI separately into a file. The process comes very handy at times when the UI is self sufficient in all respect.  As we can do for html use of XAML extensively gives you an edge in latest UI development.I hope you can now use XamlReader and XamlWriter in your application easily.

 
Sign Up to vote for this article
 
About Author
 
abhi2434
Occupation-Not Provided
Company-Not Provided
Member Type-Senior
Location-Not Provided
Joined date-22 Oct 2009
Home Page-Not Provided
Blog Page-Not Provided
 
 
Other popularSectionarticles
Comments
There is no comments for this articles.
Leave a Reply
Title:
Display Name:
Email:
(not display in page for the security purphase)
Website:
Message:
Please refresh your screen using Ctrl+F5
If you can't read this number refresh your screen
Please input the anti-spam code that you can read in the image.
^ Scroll to Top