tags:

views:

1661

answers:

3

I have created a WPF app where I dynamicly build XAML elements using c# code and then add them to a root "container" grid.

What I'm trying to do is take advantage of the features in Blend and create some XAML Pages that have their own set of code behind logic, Storyboards, etc.

I want to load that XAML at runtime, however for some reason my approach is not working and I'm at a loss for why.

This what what I did before. In my root Window I create a new MyModule and add it to my contentRoot.

 myModule = new MyModule();
 contentRoot.Children.Add(myModule );

(Approach that works) MyModule class extends Canvas and consists of a .XAML file and .CS code behind file. The XAML is just a root canvas, and the .CS has all the logic to create elements and add them to the root canvas.

When I use this same approach where MyModule is now extends Page nothing shows up. The XAML now has a lot of content in it including a Canvas.Resources Canvas.Triggers, and a bunch of other elements.

How can I load pre-created XAML content from a Class including the code behind logic at run time?

A: 
  FileStream xamlFile = new FileStream("Resources/News/NewsModuleCanvas.xaml", FileMode.Open, FileAccess.Read);
  Canvas newsCanvas = (Canvas)XamlReader.Load(xamlFile);
  contentRoot.Children.Add(newsCanvas);

Used this to load XAML, however this still does not give me the option of also adding the code behind logic.

discorax
Are you saying you want to inject arbitrary code behind to this XAML file? Where is your code behind located?
siz
inject, I don't think so, I just want to access some of the methods contained in the code behind as well as access some of the XAML elements like Storyboards.
discorax
+1  A: 

I find this question a bit unclear, but here's something that worked for me.

Define MyModule as:

<Page x:Class="WpfApplication3.MyModule"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Height="300" Width="300">
</Page>


public partial class MyModule : Page
{
    public MyModule()
    {
        InitializeComponent();
        this.Content = new TextBlock(new Run("WOW!"));
    }
}

Created a standalone file called MyModuleStandalone.xaml:

<local:MyModule xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                xmlns:local="clr-namespace:WpfApplication3;assembly=WpfApplication3"                
                xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"&gt;
</local:MyModule>

The code below works. When I show c, it displays a text block with the text "WOW!".

FileStream xamlFile = new FileStream("MyModuleStandalone.xaml", FileMode.Open, FileAccess.Read);
MyModule c= (MyModule)XamlReader.Load(xamlFile);
this.Content = c;

The local var c is an instance of MyModule so all of the code from that class is available. Is this what you're looking for?

You cannot use the x:Class attribute in your standalone XAML file because this implies the XAML is a partial class and the rest of the class is declared somewhere else. XamlReader just won't support it.

Remember that when you read in a XAML file, you are reading in a serialized object. There is no way to dynamically inject code behind into an arbitrary standalone xaml file.

siz
do you know if you can access properties inside c for instance, Start/Stop storyboards?
discorax
+2  A: 

Page and Canvas are two different kind of components in XAML.

Page is framework element, and Canvas is Container, which can have multiple controls placed with absolute x,y coordinates. Where else Page has only one property "Content" you can consider Page being an advanced content control.

Blend must have created methods related to Canvas and which will be like "Canvas.SetLeft" etc, but they will certainly not work in Page.

Your Page class must have one content of type "Canvas" and you must add all controls inside "Canvas" inside page, that shall help you.

This is the text from MSDN,

A Page can have only a single child element. All other elements on a Page must be descendents of that element. Typically, the content of a Page hosts a layout element—such as Grid, StackPanel, and DockPanel—that hosts the content of the Page.

In your case, Page should host one element "Canvas" and add items.

Or why dont you try this one, let your MyModule be same as what it is, and you create a new Page, called MyModulePage and it should look like this.

<MyModulePage>
    <MyModule/> <!-- that is your canvas generated in blend -->
</MyModulePage>
Akash Kava