2009-05-26 22 views
42

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.Cargando XAML en tiempo de ejecución?

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 "pelado" 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.

Respuesta

4

Puede cargar cualquier XAML que desee utilizando XamlReader.Load.

Si aplica todos los controles en su aplicación y define esos estilos en su diccionario de recursos de aplicaciones, puede cargar estilos nuevos 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.

33

Como se señaló Jakob Christensen, puede cargar cualquier XAML que desee mediante XamlReader.Load. Esto no aplica solo para estilos, sino también para UIElement s. Que acaba de cargar el XAML como:

UIElement rootElement; 
FileStream s = new FileStream(fileName, FileMode.Open); 
rootElement = (UIElement)XamlReader.Load(s); 
s.Close(); 

A continuación, 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 añadir la rootElement en el grid con:

layoutGrid.Children.Add(rootElement); 
layoutGrid.SetColumn(rootElement, COLUMN); 
layoutGrid.SetRow(rootElement, ROW); 

Usted, naturalmente, también tiene que conectar ningún evento para elementos dentro de la rootElement manualmente en el código subyacente. A modo de ejemplo, suponiendo que su rootElement contiene una Canvas con un montón de Path s, se puede asignar el Path s'MouseLeftButtonDown evento 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 archivos XAML sobre la marcha, por lo que no puedo decir si realmente funcionará o no.

+0

Hola TomiJ! Esto parece ser lo que estoy buscando. Lo único que me falta es cómo manejar los archivos .xaml que son parte de la solución. ¿Cómo iría y los cargaría? – djcouchycouch

+0

En la aplicación en la que estoy trabajando, solo guardo los archivos XAML en la solución y establezco su Acción de compilación en "ninguno", y hago que Visual Studio copie los archivos al directorio de salida si es más reciente. El primer fragmento de código anterior se usará para cargarlos. –

+0

Esto es lo que estaba buscando, cargando un xaml como recurso http://msdn.microsoft.com/en-us/library/aa970494.aspx – djcouchycouch

4

he hecho cargar XAML en tiempo de ejecución, aquí es un ejemplo corto

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>"; 
4

hice extensión de marcas 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:

Esta encontrar y cargar el archivo MyFirstView.xaml

<ContentControl Content="{wpf:DynamicXamlLoader XamlFileName=MyFirstView.xaml}" /> 

Y este relleno toda control de usuario (archivo de encontrar y MySecondView.xaml carga)

<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}" /> 
Cuestiones relacionadas