0 / 0 / 0
Регистрация: 17.02.2015
Сообщений: 49
1

Кнопка с несколькими объектами Path

05.12.2016, 22:22. Показов 4448. Ответов 25

Author24 — интернет-сервис помощи студентам
Доброго времени суток.

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

Есть задача, создать WPF сложную кнопку почты, на которой вместо обычного текста будет присутствовать:
- рисунок с изображением(2) (например конвертика);
- на момент подгруздки писем поверх основного рисунка, в определенном красотой месте, крутится рисунок отображающий загрузку писем(3) (а-ля стрелочки в кружочке)
- после загрузки, - текст отображающий сколько непрочитанных писем у пользователя(4), если они есть
- анимация подсветки кнопки, если письма есть(5).

После некоторого гугла было решено следующее:

1. Для применения собственных свойств к кнопке использовать стиль, в который поместить свои изыски со шрифтами и шаблон, содержащий вышеописанные дополнения.
2. В качестве основного рисунка был выбран векторный вариант картинки, реализованный с помощью объекта Path:
XML
1
2
3
4
5
6
7
8
9
10
11
<Path x:Key="Mail" Data="
          M 0, 5.5 L 17.5, 5.5 C 17.4, 6 17.4, 6.3
          17.4, 6.7 17.4, 8.3 17.8, 9.8 18.7, 11.1 L 13.78, 14.2z 
          
          M 0, 5.5 L 13.8, 17 19.6, 12.1 C 21, 13.6 
          23, 14.6 25.3, 14.6 26, 14.6 26.8, 14.5
          27.5, 14.3 L 27.5 22 27.3, 21.9 27.5, 22
          0, 22 0.1, 21.9 0, 22z"
           Stretch="Uniform" Fill="#FFFFFFFF" Width="50" Height="50" 
          Margin="0,0,0,0" RenderTransformOrigin="0.5,0.5">
    </Path>
Изображение, в принципе, можно без труда конвертить из фотошопоподобных программ путем юзания плагина, или же взять готовые бесплатные, например отсюда.
С векторным изображением в WPF, как кажется, проще работать т.к. сам WPF векторный, и, в частности, применять анимацию. (Так ли это?)
Как видно из врезки кода выше, картинка создана с помощью встроенного языка описания геометрии, сведения о котором, в целом, найти не сложно.
3. В качестве рисунка на момент загрузки, выбран следующий рисунок
XML
1
2
3
4
5
6
7
8
9
10
11
12
13
<Path x:Key="MailSync" Data="
          M 20.3, 6.3659973 L 21.1, 10.5 22.1, 9.7 C 23, 10.5 24.2, 11 25.5, 10.9 26.7, 10.7 27.6, 
          10.2 28.3, 9.4 L 27.4, 9 C 26.9, 9.5 26.2, 9.9 25.4, 9.9 24.4, 10 23.5, 9.7 22.8, 9 L 24.3, 7.8z 
          
          M 25.1, 2.2 C 24.5, 2.25 24.9, 2.3 24.6, 2.3 23.5, 2.4 22.5, 3 21.8, 3.8 L 22.7, 4.1 C 23.2, 3.6 24, 3.3 
          24.7, 3.2 25.8, 3.1 27, 3.5 27.6, 4.3 L 26.3, 5.5 30.2, 7 29.4 ,2.8 28.3, 3.7 C 27.5, 2.8, 26.4, 2.2, 25.2, 2.2z
          
          M 25.3, 0 C 29, 0 32, 3 32, 6.7 32, 10.4 29, 13.4 25.3, 13.4 21.6, 13.4 18.6, 10.4 18.6, 6. 18.6, 3 21.6, 0 25.3,0z
          "
          Stretch="Uniform" Fill="#FFFFFFFF" Width="50" Height="50" 
          Margin="0,0,0,0" RenderTransformOrigin="0.5,0.5">
        
    </Path>
.
4. Для отображения информации о полученных письмах видится создание контейнера, в который ляжет картинка для красивости фона и TextBlock для отображения количества писем. Чтобы иметь возможность удобно засылать контент думалось создать свойство зависимости, отвечающее за текст в TextBlock
5. Для создания анимации думал создать в шаблоне триггер, отвечающий за свойство Fill элементов типа Path и событие, которое будет его включать.

Собственно вопросы:
Есть ли какие-то реальные примеры подобного контрола? (В интернете в основном либо куски, либо простые примеры. Это, отчасти и послужило толчком для написания поста.)
Как будет лучше организовать структуру такого контрола?
Вопрос, на котором я повис на данном этапе - Как правильно группировать элементы типа Path в одну структуру?

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

Код стиля, который есть сейчас приаттачил как .log файл.

Большое спасибо за помощь.
Вложения
Тип файла: log BasicButtonDictionary.log (5.8 Кб, 2 просмотров)
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
05.12.2016, 22:22
Ответы с готовыми решениями:

[WPF] "Path" является неоднозначной ссылкой между "System.Windows.Shapes.Path" и "System.IO.Path"
Здравствуйте! Делаю экспорт из программы в Excel. Код брался от WinForm, немного переписал....

Работа с несколькими jquery-объектами
Правильно ли будет обращение сразу к нескольким объектам так: var h2 = $('h2'), ul =...

Децентрализованное управление несколькими объектами
Имеется туннель в котором появляются различного рода препятствия(буквы Г или просто перегородки и...

Работа с несколькими объектами на форме
Чтобы к примеру обратиться например к разным Picturebox-ам можно использовать такой код: Private...

25
0 / 0 / 0
Регистрация: 17.02.2015
Сообщений: 49
12.12.2016, 14:15  [ТС] 21
Author24 — интернет-сервис помощи студентам
Спасибо большое.

Ошибки исчезли после того, как унаследовал целевой класс от класса Button.
Ранее было наследовано от UIElement. При сборке, видимо, чего-то не хватало, класс не собирался и это интерпретировалось как ошибка XAML, наверное потому, что intelisence не видел сигнатуры целевого класса.
Сейчас буду курить почему именно Button.

Добавлено через 30 минут
Посмотрев структуру классов, стало ясно, что наследоваться от UIElement смысла нет и проблема была в том, что в этом классе не определены почти никакие свойства, относящиеся к какому-либо конкретному контролу.

На данный момент, унаследовался от класса Control ниже по иерархии наследования.
0
0 / 0 / 0
Регистрация: 17.02.2015
Сообщений: 49
13.12.2016, 21:18  [ТС] 22
Цитата Сообщение от novikov.ea Посмотреть сообщение
Можно, написав так: <ContentControl Content="{StaticResource *Имя_Элемента*}" />
А можно управлять этим экземпляром ресурса из ContentControl'a через, например, триггеры?
Например, поменять ему свойство Fill?
0
Эксперт .NET
1838 / 1346 / 427
Регистрация: 10.06.2011
Сообщений: 2,126
14.12.2016, 10:38 23
Вообще я не видел, чтобы кто-то делал представленным способом. Всё содержимое ControlTemplate описывается прямо в нём. Вы писали, что ваш Path - это ресурс, значит вы хотите, использовать его с нескольких местах. Но поскольку Path - это ресурс, то изменение его будет применяться ко всем местам, где он будет использоваться. Это точно то, что вам нужно? Может быть будет лучше просто прописать Path непосредственно в ControlTemplate?
Я не знаю специфики вашей задачи. Просто описал своё видение.
1
0 / 0 / 0
Регистрация: 17.02.2015
Сообщений: 49
15.12.2016, 13:38  [ТС] 24
Есть еще вопрос по теме: Есть ли способ применить анимацию, объявленную в ресурсе к разным объектам?
Воможно ответ кроется где-то на поверхности, но гугл показывает какие-то страшные манипуляции, аж не по себе

Например.
Есть шаблон для кнопки, в нем размещен контейнер и объекты типа Path:
XML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<ControlTemplate x:Shared="False" x:Key="SpecButtonTemplate" TargetType="Button">
        <Border  BorderBrush="{TemplateBinding BorderBrush}"
                    BorderThickness="{TemplateBinding BorderThickness}" 
                    Background="{TemplateBinding Background}" SnapsToDevicePixels="true" 
                    MinWidth="{TemplateBinding MinWidth}" MinHeight="{TemplateBinding MinHeight}">
 
            <Grid HorizontalAlignment="Center" VerticalAlignment="Center"
                        MinHeight="68" MinWidth="68" >
                
                <Canvas Height="42.5" Width="60.25"
                            HorizontalAlignment="Center"
                            VerticalAlignment="Center">
   <!--Целевой объект-->
                    <Path x:Name="Mail" Canvas.Top="2.25" Canvas.Left="5" Data="
                            M 0, 5.5 L 17.5, 5.5 C 17.4, 6 17.4, 6.3
                            17.4, 6.7 17.4, 8.3 17.8, 9.8 18.7, 11.1 L 13.78, 14.2z 
          
                            M 0, 5.5 L 13.8, 17 19.6, 12.1 C 21, 13.6 
                            23, 14.6 25.3, 14.6 26, 14.6 26.8, 14.5
                            27.5, 14.3 L 27.5 22 27.3, 21.9 27.5, 22
                            0, 22 0.1, 21.9 0, 22z"
                            Stretch="Uniform"  Width="50" Height="50" 
                            Margin="0,0,0,0" RenderTransformOrigin="0.5,0.5"
                            Effect="{StaticResource ShadowButtonEffect}">
                    </Path>
...
У шаблона есть триггеры, где хотелось бы применить анимацию:
XML
1
2
3
4
<ControlTemplate.Triggers>
            <EventTrigger RoutedEvent="FrameworkElement.Loaded">
<!--Здесь необходимо применить анимацию-->                        
            </EventTrigger>
Есть Storyboard, размещенный в ресурсе:
XML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Storyboard x:Key="butBackground" RepeatBehavior="Forever">
        <ColorAnimationUsingKeyFrames Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[0].(GradientStop.Color)">
            <EasingColorKeyFrame KeyTime="0" Value="#FFF1EBD5"/>
            <EasingColorKeyFrame KeyTime="0:0:0.25" Value="#FFFF5D11"/>
            <EasingColorKeyFrame KeyTime="0:0:0.3" Value="Red"/>
            <EasingColorKeyFrame KeyTime="0:0:0.35" Value="#FFFF5D11"/>
            <EasingColorKeyFrame KeyTime="0:0:0.8" Value="#FFF1EBD5"/>
            <EasingColorKeyFrame KeyTime="0:0:1.1" Value="#FFF1EBD5"/>
        </ColorAnimationUsingKeyFrames>
        <ColorAnimationUsingKeyFrames Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[1].(GradientStop.Color)">
            <EasingColorKeyFrame KeyTime="0:0:0.2" Value="#FFF1EBD5"/>
            <EasingColorKeyFrame KeyTime="0:0:0.3" Value="#FFFF5D11"/>
            <EasingColorKeyFrame KeyTime="0:0:0.325" Value="Red"/>
            <EasingColorKeyFrame KeyTime="0:0:0.35" Value="#FFFF5D11"/>
            <EasingColorKeyFrame KeyTime="0:0:0.8" Value="#FFF1EBD5"/>
            <EasingColorKeyFrame KeyTime="0:0:1.1" Value="#FFF1EBD5"/>
        </ColorAnimationUsingKeyFrames>
    </Storyboard>
StoryBoard такой, потому что анимируется градиентная заливка. И вынесен в ресурс, потому что применяться он будет в большом количестве мест.
Эксперименты с Blend показали, что тамошний генератор всегда создает элемент ColorAnimationUsingKeyFrames заточенный под конкретный объект, путем задания параметров, типа таких:
XML
1
<ColorAnimationUsingKeyFrames Storyboard.TargetProperty="(Shape.Fill).(GradientBrush.GradientStops)[0].(GradientStop.Color)" Storyboard.TargetName="Mail">
При моих ныненшних знаниях, Storyboard.TargetName="Mail" сводит на нет возможность переиспользования анимации для других объектов того же типа.

Как и что необходимо модифицировать, чтобы имелась возможность использовать Storyboard для разных объектов одного типа?

Спасибо.
0
Эксперт .NET
1838 / 1346 / 427
Регистрация: 10.06.2011
Сообщений: 2,126
15.12.2016, 14:06 25
Я с анимациями сам сало работал, может, чего не знаю. Но можно, как вариант, брать Storyboard-ресурс и запускать его.
Попробуйте создать свой наследник TriggerBase<>, который будет вызывать запуск анимации. Передавайте ему значения: EventTargetObject, RoutedEvent, Storyboard, StoryboardTargetObject. Попробуйте покопать у этом направлении.
Или, может, кто-то более опытный в деле анимаций подскажет.
0
0 / 0 / 0
Регистрация: 17.02.2015
Сообщений: 49
15.12.2016, 16:18  [ТС] 26
Вы говорите о коде C#. Я же думал, может быть, существует решение, при котором получится это сделать средствами XAML.

Нашел достаточно интересное решение, но оно относится не к шаблону, а к стилю и мной еще не опробовано.
Судя по всему, человек сделал прокладку в виде Объекта UIElement и свойства Opacity.

XML
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<Window.Resources>
    <UIElement x:Key="AnimationPlaceholder" Opacity="0"/>
 
    <Style TargetType="TextBlock">
        <Setter Property="Opacity" 
                Value="{Binding Source={StaticResource AnimationPlaceholder}, Path=Opacity}" />
    </Style>
    
    <Storyboard x:Key="OnClick1">
        <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" 
                                       Storyboard.Target="{StaticResource AnimationPlaceholder}" 
                                       Storyboard.TargetProperty="(UIElement.Opacity)">
            <SplineDoubleKeyFrame KeyTime="00:00:00" Value="0"/>
            <SplineDoubleKeyFrame KeyTime="00:00:00.5000000" Value="1"/>
        </DoubleAnimationUsingKeyFrames>
    </Storyboard>
    
    <Window.Triggers>
        <EventTrigger RoutedEvent="ButtonBase.Click" SourceName="button">
            <BeginStoryboard Storyboard="{StaticResource OnClick1}"/>
        </EventTrigger>
    </Window.Triggers>
</Window.Resources>
Неужели нужно прибегать к таким хитростям, чтобы решить простую проблему?))
Должно же быть какое-то решение вопроса)
0
15.12.2016, 16:18
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
15.12.2016, 16:18
Помогаю со студенческими работами здесь

Как уменьшить расстояние между несколькими объектами?
Как уменьшить расстояние между несколькими объектами?)

Буфер трафарета для сцены с несколькими объектами
Сделать вырез в фигуре с использованием буфера трафарета несложно, в сети примеров хватает. Но...

Инициализация вектора с несколькими типами данных или объектами класса
Задача наподобие книжной библиотеки. Есть класс Book в котором перечислены автор,название,год...

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


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
26
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru