web-dev-qa-db-ja.com

実行時にXAMLを読み込みますか?

最初にいくつかの背景:私はアプリケーションに取り組んでおり、それを書いているMVVMの慣習に従おうとしています。私がやりたいことの1つは、アプリケーションにアプリケーションに異なる「スキン」を提供できるようにすることです。同じアプリケーションですが、1つのクライアントに1つの「スキン」を表示し、別のクライアントに異なる「スキン」を表示します。

私の質問は次のとおりです。
1。実行時にxamlファイルを読み込み、アプリに「割り当てる」ことは可能ですか?
2。 xamlファイルは別のフォルダーにある外部ファイルにできますか?
3。アプリケーションは別のxamlファイルに簡単に切り替えることができますか、それとも起動時にのみできますか?

それで、これに関する情報をどこから探し始めるべきですか?存在する場合、どのWPFメソッドがこの機能を処理しますか?

ありがとう!

編集:私がやりたい「スキニング」のタイプは、コントロールの外観を変更するだけではありません。アイデアは、まったく異なるUIを使用することです。異なるボタン、異なるレイアウト。アプリのあるバージョンがエキスパート向けに完全に機能し、別のバージョンが初心者向けに簡素化される方法が好きです。

46
djcouchycouch

これはXamlReaderを使用するとかなり簡単だと思います。試してみて、自分で試してはいませんでしたが、うまくいくと思います。

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

17
Carlo

Jakob Christensenが指摘したように、XamlReader.Loadを使用して任意のXAMLをロードできます。これはスタイルだけに適用されるわけではありませんが、UIElementsにも適用されます。次のようにXAMLをロードするだけです。

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

次に、適切な要素のコンテンツとして設定できます。にとって

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

rootElementgridを追加するには、次のようにします。

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

当然、コードビハインドでrootElement内の要素のイベントを手動で接続する必要もあります。例として、rootElementCanvassの束を持つPathが含まれると仮定すると、Paths '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;
    }
}

その場でXAMLファイルを切り替えようとしたことがないので、それが本当に機能するかどうかはわかりません。

36
Tomi Junnila

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

使用法:

これはMyFirstView.xamlファイルを見つけてロードします

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

そして、これは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}" />
5
tom.maruska

XamlReader.Load を使用して、必要なXAMLをロードできます。

アプリケーションのすべてのコントロールをスタイルし、アプリケーションリソースディクショナリでそれらのスタイルを定義する場合、XamlReader.Loadを使用してXAMLで定義された新しいスタイルをロードし、リソースディクショナリの一部をロードされたXAMLで置き換えることができます。コントロールはそれに応じて外観を変更します。

5

実行時に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>";
4
Rahul Saksule

他の回答ですでに述べたように、 XamlReader.Load

より簡単な例を探している場合、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);
}

そして使用法として:

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);
1
Reza Aghaei

チェックアウト http://www.codeproject.com/Articles/19782/Creating-a-Skinned-User-Interface-in-WPF -Josh SmithはWPFでスキニングを行う方法に関する素晴らしい記事を書きました。

0
Ana Betts