49 votes

Chargement XAML au moment de l'exécution?

D'abord un peu de contexte: je travaille sur une application et que je suis en train de suivre MVVM conventions de l'écrit. Une chose que je voudrais faire est d'être en mesure de donner à l'application des différents "modèles" pour mon application. La même application, mais de montrer une "peau" pour un seul client et un autre "peau" de l'autre.

Et donc, mes questions sont les suivantes:
1. Est-il possible de charger un fichier xaml au moment de l'exécution et de "céder" à mon application?
2. Peut le fichier xaml être un fichier externe résidant dans un autre dossier?
3. La demande peut-elle passer à un autre fichier xaml facilement, ou seulement au moment du démarrage?

Mais où dois-je commencer à regarder pour plus d'informations sur cette question? Qui WPF méthodes, si elles existent, de gérer cette fonctionnalité?

Merci!

Edit: le type de "skinning" je suis désireux de faire est plus que juste changer le look de mon contrôle. L'idée est d'avoir un complètement différent de l'INTERFACE utilisateur. Boutons différents, différentes mises en page. Un peu comme la façon dont une version de l'application serait complet pour les experts et une autre version serait simplifiée pour les débutants.

37voto

Tomi Junnila Points 2599

Comme Jacob Christensen a noté, vous pouvez charger n'importe XAML, vous voulez l'aide d' XamlReader.Load. Cela ne s'applique pas seulement pour les styles, mais UIElements ainsi. Vous venez de charger le XAML comme:

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

Ensuite vous pouvez définir comme le contenu de la approprié de l'élément, par exemple pour

<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>

vous pouvez ajouter l' rootElement dans la grid avec:

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

Vous aurez naturellement également avoir à se connecter tous les événements pour les éléments à l'intérieur de l' rootElement manuellement dans le code-behind. Par exemple, en supposant que votre rootElement contient un Canvas avec un tas d' Paths, vous pouvez affecter l' Paths' MouseLeftButtonDown événement comme celui-ci:

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;
    }
}

Je n'ai pas essayé de commutation fichiers XAML à la volée, donc je ne peux pas dire si ça va vraiment fonctionner ou pas.

17voto

Carlo Points 8638

Je pense que c'est assez simple avec la XamlReader, donner un coup de cette, ne l'ai pas essayé moi-même, mais je pense que cela devrait fonctionner.

http://blogs.msdn.com/ashish/archive/2007/08/14/dynamically-loading-xaml.aspx

7voto

tom.maruska Points 142

J'ai fait simple extension de balisage, qui charge 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");
    }
}

Utilisation:

Ce trouver et charger MyFirstView.fichier xaml

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

Et ce à remplir toute la UserControl (trouver et charger MySecondView.fichier 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}" />

5voto

Jakob Christensen Points 9381

Vous pouvez charger n'importe XAML que vous souhaitez à l'aide de XamlReader.De la charge.

Si vous le style de toutes vos commandes dans votre application et de définir les styles dans vos applications dictionnaire de ressources, vous pouvez charger de nouveaux styles définis dans le code XAML quelque part d'autre en utilisant XamlReader.Charger et remplacer les pièces de votre dictionnaire de ressources avec le chargé de XAML. Vos commandes change d'apparence en conséquence.

4voto

Rahul Saksule Points 210

J'ai terminé le chargement de XAML au moment de l'exécution, voici un court exemple

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X