Ответ 1
Я думаю, что это довольно просто с XamlReader, дать этот снимок, сам не пробовал, но я думаю, что он должен работать.
http://blogs.msdn.com/ashish/archive/2007/08/14/dynamically-loading-xaml.aspx
Сначала немного фона: я работаю над приложением, и я пытаюсь следовать его соглашениям MVVM. Одна вещь, которую я хотел бы сделать, - уметь прикладывать приложение к другим приложениям. Это же приложение, но покажет один "скин" для одного клиента и другой "скин" для другого.
Итак, мои вопросы:
1. Возможно ли загрузить файл xaml во время выполнения и "назначить" его моему приложению?
2. Может ли файл xaml быть внешним файлом, находящимся в другой папке?
3. Может ли приложение легко переключаться на другой файл xaml или только во время запуска?
Итак, где я должен искать информацию об этом? Какие методы WPF, если они существуют, обрабатывают эту функциональность?
Спасибо!
Изменить: тип "скиннинга", который я хочу сделать, - это не просто изменение внешнего вида моих элементов управления. Идея заключается в совершенно другом интерфейсе. Различные кнопки, разные макеты. Как бы то ни было, что одна версия приложения будет полностью доступна для экспертов, а другая версия будет упрощена для новичков.
Я думаю, что это довольно просто с XamlReader, дать этот снимок, сам не пробовал, но я думаю, что он должен работать.
http://blogs.msdn.com/ashish/archive/2007/08/14/dynamically-loading-xaml.aspx
Как отметил Якоб Кристенсен, вы можете загрузить любой XAML, который хотите использовать XamlReader.Load
. Это не относится только к стилям, но UIElement
. Вы просто загружаете 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>
вы можете добавить rootElement
в grid
с помощью:
layoutGrid.Children.Add(rootElement);
layoutGrid.SetColumn(rootElement, COLUMN);
layoutGrid.SetRow(rootElement, ROW);
Естественно, вам также придется подключать любые события для элементов внутри rootElement
вручную в коде. Например, если ваш rootElement
содержит Canvas
с пучком Path
s, вы можете назначить событие 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;
}
}
Я не пытался переключать файлы XAML на лету, поэтому я не могу сказать, будет ли это действительно работать или нет.
Вы можете загрузить любой XAML, который вы хотите использовать XamlReader.Load.
Если вы создаете все свои элементы управления в своем приложении и определяете эти стили в словаре ресурсов приложений, вы можете загружать новые стили, определенные в XAML где-то еще, используя XamlReader.Load и заменять части вашего ресурсного словаря загруженным XAML. Соответственно, ваши элементы управления изменят внешний вид.
Я загрузил 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>";
Я сделал простое расширение разметки, которое загружает 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}" />
Отъезд http://www.codeproject.com/Articles/19782/Creating-a-Skinned-User-Interface-in-WPF - Джош Смит написал замечательную статью о том, как делать скинирование в WPF.