c# - español - xaml tutorial
Cargando XAML en tiempo de ejecución? (6)
Creo que esto es bastante simple con el XamlReader, dale una oportunidad, no lo intenté yo mismo, pero creo que debería funcionar.
http://blogs.msdn.com/ashish/archive/2007/08/14/dynamically-loading-xaml.aspx
Primero algunos antecedentes: estoy trabajando en una aplicación y estoy tratando de seguir las convenciones de MVVM escribiéndola. Una cosa que me gustaría hacer es poder darle a la aplicación diferentes "máscaras" para mi aplicación. La misma aplicación, pero muestra una "piel" para un cliente y una "piel" diferente para otro.
Y entonces mis preguntas son:
1. ¿Es posible cargar un archivo xaml en tiempo de ejecución y "asignarlo" a mi aplicación?
2. ¿Puede el archivo xaml ser un archivo externo que reside en una carpeta diferente?
3. ¿Puede la aplicación cambiar a otro archivo xaml fácilmente, o solo en el momento del inicio?
Entonces, ¿dónde debería empezar a buscar información sobre esto? ¿Qué métodos de WPF, si existen, manejan esta funcionalidad?
¡Gracias!
Editar: el tipo de "skinning" que quiero hacer es más que simplemente cambiar el aspecto de mis controles. La idea es tener una interfaz de usuario completamente diferente. Diferentes botones, diferentes diseños. Algo así como cómo una versión de la aplicación estará completamente equipada para expertos y otra versión simplificada para principiantes.
He terminado de cargar XAML en tiempo de ejecución, aquí hay un breve ejemplo
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>";
Hice la extensión de marcado simple, que carga 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");
}
}
Uso:
Este hallazgo y carga el archivo MyFirstView.xaml
<ContentControl Content="{wpf:DynamicXamlLoader XamlFileName=MyFirstView.xaml}" />
Y esto completa UserControl completo (encuentra y carga el archivo 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}" />
Puede cargar cualquier XAML que desee utilizando XamlReader.Load .
Si aplica estilo a todos sus controles en su aplicación y define esos estilos en el diccionario de recursos de su aplicación, puede cargar nuevos estilos definidos en XAML en otro lugar utilizando XamlReader.Load y reemplazar partes de su diccionario de recursos con el XAML cargado. Sus controles cambiarán la apariencia en consecuencia.
Visite http://www.codeproject.com/Articles/19782/Creating-a-Skinned-User-Interface-in-WPF - Josh Smith escribió un excelente artículo sobre cómo hacer skinning en WPF.
Como señaló Jakob Christensen, puede cargar cualquier XAML que desee utilizando XamlReader.Load
. Esto no aplica solo para estilos, sino también para UIElement
. Usted solo carga el XAML como:
UIElement rootElement;
FileStream s = new FileStream(fileName, FileMode.Open);
rootElement = (UIElement)XamlReader.Load(s);
s.Close();
Luego puede configurarlo como el contenido del elemento adecuado, por ejemplo, para
<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>
podría agregar rootElement
en la grid
con:
layoutGrid.Children.Add(rootElement);
layoutGrid.SetColumn(rootElement, COLUMN);
layoutGrid.SetRow(rootElement, ROW);
Naturalmente, también tendrá que conectar cualquier evento para elementos dentro de rootElement
manualmente en el código subyacente. Como ejemplo, suponiendo que su rootElement
contiene un Canvas
con un montón de rootElement
, puede asignar el evento Path
s '' MouseLeftButtonDown
como este:
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;
}
}
No he intentado cambiar los archivos XAML sobre la marcha, así que no puedo decir si realmente funcionará o no.