Код
#статьи

10 причин моей любви и ненависти к XAML

XAML — неоднозначная технология, которая умудряется дать столько же возможностей, сколько и головной боли. Разбираемся в ее плюсах и минусах.

 vlada_maestro / shutterstock

Что такое XAML

XAML — это расширенный язык разметки, который используется в .NET. Он схож с HTML, поэтому достаточно прост в освоении. У XAML есть множество качеств, за которые его можно любить, но у каждого такого качества есть обратная сторона, вызывающая ненависть.

Я собрал 5 причин для любви (и столько же — для ненависти) к XAML.

Люблю


Всё отображается так, как напишешь

Можно использовать Grid и выравнивание по горизонтали и вертикали, чтобы создавать адаптивные интерфейсы. Например, минут 15 достаточно, чтобы сверстать приложение с минималистичным дизайном:

Интерфейс отображается так, как было написано, а если его растягивать, то он сохранит пропорции:

Особенно это удобно для вертикального выравнивания, которое может быть непросто реализовать в HTML и CSS. Здесь это делается с помощью одного свойства VerticalAlignment:

<Border Grid.Row="0" Background="#333">
	<TextBlock Text="Chat" Foreground="#fff" VerticalAlignment="Center" HorizontalAlignment="Center" FontSize="16pt" FontWeight="DemiBold"/>
</Border>

И самое классное — не нужно адаптировать этот код под разные разрешения или браузеры.

Ненавижу


Чтобы всё отображалось, как ты хочешь, приходится писать много кода

Хотя большая часть задумок реализуется достаточно быстро, код получается громоздким, а иногда все же приходится прибегать к различным хитростям.

Например, в текстовом поле курсор всегда отображается в левом верхнем углу. Это, конечно, можно исправить с помощью Padding, но при изменении размеров поля всё поломается. Поэтому приходится помещать TextBox в контейнер и задавать свойства ему, а само текстовое поле просто выравнивать по центру:

<Border BorderBrush="#444" BorderThickness="1" >
	<TextBox Background="#333" Foreground="#fff" BorderThickness="0" VerticalAlignment="Center" Padding="2"/>
</Border>

Тут HTML выигрывает, потому что в нем не нужно создавать дополнительный элемент.

Однако это всё цветочки по сравнению с тем, что приходится делать, чтобы настроить отображение кнопок (смотрите ниже).

Люблю


Можно использовать стили

В XAML можно использовать стили, дающие большие возможности. Например, есть возможность задать свойства для всех кнопок или списков, а можно создать ключ и выборочно указывать его каким-то элементам.

Стили могут наследоваться, и в них можно менять свойства в зависимости от состояния элемента:

<Window.Resources>
	<Style TargetType="TextBlock">
		<Setter Property="TextBlock.FontFamily" Value="Arial"/>
	</Style>

	<Style x:Key="Button1">
		<EventSetter Event="Button.Click" Handler="Button1_Click"/>
	</Style>

	<Style x:Key="MessagesList">
		<Style.Setters>
			<Setter Property="ListView.Foreground" Value="#fff" />
		</Style.Setters>
		<Style.Triggers>
			<Trigger Property="ListView.IsMouseOver" Value="True">
				<Trigger.Setters>
					<Setter Property="ListView.Foreground" Value="#ccc" />
				</Trigger.Setters>
			</Trigger>
		</Style.Triggers>
	</Style>
</Window.Resources>

Можно даже создать триггер, который будет срабатывать, если пользователь введет определенное значение. Ну и, конечно, можно указывать обработчики событий.

Ненавижу


Иногда со стилями приходится возиться

Есть и обратная сторона. Например, одному элементу можно задать только один стиль. В HTML же можно указывать сразу несколько классов, к которым стиль будет применен.

Также, если у стиля установлен TargetType, ему нельзя указать ключ, и, следовательно, от него нельзя наследовать. Это очень неудобно, если нужно не только задать свойства всем элементам TextBlock, но и наследовать их для дальнейшего использования.

Тогда приходится писать что-то такое:

<Style x:Key="TextBase">
	<Setter Property="TextBlock.Margin" Value="5" />
	<Setter Property="TextBlock.Foreground" Value="#e2e2e2" />
</Style>

<Style BasedOn="{StaticResource TextBase}" TargetType="TextBlock"></Style>

<Style x:Key="TextHeader" BasedOn="{StaticResource TextBase}">
	<Setter Property="TextBlock.FontWeight" Value="DemiBold"/>
</Style>

То есть создавать три стиля вместо двух.

Люблю


Можно использовать шаблоны

Работа со списками в XAML — это чудо. Можно указать как источник элементов коллекцию объектов, а потом вывести их по шаблону:

<ListView ScrollViewer.VerticalScrollBarVisibility="Auto" Background="#444" BorderThickness="0" Name="MessagesListView">
	<ListView.ItemTemplate>
		<DataTemplate>
			<Border Background="#353535" Padding="7" CornerRadius="15" MaxWidth="200">
				<TextBlock Text="{Binding Text}" Foreground="#fff" FontSize="12pt"/>
			</Border>
		</DataTemplate>
	</ListView.ItemTemplate>
</ListView>

Вот сами объекты, коллекция и вывод источника:

public class Message
{
	private string text;

	public Message(string text)
	{
		this.text = text;
	}

	public string Text
	{
		get
		{
			return this.text;
		}
	}

}

public partial class MainWindow : Window
{
	public MainWindow()
	{
		InitializeComponent();

		List<Message> messages = new List<Message>();
		messages.Add(new Message("Hello!"));
		messages.Add(new Message("How are you?"));
		messages.Add(new Message("Long time no see"));

		MessagesListView.ItemsSource = messages;
	}
}

А таким будет вывод:

Написав один раз хороший шаблон, можно почти не возвращаться к нему — только если понадобится вывести новое свойство или изменить дизайн.

Ненавижу


Иногда использования шаблонов не избежать

Иногда использование шаблонов — это необходимость, без которой не обойтись. Например, нужно очень постараться, чтобы кнопка при наведении меняла цвет так, как надо:

<Style x:Key="SendButton">
	<Style.Setters>
		<Setter Property="Border.Margin" Value="1" />
		<Setter Property="Border.Background" Value="#333" />
		<Setter Property="TextBlock.Foreground" Value="#fff" />
		<Setter Property="TextBlock.FontWeight" Value="DemiBold"/>
		<Setter Property="TextBlock.VerticalAlignment" Value="Center"/>
		<Setter Property="TextBlock.TextAlignment" Value="Center"/>
		<Setter Property="Border.Padding" Value="10, 5" />
		<Setter Property="Button.Template">
			<Setter.Value>
				<ControlTemplate>
					<Border Background="{TemplateBinding Background}" Padding="{TemplateBinding Border.Padding}">
						<TextBlock Text="{TemplateBinding Button.Content}"/>
					</Border>
				</ControlTemplate>
			</Setter.Value>
		</Setter>
	</Style.Setters>
	<Style.Triggers>
		<Trigger Property="Control.IsMouseOver" Value="true">
			<Setter Property="Button.Background" Value="#444"/>
		</Trigger>
	</Style.Triggers>
</Style>

Это очень большой код, поэтому бесит, когда приходится писать его в каждом проекте. Для сравнения, вот как это делается в CSS:

.button
{
	background: #333;
}

.button:hover
{
	background: #444;
}

Люблю


Можно использовать привязку данных

Еще одна крутая штука — привязка данных. Можно в качестве значения текстового поля указать название свойства объекта — и, когда пользователь изменит текст, изменится и объект:

<TextBox Text="{Binding Name}" Background="#333" Foreground="#fff" BorderThickness="0" VerticalAlignment="Center" Padding="2"/>

Можно привязать это же свойство к другому элементу, который тоже будет меняться:

<TextBlock Text="{Binding Name, Mode=OneWay}" Foreground="#fff" VerticalAlignment="Center" HorizontalAlignment="Center" FontSize="16pt" FontWeight="DemiBold"/>

И вот что получится в результате:

Ненавижу


В некоторые аспекты сложно вникнуть

Привязка данных позволяет значительно сократить код и избавить разработчика от решения многих задач. Но проблема в том, что использовать привязку бывает очень сложно. Чаще всего потому, что не всегда понятно, из-за чего вывод работает некорректно. А причин может быть много:

  • неправильно указана привязка;
  • не указан DataContext;
  • передается пустой объект и так далее.

Также каждый раз приходится имплементировать интерфейс INotifyPropertyChanged и писать повторяющийся код для каждого класса, об изменении которого нужно уведомлять.

public class User : INotifyPropertyChanged
{
	private string name;

	public User(string name)
	{
		this.name = name;
	}

	public string Name
	{
		get
		{
			return this.name;
		}

		set
		{
			this.name = value;
			NotifyPropertyChanged();
		}
	}

	public void NotifyPropertyChanged(string propertyName = "")
	{
		PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
	}
	public event PropertyChangedEventHandler PropertyChanged;
}

Люблю


Один язык разметки для всех платформ

Еще одна крутая особенность — кроссплатформенность. XAML используется не только в WPF, но и в Xamarin.Forms. Это позволяет разработчикам ПО для компьютеров быстро начать создавать мобильные приложения.

Так, можно один раз написать интерфейс, который будет работать на Android, iOS и UWP (Windows 10). При этом XAML скомпилируется в нативный код для этих платформ.

Ненавижу


XAML в WPF! = XAML в Xamarin.Forms

Только начинаешь вникать в Xamarin.Forms, как XAML делает удар под дых — это не тот XAML, который ты любишь и знаешь.

Можно, конечно, стерпеть, что у некоторых элементов другие названия. Например, что StackPanel превращается в StackLayout. Можно даже привыкнуть к тому, что для одних целей используются разные элементы. Например, в Xamarin.Forms текст выводится с помощью Label, а не TextBlock.

Но самое интересное начинается, когда пытаешься добавить привязку данных, потому что она делается совсем не так, как ты привык. Можно потратить несколько часов, пока не осознаешь, что ты пытаешься использовать MVVM, а нужно — MVVMCross.

Заключение

XAML — это крутая технология, которую есть за что любить, но есть и за что ненавидеть. Поэтому разработка превращается в эмоциональные качели: сначала ты счастлив, что всё так просто и удобно, а потом тратишь на реализацию небольшой, казалось бы, фичи несколько часов.

Однако, проработав достаточно долго как с HTML, так и с XAML, я все равно выберу второй. Потому что с ним я каждый раз уверен, что все работает так, как мне нужно, и никак не зависит от внешних факторов.

Изучайте IT на практике — бесплатно

Курсы за 2990 0 р.

Я не знаю, с чего начать
Научитесь: Профессия Python-разработчик Узнать больше
Понравилась статья?
Да

Пользуясь нашим сайтом, вы соглашаетесь с тем, что мы используем cookies 🍪

Ссылка скопирована