C# 在运行时加载 XAML?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/910814/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Loading XAML at runtime?
提问by djcouchycouch
First some background: I'm working on an application and I'm trying to follow MVVM conventions writing it. One thing I'd like to do is to be able to give the application different "skins" to my application. The same application, but show one "skin" for one client and a different "skin" for another.
首先是一些背景:我正在开发一个应用程序,我正在尝试遵循 MVVM 约定编写它。我想做的一件事是能够为我的应用程序提供不同的“外观”。相同的应用程序,但为一个客户端显示一个“皮肤”,为另一个客户端显示不同的“皮肤”。
And so my questions are:
1. Is it possible to load a xaml file at run time and "assign" it to my app?
2. Can the xaml file be an external file residing in a different folder?
3. Can the application switch to another xaml file easily, or only at startup time?
所以我的问题是:
1. 是否可以在运行时加载 xaml 文件并将其“分配”给我的应用程序?
2. xaml 文件可以是驻留在不同文件夹中的外部文件吗?
3. 应用程序是否可以轻松切换到另一个 xaml 文件,或者仅在启动时?
So where should I start looking at for information on this? Which WPF methods, if they exist, handle this functionality?
那么我应该从哪里开始寻找这方面的信息呢?哪些 WPF 方法(如果存在)处理此功能?
Thanks!
谢谢!
Edit: the type of "skinning" I'm wanting to do is more than just changing the look of my controls. The idea is having a completely different UI. Different buttons, different layouts. Kinda like how one version of the app would be fully featured for experts and another version would be simplified for beginners.
编辑:我想要做的“换肤”类型不仅仅是改变我的控件的外观。这个想法是有一个完全不同的用户界面。不同的按钮,不同的布局。有点像该应用程序的一个版本如何为专家提供完整功能,而另一个版本将为初学者简化。
采纳答案by Carlo
I think this is fairly simple with the XamlReader, give this a shot, didn't try it myself, but I think it should work.
我认为这对于 XamlReader 来说相当简单,试一试,我自己没有尝试过,但我认为它应该可以工作。
http://blogs.msdn.com/ashish/archive/2007/08/14/dynamically-loading-xaml.aspx
http://blogs.msdn.com/ashish/archive/2007/08/14/dynamically-loading-xaml.aspx
回答by Jakob Christensen
You can load any XAML that you want using XamlReader.Load.
您可以使用XamlReader.Load加载您想要的任何 XAML 。
If you style all your controls in your application and define those styles in your applications resource dictionary you can load new styles defined in XAML somewhere else using XamlReader.Load and replace parts of your resource dictionary with the loaded XAML. Your controls will change appearance accordingly.
如果您为应用程序中的所有控件设置样式并在应用程序资源字典中定义这些样式,则可以使用 XamlReader.Load 加载在 XAML 中定义的新样式,并使用加载的 XAML 替换部分资源字典。您的控件将相应地更改外观。
回答by Tomi Junnila
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:
正如 Jakob Christensen 所指出的,您可以使用XamlReader.Load
. 这不仅适用于样式,也适用于UIElement
s。您只需加载 XAML,如:
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:
你可以rootElement
在其中添加grid
:
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:
您自然还必须rootElement
在代码隐藏中手动连接内部元素的任何事件。例如,假设您rootElement
包含Canvas
带有一堆Path
s 的 a,您可以像这样分配Path
s 的MouseLeftButtonDown
事件:
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.
我没有尝试过即时切换 XAML 文件,所以我不能说这是否真的有效。
回答by Ana Betts
Check out http://www.codeproject.com/Articles/19782/Creating-a-Skinned-User-Interface-in-WPF- Josh Smith wrote a great article on how to do skinning in WPF.
查看http://www.codeproject.com/Articles/19782/Creating-a-Skinned-User-Interface-in-WPF- Josh Smith 写了一篇关于如何在 WPF 中进行蒙皮的精彩文章。
回答by Rahul Saksule
I have done loading XAML at runtime, here is a short example
我已经在运行时加载了 XAML,这是一个简短的例子
Grid grd = new Grid();
var grdEncoding = new ASCIIEncoding();
var grdBytes = grdEncoding.GetBytes(myXAML);
grd = (Grid)XamlReader.Load(new MemoryStream(grdBytes));
Grid.SetColumn(grd, 0);
Grid.SetRow(grd, 0);
parentGrid.Children.Add(grd);
private String myXAML = @" <Grid xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation' Margin='30 10 30 65' VerticalAlignment='Bottom'>" +
"<Label Content='Date: 1-Feb-2013' FontFamily='Arial' FontSize='12' Foreground='#666666' HorizontalAlignment='Left'/>" +
"<Label Content='4' FontFamily='Arial' FontSize='12' Foreground='#666666' HorizontalAlignment='Center'/>" +
"<Label Content='Hello World' FontFamily='Arial' FontSize='12' Foreground='#666666' HorizontalAlignment='Right'/>" +
"</Grid>";
回答by tom.maruska
I made simple markup extension, which loads xaml:
我做了简单的标记扩展,它加载了 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
此查找并加载 MyFirstView.xaml 文件
<ContentControl Content="{wpf:DynamicXamlLoader XamlFileName=MyFirstView.xaml}" />
And this fill whole UserControl (find and load MySecondView.xaml file)
这填充了整个 UserControl(查找并加载 MySecondView.xaml 文件)
<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}" />
回答by Reza Aghaei
As it's already mentioned in other answers, you can use XamlReader.Load
.
正如其他答案中已经提到的那样,您可以使用XamlReader.Load
.
If you are looking for a more straightforward example, here is an example showing how easily you can create a control from a string variable containing the XAML:
如果您正在寻找更直接的示例,下面的示例显示了从包含 XAML 的字符串变量创建控件是多么容易:
public T LoadXaml<T>(string xaml)
{
using (var stringReader = new System.IO.StringReader(xaml))
using (var xmlReader = System.Xml.XmlReader.Create(stringReader))
return (T)System.Windows.Markup.XamlReader.Load(xmlReader);
}
And as the usage:
并作为用法:
var xaml = "<TextBox xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation\'>" +
"Lorm ipsum dolor sit amet." +
"</TextBox>";
var textBox = LoadXaml<System.Windows.Controls.TextBox>(xaml);