Loading XAML at runtime?
As Jakob Christensen noted, you can load any XAML you want using XamlReader.Load
. This doesn't apply only for styles, but UIElement
s as well. You just load the XAML like:
UIElement rootElement;
FileStream s = new FileStream(fileName, FileMode.Open);
rootElement = (UIElement)XamlReader.Load(s);
s.Close();
Then you can set it as the contents of the suitable element, e.g. for
<Window x:Class="MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Foo Bar">
<Grid x:Name="layoutGrid">
<!-- any static elements you might have -->
</Grid>
</Window>
you could add the rootElement
in the grid
with:
layoutGrid.Children.Add(rootElement);
layoutGrid.SetColumn(rootElement, COLUMN);
layoutGrid.SetRow(rootElement, ROW);
You'll naturally also have to connect any events for elements inside the rootElement
manually in the code-behind. As an example, assuming your rootElement
contains a Canvas
with a bunch of Path
s, you can assign the Path
s' MouseLeftButtonDown
event like this:
Canvas canvas = (Canvas)LogicalTreeHelper.FindLogicalNode(rootElement, "canvas1");
foreach (UIElement ui in LogicalTreeHelper.GetChildren(canvas)) {
System.Windows.Shapes.Path path = ui as System.Windows.Shapes.Path;
if (path != null) {
path.MouseLeftButtonDown += this.LeftButtonDown;
}
}
I've not tried switching XAML files on the fly, so I cannot say if that'll really work or not.
I think this is fairly simple with the XamlReader, give this a shot, didn't try it myself, but I think it should work.
http://blogs.msdn.com/ashish/archive/2007/08/14/dynamically-loading-xaml.aspx
I made simple markup extension, which loads xaml:
public class DynamicXamlLoader : MarkupExtension
{
public DynamicXamlLoader() { }
public DynamicXamlLoader(string xamlFileName)
{
XamlFileName = xamlFileName;
}
public string XamlFileName { get; set; }
public override object ProvideValue(IServiceProvider serviceProvider)
{
var provideValue = serviceProvider.GetService(typeof(IProvideValueTarget)) as IProvideValueTarget;
if (provideValue == null || provideValue.TargetObject == null) return null;
// get target
var targetObject = provideValue.TargetObject as UIElement;
if (targetObject == null) return null;
// get xaml file
var xamlFile = new DirectoryInfo(Directory.GetCurrentDirectory())
.GetFiles(XamlFileName ?? GenerateXamlName(targetObject), SearchOption.AllDirectories)
.FirstOrDefault();
if (xamlFile == null) return null;
// load xaml
using (var reader = new StreamReader(xamlFile.FullName))
return XamlReader.Load(reader.BaseStream) as UIElement;
}
private static string GenerateXamlName(UIElement targetObject)
{
return string.Concat(targetObject.GetType().Name, ".xaml");
}
}
Usage:
This find and load MyFirstView.xaml file
<ContentControl Content="{wpf:DynamicXamlLoader XamlFileName=MyFirstView.xaml}" />
And this fill whole UserControl (find and load MySecondView.xaml file)
<UserControl x:Class="MySecondView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Content="{wpf:DynamicXamlLoader}" />