Как сделать рамку wpf

Обновлено: 06.07.2024

Аннотация: Рассматриваются роль и назначение языка расширенной разметки приложений XAML в процессе создания WPF- и Silverlight-приложений. При рассмотрении XAML-документа анализируется его общая структура и состав вложенных элементов, основные конструкции, используемые при построении XAML-описания элементов документа.

Получить первоначальное представление о назначении и области применения языка XAML , составить представление о структуре XAML -документа, изучить основные синтаксические конструкции.

Основные сведения о языке XAML

XAML базируется на языке расширенной разметки XML (Extensible Markup Language) и его синтакс определяется следующими правилами [ 3 ] :

Язык XAML характеризуется самоописанием. Каждый элемент в XAML -документе представляет имя типа (такие как Button, Window или Page ) в рамках заданного пространства имен. Атрибуты элементов используются для задания свойств ( Name, Height, Width и т.п.) и событий ( Click, Load и т.д.) соответствующих объектов.

При создании WPF-приложения MyFirstWpfProject VisualStudio генерирует следующий XAML -документ.

XAML -документ WPF-приложения MyFirstWpfProject начинается с дескриптора . Все дескрипторы XAML -документа начинаются символами . Любой XAML -документ состоит из XAML -элементов. Каждый XAML -документ ( XAML -элемент) начинается открывающимся дескриптором (например ), за которым следует содержимое документа (например, текстовая строка или другие XAML -элементы). В открывающем дескрипторе могут присутствовать описания атрибутов (например, Class, xmlns, Title, Height, Width и др.). XAML -документ ( XAML -элемент) должен завершаться закрывающимся дескриптором (например, /> или ). Текст XAML -документа должен содержать один корневой элемент – элемент верхнего уровня вложенности. В XAML -документе WPF-приложения MyFirstWpfProject таким элементом является . В корневой элемент могут быть добавлены другие XAML -элементы. В рассматриваемом XAML -документе это элемент .

В процессе компиляции XAML -документа WPF-приложения синтаксический анализатор переводит XAML файлы в файлы языка двоичной разметки приложений BAML ( Binary Application Markup Language ), которые затем встраиваются в виде ресурсов в сборку проекта. Для построения классов WPF-приложения синтаксический анализатор использует пространство имен, которое определено в корневом дескрипторе XAML -документа.

Пространство имен в XAML -документе задается с помощью атрибута xmlns. В приведенном выше документе объявлено два базовых пространства имен:

  • xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" – это базовое пространство имен WPF, которое охватывает все классы WPF, включая элементы управления, которые применяются при построении пользовательского интерфейса. Так как данное пространство имен объявлено без префикса, то оно распространяется на весь XAML -документ;
  • xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" – пространство имен XAML . Оно включает различные свойства утилит XAML , которые позволяют влиять на то, как XAML -документ следует интерпретировать. Данное пространство имен отображается на префикс x. Этот префикс можно помещать перед именем элемента ( x:ИмяЭлемента ).

Второе пространство имен используется для включения специфичных для XAML лексем – "ключевых слов" [ [ 9 ] ]. В табл.1.1 приведены наиболее часто используемые ключевые слова XAML .

В WPF-приложениях кроме базовых применяют специальные, необязательные пространства имен:

В атрибуты объекта Window могут быть добавлены следующие XAML -описания.

Данное XAML -описание объявляет необязательные пространства имен с префиксами mc и d. Свойства DesignHeight и DesignWidth находятся в пространстве имен, помеченном префиксом d. Данные свойства определяют, что во время разработки проекта приложения в дизайнере Visual Studio окно должно иметь размеры 300x600. Свойство Ignorable находится в пространстве имен, помеченном префиксом mc, и информирует синтаксический анализатор о том, что он должен игнорировать часть XAML -документа, помеченные префиксом d.

Префикс ( command ) используется для ссылки на пространство имен в XAML -документе. Лексеме clr-namespace присваивается название пространства имен . NET в сборке.

Для описания класса в XAML -документе используется атрибут Class . Строка XAML -документа

предписывает создать класс MyFirstWpfProject.MainWindow на базе класса Window. Префикс x атрибута Class определяет то, что данный атрибут помещается в пространство имен XAML . Класс MainWindow генерируется автоматически во время компиляции . Для части класса автоматически генерируется код (частичный (partial) класс ):

Когда выполняется компиляция приложения, XAML - файл , который определяет пользовательский интерфейс ( MainWindow.xaml ), транслируется в объявление типа CLR , которое объединяется с логикой приложения из файла класса отдельного кода ( MainWindow.xaml.cs ).

Метод InitializeComponent() генерируется во время компиляции приложения и в исходном коде не присутствует.

Для программного управления элементами управления, описанными в XAML -документе необходимо для элемента управления задать XAML атрибут Name. Так для задания имени элементу Grid необходимо записать следующую разметку:

Простые свойства задаются в XAML -документе в соответствии со следующим синтаксисом:

Например, Name = "grid1"

При необходимости задать свойство, которое является полноценным объектом, используются сложные свойства в соответствии с синтаксисом "свойство-элемент":

Например, для контейнера StackPanel нам необходимо задать градиентную кисть для заливки панели, что определяется атрибутом Background. Это реализуется с помощью дескрипторов . . . .

Для задания значения свойства из выделенного класса используется расширение разметки, которое обеспечивает расширение грамматики XAML новой функциональностью. Расширения разметки могут использоваться во вложенных дескрипторах или в XAML -атрибутах. Когда это используется в атрибутах, то необходимо применять фигурные скобки <. >.

Расширения разметки используют следующий синтаксис :

Расширения разметки реализуются классами, дочерними от класса System.Windows.Markup.MarkupExtention. Базовый класс MarkupExtention имеет метод ProvideValue(), который предоставляет нужное значение для атрибута. Например, для задания атрибуту Foreground объекта Button статического свойства, определенного в другом классе, необходимо создать следующее XAML -описание.

При компиляции синтаксический анализатор создаст экземпляр класса Static Extention, затем вызовет метод ProvideValue(), который извлечет нужное значение и установит его для свойства Foreground.

Расширения разметки могут использоваться как вложенные свойства.

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

Например, если необходимо расположить кнопку в нулевой строке сетки, то необходимо сделать следующее XAML -описание.

Здесь присоединенным свойством является Grid.Row, то есть свойство Row элемента Grid, которое не является свойством объекта Button. Свойство Row присоединяется к свойствам объекта Button, поскольку данный объект располагается в контейнере Grid.

Атрибуты объектов могут использоваться для присоединения обработчиков событий, используя следующий синтаксис .

Например, для кнопки событию её нажатия Click можно установить обработчик события Exit_Click.

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

Ключевые термины

Язык расширенной разметки приложений XAML , язык двоичной разметки приложений BAML, XAML -документ, XAML -элемент, корневой элемент XAML -документа, дескриптор , язык двоичной разметки приложений, синтаксический анализатор, базовое пространство имен XAML -документа, ключевые слова XAML , лексема clr-namespace, префикс в XAML -документе, простое свойство в XAML -документе, сложное свойство в XAML -документе, расширение разметки в XAML -документе, присоединенные свойства в XAML -документе, присоединение обработчиков событий в XAML -документе.

Краткие итоги

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

На днях, после долгого перерыва, надо было поработать на WPF, и возникло желание заменить поднадоевший стандартный вид окон Windows 7 на что-нибудь более вдохновляющее, скажем в стиле Visual Studio 2012:


Переходить на Windows 8 ради этого еще не хотелось, как и добавлять в проекты ссылки на метро-подобные библиотеки и разбираться с ними — это будет следуюшим шагом. А пока было интересно потратить вечер и добиться такого результата с минимальными изменениями рабочего кода. Забегая вперед, скажу что результат, как и планировалось, получился довольно чистым: фрагмент следующего кода, если не считать нескольких аттрибутов пропущенных для наглядности, это и есть окно с первого скриншота. Все изменения ограничились заданием стиля.



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

Основная проблема


За всю историю развития WPF в этом отношении мало что изменилось. К счастью, у меня были исходники из старинного поста Алекса Яхнина по стилизации под Офис 2007, которые он писал работая над демо проектом по популяризации WPF для Микрософта, так что с нуля начинать мне не грозило.


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

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

Создаем стиль


Сразу же определим кнопки управления окном в стиле Студии 2012. Это будет единственный дополнительный глобальный стиль на случай если потом возникнет желание использовать такие кнопки в приложении.


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

Для текста заголовка используем стандартный шрифт Segoe UI. Единственная особенность здесь — убедиться, что текст отрисован без размытия, иначе заголовок окна будет выглядеть… плохо он будет выглядеть — как во второй строчке на скриншоте.


Остальные детали менее существенны, но если интересно, добро пожаловать в исходники.

Оживляем окно

Помимо реакции на кнопки и иконку, окно должно перемещаться и изменять размер при drag'е за заголовок, за края и уголки. Соответствующие горячие зоны проще всего задать при помощи невидимых контролов. Пример для левого верхнего (северо-западного) угла.


При наличие атрибута Class в ресурсах, методы этого класса можно вызывать просто по имени как обычные обработчики событий, чем мы и воспользовались. Сами обработчики, например MinButtonClick и OnSizeNorthWest, выглядят примерно так:


DragSize далее вызывает WinAPI (исходник) и заставляет Windows перейти в режим измененения размера окна как в до-дотнетовские времена.

Почти готово. Зададим триггеры для контроля изменений интерфейса при изменении состояния окна. Вернемся в XAML и, например, заставим StatusBar'ы изменять цвет в зависимости от значения Window.IsActive.

Обратите внимание, что этот стиль влияет не на темплэйт окна, а на контролы помещенные в наше окно. Помните самый первый фрагмент с пользовательским кодом?

Собираем все вместе

Все. Нам осталось только подключить стиль к проекту через ресурсы приложения:



И можно использовать его в любом окне.

У меня есть несколько изображений в WPF. При щелчке мыши, я хочу добавить границу к изображению. Скажите, пожалуйста, как это сделать.
Должен ли я создать элемент стиля в xaml и применить его в коде?

Есть много способов. Я рекомендую что-то подобное, используя xaml.

DataContext этого блока должен иметь свойство IsSelected или что-то вроде этого. Также вам нужно реализовать IValueConverter для преобразования true в 1 и false в 0.

Просто удалите изображение из своего контейнера, создайте границу, добавьте изображение в качестве дочернего элемента границы и добавьте рамку обратно в контейнер, где было изображение. Если вы застряли, почтовый код, и я помогу вам его адаптировать, но это не должно быть сложно. Вы можете сделать все это в коде.

Еще в рубрике

Программно добавьте новый Datagrid (или другой UserControll) в программно сгенерированный TabItem (используя mvvm)

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

Выбор контейнера

Для перемещения кнопки (или любого другого элемента) по плоской форме достаточно двух координат Left по горизонтали и Top по вертикали. В силу философии компоновки WPF позиционированием своих детей ведают контейнеры и поэтому элементы не имеют свойств Left и Top. Класс Button, соответственно, также не имеет свойств абсолютного позиционирования.

Чтобы кнопки перемещались точно в указанные координаты, в качестве контейнера, выберем панель Canvas. Canvas автоматически не позиционирует свои дочерние элементы, но позволяет указывать для них абсолютные места размещения. Статический методы Canvas.SetLeft(элемент, координата-X) , Canvas.SetTop(элемент, координата-Y) перемещают элементы в любую позицию в пределах канвы.

Построение каркаса класса

Метод анимационного перемещения кнопки создадим в отдельном классе. Таким образом, используя принцип инкапсуляции, значительно уменьшим количество кода в файле главного окна приложения.

Построим скелет класса, назовём его Moving: Листинг скелета класса:

Поскольку в составе класса только один метод и нет ни одного поля, рациональней объявить его статическим. Метод движения элемента в качестве параметров принимает сам элемент и координаты пункта назначения. Хотя речь идет об анимации кнопок, в качестве первого параметра можно использовать элемент любого типа.

Разработка кода

По условию нет необходимости создавать длительную анимацию, поэтому код упростим применением метода UIElement.BeginAnimation(…) , который наследует класс Button . Один метод с параметрами для Left координаты, аналогичный метод для Top координаты. BeginAnimation(. ) работает в отдельном потоке, не прерывая основной. Два метода запустятся почти одновременно и управляемый элемент поедет по прямой до точки с координатами x и y.

Чтобы скорость была постоянной, длительность анимации должна быть пропорциональна расстоянию перемещения. Перед началом движения необходимо вычислять длину гипотенузы (катеты – Left->Left1 и Top->Top1) и делить её на значение скорости. Так мы получаем время движения в пути, обеспечивая константную скорость на любые дистанции.

Вот что у нас получилось, полный листинг класса Moving:

Анимация движения червяка

Задача

Создать анимацию элемента напоминающего движение червяка. В качестве контейнера для элемента нельзя использовать панель Canvas. Движение построить на изменениях относительных величин. Обеспечить настройку частоты кадров анимации.

Разработка алгоритма движения элемента

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

Напишем скелет-алгоритм класса движения червяка в направлении вращения часовой стрелки:

Разработка метода управления и создание кода класса

Внутри контейнера Grid элементы обычно позиционируются по столбцам и строкам. Если не создавать таблицу, можно точно управлять расположением детей Grid изменением свойства Margin . Данное свойство определяется как структура Thickness , имеющая double значения Left, Top, Right, Bottom. Эти значения устанавливают размер поля с каждой стороны элемента, соответственно названию.

Но Margin имеет относительные величины и всегда используется вместе с выравниванием HorizontalAlignment и VerticalAlignment . В этом случае, например, если HorizontalAlignment равен Left отсчёт координат по горизонтали от левого края, если равен Right, отсчёт начинается от правого края. Аналогично и с вертикальным выравниванием. Если не учитывать эти выравнивающие факторы, при движении элементов, возможно возникновение непредсказуемых артефактов.

Теперь все факторы учтены, каркас класса создан, наполняем кодом методы WormAnimation:

Код главного окна

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

Стоит отдельно описать создание группы кнопок. Множество элементов не рационально определять в XAML файле. Гораздо быстрее создать массив элементов класса Button с необходимыми настройками свойств и координатами размещения. Инициализация группы кнопок и объекта класса движения червяка происходят в конструкторе.

Код инициализации приложения: Код запуска анимаций группы кнопок и имитации движения червяка:

Исходник анимации движения элементов

Исходный код написан в MS Visual Studio 2019. Два вида анимаций размещены в закладках контейнера TabControl . Исходник приложения комбинирует инициализацию элементов в XAML и в программном коде. Для работы с исходным кодом рекомендуется изучить данную статью.

У меня есть StackPanel , содержащий пять изображений, и я хочу поставить черную рамку вокруг каждого изображения.

XAML, который у меня есть на данный момент, это:

Я думал, что смогу просто поместить на изображение одинарное поле или отступ и установить цвет фона на 000000 , но Padding и Background недопустимы для изображений.

Какой простой способ сделать это в XAML? Действительно ли я должен поместить каждое изображение в другой элемент управления, чтобы получить границу вокруг него, или есть какой-то другой трюк, который я могу использовать?

3 ответа

Я использую AQGridView в своем проекте. нам нужно создать черную цветную рамку вокруг каждого изображения. Кто-нибудь может мне в этом помочь? Заранее спасибо. С Уважением, Джас.

Просто оберните изображение в пограничный контроль

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

Окончательное решение из ответа и комментариев, добавленных Pax:

Я просто наткнулся на этот пост, и другой ответ не сработал правильно. Может быть, потому, что я теперь использую фреймворк 4, а этот пост старый?

В любом случае - если кто - то случайно увидит это в будущем-вот мой ответ:

Толщина границы и кисть важны (если вы не выберете цвет - вы не увидите границу. )

Кроме того, граница должна быть выровнена по вашему окну. Изображение "inside" граница, так что вы можете использовать поля или просто растянуть его, как это сделал я.

Я решил эту проблему таким образом.

Похожие вопросы:

У меня есть квадратное изображение 40х40, которое я хочу сделать круглым с помощью обрезки, но также поставить черную 5-пиксельную рамку вокруг изображения. У меня есть следующее, которое маскирует.

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

Я использую AQGridView в своем проекте. нам нужно создать черную цветную рамку вокруг каждого изображения. Кто-нибудь может мне в этом помочь? Заранее спасибо. С Уважением, Джас.

Привет, я играю с лайтбоксом. То, что я пытаюсь сделать, - это сделать рамку вокруг моего миниатюры, чтобы, когда пользователь наводит на нее курсор, она меняла цвет. Пример.

Я использую Owl Carousel в качестве слайдера моей домашней страницы, но я хотел бы поместить рамку вокруг раздела изображения слайдера. Если я помещу изображение вокруг всего класса owl-theme, он.

Я хотел бы создать черную рамку вокруг изображения. К сожалению, у меня есть следующая ошибка. ValueError: could not broadcast input array from shape (512,512) into shape (562,562) Вот мой код.

Вот код python, который я написал :- import cv2 import argparse ap = argparse.ArgumentParser() ap.add_argument(-v, --video, help = path to the (optional) video file) args = vars(ap.parse_args()) if.

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

Читайте также: