Проектирование графического интерфейсного окна
93WPF --- Основа WPF --- Проектирование графического интерфейсного окна
API-интерфейс WPF поддерживает возможность программной загрузки, разбора и сохранения XAML-описаний. Это может быть полезно во многих ситуациях. Например, предположим, что есть пять разных файлов XAML, описывающих внешний вид и поведение типа Window. До тех пор, пока имена каждого элемента (и всех необходимых обработчиков событий) идентичны внутри каждого файла, можно динамически менять "обложки" окна (возможно, на основе аргумента, передаваемого приложению при запуске).
Взаимодействие с XAML во время выполнения вращается вокруг типов XamlReader и XamlWriter — оба они определены в пространстве имен System.Windows.Markup. Чтобы проиллюстрировать, как программно наполнить объект Window из внешнего файла *.xaml, создадим приложение, которое имитирует базовую функциональность редактора Kaxaml.
Хотя наше приложение определенно не будет столь же развитым, как Kaxaml, все же оно предоставит возможность вводить разметку XAML, просматривать результаты и сохранять XAML во внешнем файле. Для начала обновите начальное XAML-определение элемента <Window>, как показано ниже:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="XAML Editor" Height="350" Width="525" WindowStartupLocation="CenterScreen"
Loaded="Window_Loaded" Closed="Window_Closed">
<DockPanel>
<Button DockPanel.Dock="Top" Name="btnViewXAML" Width="100" Height="40" Padding="4"
Content="Код XAML" Click="btnViewXAML_Click"></Button>
<TextBox AcceptsReturn="True" Name="txtCodeXAML" FontSize="14"
Background="Gray" Foreground="White" BorderBrush="LightBlue"
BorderThickness="2" VerticalScrollBarVisibility="Auto" AcceptsTab="True">
</TextBox>
</DockPanel>
</Window>
Прежде всего, обратите внимание на то, что первоначальный тип <Grid> заменен типом <DockPanel>, содержащим Button и TextBox, а также на то, как обрабатывается событие Click типа Button. Кроме того, события Loaded и Closed самого типа Window были обработаны внутри открывающего элемента <Window>.
Событие Loaded главного окна отвечает за определение наличия файла YourXaml.xaml в папке, содержащей приложение. Если этот файл есть, вы прочитаете его данные и поместите в TextBox главного окна. Если же нет, то заполните TextBox начальным XAML-описанием по умолчанию пустого окна (это описание в точности совпадает с разметкой, полученной при начальном определении окна, за исключением того, что для неявной установки свойства Content из Window вместо <Grid> используется <StackPanel>).
При щелчке на объекте Button сначала сохраняются текущие данные из TextBox в файле YourXaml.xaml. Сохраненные данные читаются через File.Open() для получения типа-наследника Stream. Это необходимо, поскольку метод XamlReader.Load() требует типа-наследника Stream (вместо простого System.String) для представления XAML-разметки, подлежащей разбору.
Ниже представлен исполняющий код приложения:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.IO;
using System.Windows.Markup;
namespace WpfApplication1
{
/// <summary>
/// Логика взаимодействия для MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void button1_Click(object sender, RoutedEventArgs e)
{
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
// Помещаем базовую разметку
if (File.Exists(System.Environment.CurrentDirectory + "\\YourXaml.xaml"))
{
txtCodeXAML.Text = File.ReadAllText("YourXaml.xaml");
}
else
{
string s = "<Window xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"\n"+
"xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"\n"+
"Title=\"XAML Editor\" Height=\"350\" Width=\"525\" WindowStartupLocation=\"CenterScreen\">\n"+
"<StackPanel>\n</StackPanel>\n</Window>";
txtCodeXAML.Text = s;
}
}
private void Window_Closed(object sender, EventArgs e)
{
// Записать данные из текстового блока в локальный файл
File.WriteAllText("YourXaml.xaml", txtCodeXAML.Text);
}
private void btnViewXAML_Click(object sender, RoutedEventArgs e)
{
// Запись данных из текстового блока в файл YourXaml.xaml
File.WriteAllText("YourXaml.xaml", txtCodeXAML.Text);
Window myWindow = null;
try
{
using (Stream sr = File.Open("YourXaml.xaml", FileMode.Open))
{
myWindow = (Window)XamlReader.Load(sr);
myWindow.ShowDialog();
myWindow.Close();
myWindow = null;
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
}
Обратите внимание, что большая часть логики помещена в блок try/catch. Таким образом, если файл YourXaml.xaml содержит неверно сформированную разметку, в результирующем окне сообщения отобразится сообщение об ошибке. Например, запустите программу и намеренно внесите ошибку в <StackPanel>, скажем, добавив лишнюю букву Р в открывающий элемент. После щелчка на кнопке отобразится сообщение об ошибке.
Запустите приложение и ведите некоторую XAML-разметку в текстовой области. Имейте в виду, что (подобно редактору Kaxaml) это приложение не позволяет указывать атрибуты XAML, связанные с кодом (такие как Class или обработчики событий). После щелчка на кнопке появится окно, визуализирующее определение XAML (или, возможно, окно с сообщением об ошибке разбора — будьте внимательны при вводе).