Как я кастoмизировал кнопки перемотки в MediaPlayerElement

Как я кастoмизировал кнопки перемотки в MediaPlayerElement

SolarWind

Элемент управления воспроизведением медиа в UWP очень сильно разухабистый и может всего много и сразу, но для моего текущего домашнего проекта его нужно подшаманить. Кастамизируется он довольно просто о чем есть довольно полезная статья в документации. Есть там две замечательные кнопки - это перемотка назад (SkipBackwardButton) и перемотка вперед (SkipForwardButton), в своем первородном виде они выглядят

Если заглянуть в темплейт элемента управления MediaTransportControls (у меня он находится в файле c:\Program Files (x86)\Windows Kits\10\DesignTime\CommonConfiguration\Neutral\UAP\10.0.14393.0\Generic\generic.xaml об этом есть в статье, ссылку на которую дал выше), то видно, что это AppBarButton с FontIcon, коды иконок  и 

Теперь если заглянуть в таблицу символов шрифта Segoe MDL2 Assets

Это единственные символы подобного начертания и других не предвидится. Да и проигрыватель по нажатию на эти кнопки ведет себя соответственно, прыжок назад на 10 секунд, прыжок вперед на 30 секунд. Мое-же приложение подразумевает, что пользователь может в настройках задать значения 5, 10, 15, 30, 60 секунд как на перемотку вперед, так и на перемотку назад.

Есть несколько способов решения данной проблемы:

  • все оставить как есть, но надписи на кнопках не будут в полной мере отражать того, что они делают
  • поставить на их место кнопки перемотки FastForward и Rewind, уже лучше, но поведение моих кнопок будет отличаться от других приложений в магазине к которым пользователь возможно уже привык.
  • В качестве иконки AppBarButton может принимать: FontIcon - уже разобрали, что подходящих иконок в шрифте по умолчанию нет, искать другой шрифт с нужными иконками? Времени убью много, не факт что найду, а самому рисовать шрифты я не умею. SymbolIcon - это предустановленный набор иконок, по большому счету в основном используется именно SymbolIcon, а FontIcon его более разухабистая версия. BitmapIcon - уже ближе, но проблемы с Bitmap думаю всем знакомы, множество разрешений, светлая/темная тема, нет конечно можно обойтись и одним разрешением, а цвета менять масками, но вектор все-же предпочтительней. И наконец наш подопечный PathIcon. Прекрасен своей вектороностью, что снимает головную боль по масштабированию и раскрашиванию. Одна проблема генерация этой самой геометрии.

Пять минут любимого поисковика сказали что InkScape таки могёт, никогда не пользовался этим OpenSource редактором предпочитая более простой Paint.net.

Для начала разберемся с размерами, если заглянуть в шаблон AppBarButton, все в том же generic.xaml файле то видно, что ширина элемента управления 68, но если посмотреть на шаблон MediaTransportControls, там кнопки перегружены стилем в котором ширина и высота заданы ресурсами MTCMediaButtonWidth и MTCMediaButtonHeight, у которых значение 48. Итого кнопочки у нас 48*48, но сама иконка зажата в 20 единиц по высоте и отступы 14 сверху и 4 снизу

<ContentPresenter x:Name="Content"

                               Height="20"

                               Margin="0,14,0,4"

                               Content="{TemplateBinding Icon}"

                               Foreground="{TemplateBinding Foreground}"

                               HorizontalAlignment="Stretch"

                               AutomationProperties.AccessibilityView="Raw"/>

Короче создаем в Inkscape документ 48*48, отвечая сразу на вопрос почему не 48*20, путь (path) который потом сгенерируется странным образом прибит гвоздями к нижнему краю и если потом его генерировать на разрешении 48*20, то на кнопке его просто не видно, он внизу.

Поэтому первым делом меняем разрешение нового документа

Вот тут происходит неприятный глюк который потом может привести к непредсказуемым результатам. Сохраним файл и откроем его в редакторе

<g

    inkscape:label="Layer 1"

    inkscape:groupmode="layer"

    id="layer1"

    transform="translate(0,-1004.3622)" />


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

<g

    inkscape:groupmode="layer"

    id="layer3"

    inkscape:label="Layer" />

Далее нам нужна стрелка от оригинальной иконки, копируем ее из таблицы символов.

И вставляем в Incscape, установив нужный шрифт и размер 20 (подбирал методом научного тыка). Дальше нужно стереть 10 и вписать свое число.

Для этого наш текст (ведь сейчас наш символ лишь буква, хоть и странно выглядящая) нужно преобразовать в Path.

Если сейчас сохранить файл в стандартный для Inkscape .svg, то можно заполучить Path для данного символа, вот он родимый (файл легко и непринужденно открывается VSCode, или любым другим любимым текстовым редактором).

Если провалиться внутрь нашей группы, чему способствует double click, то можно редактировать части нашего изображения

Нам же нужно под корень стереть 10.

Но прежде чем стирать, нужно выяснить каким-же шрифтом была написана предыдущая 10, можете не выяснять, это SegoeUI размера 13

Далее преобразовываем нашу новую цифру в Path, как до этого делали со стрелкой. Вот если сейчас сохранить файл, то Path там будет два, а нам нужен один монолитный объект. Для этого выбираем оба наших пути и объединяем их.

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

Зачастую глючит создание пути у цифры "1"

Тут помогает команда "упрощение пути"

Но для сохранения качества, лучше командой Undo (Ctrl+Z) откатиться до момента объединения и команду упрощения вызвать для цифр, потом объединяться и сохраняться.

Открываем файл

Все что в атрибуте "d" тега <path> и есть наше значение, которое можно вставлять в XAML

В качестве бонуса, иногда Data у PathIcon, как в моем случае это не статика, а переменная, заменить Data кодом, как оказалось тоже не тривиальная задача, но тут на помощь приходит StackOverflow, вот метод доблестно скопирайченный оттуда

private Geometry PathDataToGeometry (string data)

       {

           var xaml = $"<Path xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'><Path.Data>{data}</Path.Data></Path>";

           var path = XamlReader.Load(xaml) as Windows.UI.Xaml.Shapes.Path;

           var geometry = path.Data;

           path.Data = null;

           return geometry;

       }

Report Page