Перейти к содержанию

Размеры: расширение SizeExtension

Для использования необходимо подключить nuget-пакет ModPlusStyle версии не ниже 16.0 (если в пакете модуля версия ниже)!

<PackageReference Include="ModPlusStyle" Version="16.0.0" ExcludeAssets="runtime" />


Назначение

SizeExtension — разметочное расширение {mps:Size}, которое задаёт размер, автоматически уменьшающийся в компактном режиме библиотеки оформления.

Компактный режим (ThemeManager.IsCompactMode, начальное значение — параметр CompactMode в реестре HKCU\Software\ModPlus) уменьшает отступы и высоты элементов внутри самих стилей. Но размеры, которые плагин задаёт сам — ширина поля ввода, ширина колонки, максимальная ширина окна — библиотека не видит. Если написать Width="170", поле останется шириной 170 пикселей и в компактном режиме, и вся экономия места пропадёт. {mps:Size 170} решает эту задачу.

Отступы этим расширением не задают. Для них есть {mps:Margin} с множителями базовой единицы — см. Отступы: ресурсы Margin и расширение MarginExtension.

Подключение

xmlns:mps="https://modplus.org/winfx/xaml/controls"

Как считается значение

Число в расширении — это размер в пикселях для обычного режима. В компактном режиме он умножается на коэффициент из ресурса ModPlus.Sizes.Scale и округляется до целого пикселя (округление от нуля, то есть 127.5 → 128).

Ресурс Обычный режим Компактный режим
ModPlus.Sizes.Scale 1.0 0.75

Примеры:

Запись Обычный режим Компактный режим
{mps:Size 170} 170 128
{mps:Size 200} 200 150
{mps:Size 240} 240 180
{mps:Size 300} 300 225
{mps:Size 1000} 1000 750

Нижняя граница

Второе число, если оно указано, — нижняя граница: ниже неё размер не опускается, каким бы плотным ни был режим. Пригодится там, где слишком узкое поле перестаёт быть читаемым: поле для номера листа, колонка с датой, кнопка с длинной подписью.

<TextBox Width="{mps:Size 170, 150}" />
Запись Обычный режим Компактный режим
{mps:Size 170} 170 128
{mps:Size 170, 150} 170 150 — сработала нижняя граница

Обратите внимание на синтаксис: два числа передаются через запятую и без кавычек — это два аргумента конструктора расширения, а не одна строка (в отличие от {mps:Margin '1 0.5'}, где вся запись множителей берётся в кавычки).

Значение 0 (и отсутствие второго аргумента) означает «без ограничения». Свойства расширения можно задавать и по именам:

<TextBox Width="{mps:Size Size=170, Minimum=150}" />

Каким свойствам подходит

Расширение возвращает double, поэтому подходит любому свойству этого типа:

  • Width, Height
  • MinWidth, MinHeight
  • MaxWidth, MaxHeight
  • любому пользовательскому свойству типа double

Отдельный случай — ColumnDefinition.Width и RowDefinition.Height: они имеют тип GridLength, и расширение само отдаёт значение как GridLength в пикселях.

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="{mps:Size 200}" />
        <ColumnDefinition Width="*" />
    </Grid.ColumnDefinitions>
</Grid>

Смешанный вариант — колонка тянется, но не сжимается меньше заданного:

<ColumnDefinition Width="300" MinWidth="{mps:Size 200}" />

Пример: окно плагина

<mps:ModPlusWindow x:Class="MyPlugin.MainWindow"
                   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                   xmlns:mps="https://modplus.org/winfx/xaml/controls"
                   Title="Нумерация помещений"
                   Width="{mps:Size 1000}"
                   Height="{mps:Size 640}"
                   MinWidth="{mps:Size 760}"
                   MinHeight="{mps:Size 480}">

    <StackPanel Margin="{mps:Margin 1}">

        <TextBox Width="{mps:Size 170}"
                 HorizontalAlignment="Left" />

        <!-- Поле не должно становиться уже 150: иначе не видно значение целиком -->
        <mps:NumericBox Width="{mps:Size 170, 150}"
                        HorizontalAlignment="Left" />

        <TextBlock MaxWidth="{mps:Size 364}"
                   TextWrapping="Wrap"
                   Text="Длинное пояснение, которое не должно растягиваться на всю ширину окна." />

    </StackPanel>

</mps:ModPlusWindow>

Размеры для контролов, создаваемых в коде

Если контрол собирается в C#, вместо присваивания числа используйте DensityAssist.SetSize:

using ModPlusStyle.Controls;

var textBox = new TextBox();

// Width = 170 в обычном режиме, 128 в компактном
DensityAssist.SetSize(textBox, FrameworkElement.WidthProperty, 170);

// То же самое, но не уже 150
DensityAssist.SetSize(textBox, FrameworkElement.WidthProperty, 170, 150);

Метод ставит привязку, а не константу, поэтому значение пересчитывается при переключении режима на лету.

Технические детали

  • Значение отдаётся привязкой к наследуемому свойству DensityAssist.Scale, поэтому оно следует за ресурсом ModPlus.Sizes.Scale и переживает переключение компактного режима без перезагрузки окна.
  • ModPlusWindow в конструкторе связывает DensityAssist.Scale с этим ресурсом, и значение наследуется всеми элементами внутри окна.
  • Когда цель расширения известна, оно дополнительно ставит ссылку на ресурс само — как для FrameworkElement, так и для FrameworkContentElement. Благодаря этому {mps:Size} работает и в окнах, не унаследованных от ModPlusWindow, — достаточно, чтобы были подключены словари стилей.
  • Если ни того, ни другого нет, коэффициент берёт значение по умолчанию 1, то есть размер остаётся таким, как в обычном режиме.

Чего расширение не делает

  • Не задаёт отступы. Для них — {mps:Margin}.
  • Не масштабирует размеры самих контролов библиотеки. Высоты полей, паддинги кнопок, высоты строк меню уменьшаются словарём Density.Compact.xaml внутри стилей — их задавать вручную не нужно.
  • Не трогает иконки и геометрию глифов. В компактном режиме они намеренно оставлены прежними: их уменьшение ломает отрисовку, а не делает интерфейс плотнее. Если задаёте размер иконки, оставляйте обычное число.
  • Не уменьшает текст подсказок и заголовков столбцов DataGrid. Ресурсы ModPlus.Fonts.Sizes.Tooltip и ModPlus.Fonts.Sizes.DataGridColumnHeader (оба 12) в компактном режиме намеренно оставлены прежними: они равны базовому размеру текста ModPlus.Fonts.Sizes.Content, который компактный режим не трогает, а подсказка или заголовок мельче поясняемого текста читаются плохо.

Размер и положение окна

Начиная с версии 16.0.8 ModPlusWindow с включённым SaveWindowPosition запоминает размер и положение отдельно для каждого режима: в компактном режиме к ключу хранилища (полному имени типа окна) добавляется суффикс .Compact. Содержимое при разной плотности занимает разное место, и один общий размер подходил бы только одному из режимов.

  • Ключ выбирается при открытии окна. Если переключить компактный режим у уже открытого окна, при закрытии размер сохранится туда же, откуда был загружен.
  • После обновления пакета окно при первом открытии в компактном режиме откроется с размером по умолчанию — ранее сохранённый размер относится к обычному режиму.
  • Поэтому в разметке окна не нужно подбирать Width/Height, которые устроят оба режима: достаточно {mps:Size} для начального размера, дальше пользователь настроит окно сам.

Высота пунктов меню

Начиная с версии 16.0.9 высота пунктов Menu/ContextMenu задаётся через MinHeight, а не Height (ресурсы ModPlus.Sizes.MenuItem.Height и ModPlus.Sizes.MenuItem.TopLevelHeight). Пункт с крупным или многострочным заголовком теперь растёт по содержимому и не обрезается в компактном режиме. Если нужен пункт фиксированной высоты, задавайте Height явно.

Смотрите также