Файлы отделенного кода (.cs) — это файлы содержащие исполняемый код для программного управления объектами, которые, в свою очередь, определяются в интерфейсной части окна (страницы) с использованием XAML. Так, например, при создании нового приложения WPF у нас создаются два файла: MainWindow.xaml в котором определяются элементы интерфейса и их свойства и файл отделенного кода MainWindow.xaml.cs в котором может содержаться какая-либо логика управления созданными объектами, например, обработчики событий элементов и так далее.
Файлы отделенного кода
При создании нового проекта WPF в разметке окна используется атрибут вида:
x:Class="HelloWpf.MainWindow"
это говорит нам о том, что весь код XAML в итоге будет компилироваться в класс HelloWpf.MainWindow
. Теперь посмотрим на файл отделенного кода, который имеет следующее содержимое по умолчанию:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; 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; namespace HelloWpf { /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } } }
Здесь мы видим подключенные по умолчанию пространства имен .NET, а также то, что разделяемый класс HelloWpf.MainWindow
наследуется от класса Window
. И, несмотря на то, что, по сути, перед нами пустой класс, этот класс уже выполняет некоторую работу.
Во время компиляции этот класс объединяется с классом, который генерируется из кода XAML. Для того, чтобы произошло такое слияние, класс HelloWpf.MainWindow
определяется как разделяемый с модификатором partial
. А через метод InitializeComponent()
класс MainWindow
вызывает скомпилированный ранее код XAML, разбирает его и по нему строит графический интерфейс окна.
Что делает InitializeComponent()? По сути, это вызов метода LoadComponent()
класса System.Windows.Application
. Метод LoadComponent()
извлекает код BAML (скомпилированный XAML) из сборки и использует его для построения пользовательского интерфейса. При разборе BAML метод создает объекты каждого элемента управления, устанавливает их свойства и присоединяет все обработчики событий.
Взаимодействие XAML и кода C#
Довольно часто, при работе над проектом, нам необходимо каким-либо образом в коде C# взаимодействовать с элементами управления, созданными в XAML. С примером такого взаимодействия мы познакомились в самом первом нашем приложении WPF, когда назначали обработчик события Click
кнопки. Так, в коде XAML мы определили элемент Button
со следующими свойствами:
<Button Content="Нажми меня" Width="200" Height="60" Click="Button_Click"/>
здесь предполагалось, что где-то в файле отделенного кода MainWindow.xaml.cs определен метод Button_Click
с правильной сигнатурой, который будет служить обработчиком события Click
кнопки. В этом случае для нас всё достаточно прозрачно и интуитивно понятно — мы из кода XAML как бы создали ссылку на метод C#.
Второй момент взаимодействия прямо противоположный — когда нам необходимо из кода C# добраться до какого-либо элемента управления, определенного в XAML. Здесь для новичков в WPF не всё так очевидно. Например, нам необходимо вывести на экран сообщение, которое пользователь должен ввести в текстовое поле в окне приложения. В XAML мы можем определить следующую разметку:
<Window x:Class="HelloWpf.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:HelloWpf" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800"> <Grid Name="grid"> <TextBox Width="200" HorizontalAlignment="Center" VerticalAlignment="Top" Margin="5,5,5,5" Text="Введите текст"></TextBox> <Button Content="Нажми меня" Width="200" Height="60" Click="Button_Click"/> </Grid> </Window>
При запуске приложения мы увидим следующее содержимое окна:
Чтобы в файле отделенного кода добраться до какого-либо элемента управления в окне этот элемент должен иметь имя (Name
). В нашем случае, нам необходимо прочитать значение свойства Text
элемента управления TextBox
. Допишем описание этого элемента следующим образом:
<TextBox Width="200" HorizontalAlignment="Center" VerticalAlignment="Top" Margin="5,5,5,5" Text="Введите текст" x:Name="message"></TextBox>
здесь мы определили свойство Name
как message
. x:Name
отвечает за то, чтобы мы могли сослаться на это имя в файле отделенного кода. Теперь мы можем определить следующий обработчик события Click
кнопки:
private void Button_Click(object sender, RoutedEventArgs e) { MessageBox.Show(message.Text); }
Теперь можно запустить приложение и убедиться, что оно работает так, как мы и задумывали:
Аналогичным образом, используя свойство Name
мы получаем возможность создавать различные элементы управления, используя код C# или преобразовывать эти элементы управления. Например, воспользуемся тем правилом XAML, которое говорит нам, что одни элементы могут содержать в себе другие и добавим в кнопку, скажем, прямоугольник. Во-первых, дадим нашей кнопке имя
<Button Content="Нажми меня" Width="200" Height="60" Click="Button_Click" x:Name="button"/>
теперь, используя C# добавим в кнопку прямоугольник, дополнив конструктор по умолчанию следующим кодом:
public MainWindow() { InitializeComponent(); Rectangle r = new Rectangle(); //создали прямоугольник r.Width = 20; //задаем ширину r.Height = 20;//задаем высоту r.Fill = Brushes.Black;//цвет button.Content = r;//добавляем прямоугольник в кнопку }
теперь запустим приложение, чтобы убедиться, что всё прекрасно работает:
Подобным образом мы можем создавать элементы управления, используя код C#. Правда, не стоит сильно заигрываться с таким подходом при работе над проектами WPF, всё же лучше придерживаться такого правила — XAML для пользовательского интерфейса, C# — для логики.
Итого
Файлы отделенного кода могут использоваться для определения логики приложения, например, для задания обработчиков событий. При этом, если необходимо, то, используя атрибут Name
(x:Name
) в коде XAML мы получаем возможность доступа к свойствам элементов управления из кода C#.