Форум программистов, компьютерный форум, киберфорум
C#: WPF, UWP и Silverlight
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
Рейтинг 4.86/64: Рейтинг темы: голосов - 64, средняя оценка - 4.86
21 / 17 / 1
Регистрация: 01.09.2019
Сообщений: 262

Кастомная кнопка в UserControl или UserControl со свойствами кнопки

01.09.2019, 19:54. Показов 16120. Ответов 128
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Привет,

пытаюсь запихнуть кастомную кнопку в Useк Control. Что-то ерунда какая-то получается.
Можете помочь?

Хотелось бы UC со свойствами кнопки. Чтобы при клике меняла цвет своего Fill. и чтобы handle event был и binding работал, Также, от прилетаещего bool меняла свой Fill.

Спасибо!

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
27
28
29
30
31
32
33
34
35
36
37
<UserControl x:Class="Button_testing.UserControls.Polygon_Button"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:Button_testing.UserControls"
             mc:Ignorable="d" 
             d:DesignHeight="100" d:DesignWidth="100">
    <Grid>
 
 
       
        <Button Name="button1" Height="90" VerticalAlignment="Bottom" HorizontalAlignment="Left" Width="90"
     Content="No content">
 
            <Button.Template>
                <ControlTemplate TargetType="{x:Type Button}">
                    <Grid Margin="5">
                        <Ellipse Stroke="DarkBlue" StrokeThickness="2">
                            <Ellipse.Fill>
                                <RadialGradientBrush Center="0.3,0.2" RadiusX="0.5" RadiusY="0.5">
                                    <GradientStop Color="Azure" Offset="0.1" />
                                    <GradientStop Color="CornflowerBlue" Offset="1.1" />
                                </RadialGradientBrush>
                            </Ellipse.Fill>
                        </Ellipse>
 
                        <ContentPresenter Name="content" HorizontalAlignment="Center" VerticalAlignment="Center"/>
 
                    </Grid>
                </ControlTemplate>
 
            </Button.Template>
        </Button>
 
    </Grid>
</UserControl>
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
01.09.2019, 19:54
Ответы с готовыми решениями:

Как разместить UserControl поверх другого UserControl
Такая задача. Есть форма. На ней размещена панель panelRight. Также есть два пользовательских контрола (TimelineControl() и Bar()). Потом в...

Не сохраняются значения свойств заданные в дизайнере после создания своего UserControl с дополнительными свойствами
using System.ComponentModel; using System.Windows.Forms; namespace Library { public partial class CellControl : UserControl ...

DP UserControl внутри UserControl MVVM
Есть UC c DP Text &lt;Grid&gt; &lt;TextBlock HorizontalAlignment=&quot;Left&quot; Text=&quot;{Binding Text, ElementName=UC}&quot;...

128
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16165 / 11285 / 2891
Регистрация: 21.04.2018
Сообщений: 33,173
Записей в блоге: 2
04.09.2019, 21:55
Студворк — интернет-сервис помощи студентам
Цитата Сообщение от Ахромчон Посмотреть сообщение
- как в Triangle_button_EH.xaml выставить свои default background colors UC?
- как в Triangle_button_EH.xaml определить свои default width и height UC?
Убрал косяки. Добавил вывод контента. Теперь можно использовать внешние стили.

UC называется ButtonPolygon.

CB (файл ButtonPolygon.xaml.cs)
C#
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
 
namespace ButtonTriangleWPF
{
    /// <summary>Делегат функции возвращающей коллекцию вершин фигуры вписанной в заданную область</summary>
    /// <param name="width">Ширина области</param>
    /// <param name="height">Высота области</param>
    /// <returns>PointCollection - коллекцию вершин фигуры</returns>
    public delegate PointCollection InscribedPolygonHandler(double width, double height);
 
    /// <summary>
    /// Логика взаимодействия для ButtonTriangle.xaml
    /// Класс со свойствами дли многоугольной кнопки
    /// </summary>
    public partial class ButtonPolygon : Button
    {
        public ButtonPolygon()
        {
            InitializeComponent();
            SizeChanged += ButtonPolygon_SizeChanged;
        }
 
        /// <summary>Статический конвертер в кисть</summary>
        static readonly BrushConverter brushConverter = new BrushConverter();
 
        /// <summary>Делегат функции возвращающей вершины многоугольника</summary>
        public InscribedPolygonHandler InscribedPolygonDelegate
        {
            get { return (InscribedPolygonHandler)GetValue(InscribedPolygonDelegateProperty); }
            set { SetValue(InscribedPolygonDelegateProperty, value); }
        }
 
        // Using a DependencyProperty as the backing store for InscribedPolygonDelegate.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty InscribedPolygonDelegateProperty =
            DependencyProperty.Register("InscribedPolygonDelegate", typeof(InscribedPolygonHandler), typeof(ButtonPolygon), new PropertyMetadata((InscribedPolygonHandler)InscribedPolygonMetod));
 
 
        protected static readonly DependencyPropertyKey PointsKey =
            DependencyProperty.RegisterReadOnly(nameof(Points), typeof(PointCollection), typeof(ButtonPolygon), new PropertyMetadata(null));
 
        /// <summary>Свойство только для чтения. 
        /// Возвращает коллекцию вершин</summary>
        public PointCollection Points
        {
            get { return (PointCollection)GetValue(PointsProperty); }
            protected set { SetValue(PointsKey, value); }
        }
 
        // Using a DependencyProperty as the backing store for Points.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty PointsProperty = PointsKey.DependencyProperty;
 
        /// <summary>Обработчик события изменения размера</summary>
        /// <param name="sender">Источник события - неиспользуется</param>
        /// <param name="e">Информация события</param>
        private void ButtonPolygon_SizeChanged(object sender, SizeChangedEventArgs e)
            => Points = InscribedPolygonDelegate?.Invoke(e.NewSize.Width, e.NewSize.Height);
 
        /// <summary>Делегат многограника по умолчанию.
        /// Возврашает вершины внисанного треугольника</summary>
        /// <param name="width">Ширина выделенной области</param>
        /// <param name="height">Высота выделенной области</param>
        /// <returns>PointCollection с вершинами треугольника</returns>
        static protected PointCollection InscribedPolygonMetod(double width, double height)
            => new PointCollection(new Point[] { new Point(0, 0), new Point(width, 0), new Point(0.5 * width, height) });
 
        /// <summary>Ширина границы</summary>
        public double StrokeThickness
        {
            get { return (double)GetValue(StrokeThicknessProperty); }
            set { SetValue(StrokeThicknessProperty, value); }
        }
 
        // Using a DependencyProperty as the backing store for StrokeThickness.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty StrokeThicknessProperty =
            DependencyProperty.Register(nameof(StrokeThickness), typeof(double), typeof(ButtonPolygon), new PropertyMetadata(1.0));
 
        /// <summary>Кисть фона при наведении курсора мыши</summary>
        public Brush MouseOverBackground
        {
            get { return (Brush)GetValue(MouseOverBackgroundProperty); }
            set { SetValue(MouseOverBackgroundProperty, value); }
        }
 
        // Using a DependencyProperty as the backing store for MouseOverBackground.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty MouseOverBackgroundProperty =
            DependencyProperty.Register(nameof(MouseOverBackground), typeof(Brush), typeof(ButtonPolygon), new PropertyMetadata(brushConverter.ConvertFrom("#FFBEE6FD")));
 
 
 
        /// <summary>Кисть границы при наведении курсора мыши</summary>
        public Brush MouseOverBorder
        {
            get { return (Brush)GetValue(MouseOverBorderProperty); }
            set { SetValue(MouseOverBorderProperty, value); }
        }
 
        // Using a DependencyProperty as the backing store for MouseOverBorder.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty MouseOverBorderProperty =
            DependencyProperty.Register(nameof(MouseOverBorder), typeof(Brush), typeof(ButtonPolygon), new PropertyMetadata(brushConverter.ConvertFrom("#FF3C7FB1")));
 
 
 
        /// <summary>Кисть фона нажатой кнопки</summary>
        public Brush PressedBackground
        {
            get { return (Brush)GetValue(PressedBackgroundProperty); }
            set { SetValue(PressedBackgroundProperty, value); }
        }
 
        // Using a DependencyProperty as the backing store for PressedBackground.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty PressedBackgroundProperty =
            DependencyProperty.Register(nameof(PressedBackground), typeof(Brush), typeof(ButtonPolygon), new PropertyMetadata(brushConverter.ConvertFrom("#FFC4E5F6")));
 
 
 
        /// <summary>Кисть границы нажатой кнопки</summary>
        public Brush PressedBorder
        {
            get { return (Brush)GetValue(PressedBorderProperty); }
            set { SetValue(PressedBorderProperty, value); }
        }
 
        // Using a DependencyProperty as the backing store for PressedBorder.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty PressedBorderProperty =
            DependencyProperty.Register(nameof(PressedBorder), typeof(Brush), typeof(ButtonPolygon), new PropertyMetadata(brushConverter.ConvertFrom("#FF2C628B")));
 
 
 
        /// <summary>Кисть фона отключенной кнопки</summary>
        public Brush DisabledBackground
        {
            get { return (Brush)GetValue(DisabledBackgroundProperty); }
            set { SetValue(DisabledBackgroundProperty, value); }
        }
 
        // Using a DependencyProperty as the backing store for DisabledBackground.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty DisabledBackgroundProperty =
            DependencyProperty.Register(nameof(DisabledBackground), typeof(Brush), typeof(ButtonPolygon), new PropertyMetadata(brushConverter.ConvertFrom("#FFF4F4F4")));
 
 
 
 
        /// <summary>Кисть границы отключенной кнопки</summary>
        public Brush DisabledBorder
        {
            get { return (Brush)GetValue(DisabledBorderProperty); }
            set { SetValue(DisabledBorderProperty, value); }
        }
 
        // Using a DependencyProperty as the backing store for DisabledBorder.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty DisabledBorderProperty =
            DependencyProperty.Register(nameof(DisabledBorder), typeof(Brush), typeof(ButtonPolygon), new PropertyMetadata(brushConverter.ConvertFrom("#FFADB2B5")));
 
 
 
        /// <summary>Кисть текста отключенной кнопки</summary>
        public Brush DisabledForeground
        {
            get { return (Brush)GetValue(DisabledForegroundProperty); }
            set { SetValue(DisabledForegroundProperty, value); }
        }
 
        // Using a DependencyProperty as the backing store for DisabledForeground.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty DisabledForegroundProperty =
            DependencyProperty.Register("DisabledForeground", typeof(Brush), typeof(ButtonPolygon), new PropertyMetadata(brushConverter.ConvertFrom("#FF838383")));
 
    }
}
XAML (файл ButtonPolygon.xaml)
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
<Button x:Name="PART_MainButton" x:Class="ButtonTriangleWPF.ButtonPolygon"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:local="clr-namespace:ButtonTriangleWPF"
        mc:Ignorable="d"
        d:DesignHeight="450" d:DesignWidth="800">
    <Button.Template>
        <ControlTemplate TargetType="{x:Type Button}">
            <Grid>
                <Polygon x:Name="PART_Polygon"
                         Points="{Binding Points, Mode=OneWay, ElementName=PART_MainButton}"  
                         Stroke="{TemplateBinding BorderBrush}" 
                         StrokeThickness="{Binding StrokeThickness, Mode=OneWay, ElementName=PART_MainButton}"
                         Fill="{TemplateBinding Background}"/>
                <ContentPresenter x:Name="contentPresenter" Focusable="False" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
            </Grid>
            <ControlTemplate.Triggers>
                <Trigger Property="IsMouseOver" Value="true">
                    <Setter Property="Fill" TargetName="PART_Polygon" 
                                    Value="{Binding MouseOverBackground, Mode=OneWay, ElementName=PART_MainButton}"/>
                    <Setter Property="Stroke" TargetName="PART_Polygon" 
                                    Value="{Binding MouseOverBorder, Mode=OneWay, ElementName=PART_MainButton}"/>
                </Trigger>
                <Trigger Property="IsPressed" Value="true">
                    <Setter Property="Fill" TargetName="PART_Polygon"
                                    Value="{Binding PressedBackground, Mode=OneWay, ElementName=PART_MainButton}"/>
                    <Setter Property="Stroke" TargetName="PART_Polygon"
                                    Value="{Binding PressedBorder, Mode=OneWay, ElementName=PART_MainButton}"/>
                </Trigger>
                <Trigger Property="IsEnabled" Value="false">
                    <Setter Property="Fill" TargetName="PART_Polygon"
                                    Value="{Binding DisabledBackground, Mode=OneWay, ElementName=PART_MainButton}"/>
                    <Setter Property="Stroke" TargetName="PART_Polygon"
                                    Value="{Binding DisabledBorder, Mode=OneWay, ElementName=PART_MainButton}"/>
                    <Setter Property="TextElement.Foreground" TargetName="contentPresenter" 
                            Value="{Binding DisabledForeground, Mode=OneWay, ElementName=PART_MainButton}"/>
                </Trigger>
            </ControlTemplate.Triggers>
        </ControlTemplate>
    </Button.Template>
</Button>
Пример использования
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
<Window x:Class="ButtonTriangleWPF.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:ButtonTriangleWPF"
        xmlns:sys="clr-namespace:System;assembly=mscorlib"
        mc:Ignorable="d"
        Title="MainWindow" Height="400" Width="400">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <Grid.Resources>
            <Style TargetType="{x:Type local:ButtonPolygon}">
                <Setter Property="Margin" Value="20"/>
                <Setter Property="Background" Value="Yellow"/>
                <Setter Property="DisabledBackground" Value="LightYellow"/>
                <Setter Property="Width" Value="50"/>
                <Setter Property="Height" Value="50"/>
                <Setter Property="IsEnabled" Value="{Binding IsChecked, ElementName=cbEnabled}"/>
            </Style>
        </Grid.Resources>
        <!--Треугольная кнопка-->
        <local:ButtonPolygon/>
        <!--Ромбическая кнопка-->
        <local:ButtonPolygon Grid.Row="1" Style="{x:Null}"
                             InscribedPolygonDelegate="{x:Static local:InscribedPolygonClass.InscribedRhombusDelegate}"
                             MouseOverBackground="Pink" PressedBackground="Red" Background="Green" DisabledBackground="LightGreen"
                             Content="      Кнопка
с отключенным
       стилем" HorizontalContentAlignment="Center"
                             IsEnabled="{Binding IsChecked, ElementName=cbEnabled}"/>
        <!--Шестиугольная кнопка-->
        <local:ButtonPolygon Grid.Column="1" 
                             InscribedPolygonDelegate="{x:Static local:InscribedPolygonClass.InscribedHexagonDelegate}"/>
        <!--Кнопка галочка-->
        <local:ButtonPolygon Grid.Row="1" Grid.Column="1" 
                             InscribedPolygonDelegate="{x:Static local:InscribedPolygonClass.InscribedMarkItemDelegate}"/>
 
        <CheckBox x:Name="cbEnabled" Content="Включить кнопки" IsChecked="True" VerticalAlignment="Center" HorizontalAlignment="Center"
                  Grid.RowSpan="2" Grid.ColumnSpan="2"/>
    </Grid>
</Window>
1
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16165 / 11285 / 2891
Регистрация: 21.04.2018
Сообщений: 33,173
Записей в блоге: 2
04.09.2019, 22:00
Цитата Сообщение от Ахромчон Посмотреть сообщение
базовый класс кнопки? как посмотреть?
В библиотеке Controls. Толку смотреть если изменить всё равно не можешь?

Цитата Сообщение от Ахромчон Посмотреть сообщение
то за значение NaN? можно чуть подробнее?
https://ru.wikipedia.org/wiki/NaN
https://docs.microsoft.com/ru-... mework-4.8
1
21 / 17 / 1
Регистрация: 01.09.2019
Сообщений: 262
04.09.2019, 22:01  [ТС]
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Убрал косяки. Добавил вывод контента. Теперь можно использовать внешние стили.
Завтра потестим. Спасибо!

В обычном UC я делал так для биндинга:

XML
1
2
3
4
5
6
7
8
9
 <UserControl.Resources>
 
 
        <Converters:First_MultiConverter_Colours x:Key="First_MultiConverter_Colours" />
        <Converters:Second_MultiConverter_Visibility x:Key="Second_MultiConverter_Visibility" />
        <Converters:Third_Converter_Visibility x:Key="Third_MultiConverter_Visibility" />
 
 
    </UserControl.Resource

Как в нашем случае?

Где,

XML
1
2
3
<Button.Resources>
 
</Button.Resources>
Пробовал, как с UC не прокатывает.
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16165 / 11285 / 2891
Регистрация: 21.04.2018
Сообщений: 33,173
Записей в блоге: 2
04.09.2019, 22:03
В примере использования неправильно показан текст кнопки - конфликт с XML разметкой.
Там текст Content=" Кнопка& #10;с отключенным& #10; стилем"[/NOPARSE]
Пробелы между & # - удалить.
1
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16165 / 11285 / 2891
Регистрация: 21.04.2018
Сообщений: 33,173
Записей в блоге: 2
04.09.2019, 22:06
Цитата Сообщение от Ахромчон Посмотреть сообщение
В обычном UC я делал так для биндинга:
....??
А зачем такое может понадобиться? На мой взгляд бессмыслица какая-то.
Не понимая смысла - не могу сказать как сделать.
1
21 / 17 / 1
Регистрация: 01.09.2019
Сообщений: 262
04.09.2019, 22:09  [ТС]
Цитата Сообщение от Элд Хасп Посмотреть сообщение
....??
А зачем такое может понадобиться? На мой взгляд бессмыслица какая-то.
Не понимая смысла - не могу сказать как сделать.
Ну не для самого биндинга, а для конвертации прилетающей bool в Visibility, bool в Brush и т.д. Иначе не работает!
Чтобы работало в обычном UC я загонял конвертеры в ресурсы UC. Если не загнать весь биндинг и мультибиндинг накрывается.
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16165 / 11285 / 2891
Регистрация: 21.04.2018
Сообщений: 33,173
Записей в блоге: 2
04.09.2019, 22:18
Цитата Сообщение от Ахромчон Посмотреть сообщение
Ну не для самого биндинга, а для конвертации прилетающей bool в Visibility, bool в Brush и т.д. Иначе не работает!
Чтобы работало в обычном UC я загонял конвертеры в ресурсы UC. Если не загнать весь биндинг и мультибиндинг накрывается.
Мудрите, батенька... Мудрите...

Вы явно что-то не так делаете.
Полностью опишите что вы хотите реализовать. Именно не КАК, а ЧТО.
1
21 / 17 / 1
Регистрация: 01.09.2019
Сообщений: 262
04.09.2019, 22:25  [ТС]
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Мудрите, батенька... Мудрите...
хорошее начало! То, что я описал выше работает с прошлого года, только там не кнопка, а обычный, стандартный, рисованный UC.

Цитата Сообщение от Элд Хасп Посмотреть сообщение
Полностью опишите что вы хотите реализовать. Именно не КАК, а ЧТО.
Что хотелось бы...
У нас есть ваш классный, назовем pseudo-Control Button, и нужно когда прилетает 'true' через биндинг, поменять default background на background pressed. Другими словами эта 'true' симулирует нажатие. Естественно само нажатие остается рабочим, нетронутым.
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16165 / 11285 / 2891
Регистрация: 21.04.2018
Сообщений: 33,173
Записей в блоге: 2
04.09.2019, 22:32
Цитата Сообщение от Ахромчон Посмотреть сообщение
У нас есть ваш классный, назовем pseudo-Control Button, и нужно когда прилетает 'true' через биндинг поменять default background background pressed.
Для этого используются триггера.

Нужно больше конкретики, но демонстрационный пример - надеюсь поймёте.
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
<Window x:Class="ButtonTriangleWPF.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:ButtonTriangleWPF"
        xmlns:sys="clr-namespace:System;assembly=mscorlib"
        mc:Ignorable="d"
        Title="MainWindow" Height="400" Width="400">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <Grid.Resources>
            <Style TargetType="{x:Type local:ButtonPolygon}">
                <Setter Property="Margin" Value="20"/>
                <Setter Property="Background" Value="Yellow"/>
                <Setter Property="DisabledBackground" Value="LightYellow"/>
                <Setter Property="Width" Value="50"/>
                <Setter Property="Height" Value="50"/>
                <Setter Property="IsEnabled" Value="{Binding IsChecked, ElementName=cbEnabled}"/>
                <Style.Triggers>
                    <DataTrigger Binding="{Binding IsChecked, ElementName=cbColor}" Value="true">
                        <Setter Property="Background" Value="Aquamarine"/>
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </Grid.Resources>
        <!--Треугольная кнопка-->
        <local:ButtonPolygon/>
        <!--Ромбическая кнопка-->
        <local:ButtonPolygon Grid.Row="1" Style="{x:Null}"
                             InscribedPolygonDelegate="{x:Static local:InscribedPolygonClass.InscribedRhombusDelegate}"
                             MouseOverBackground="Pink" PressedBackground="Red" Background="Green" DisabledBackground="LightGreen"
                             Content="      Кнопка& #10;с отключенным& #10;       стилем" HorizontalContentAlignment="Center"
                             IsEnabled="{Binding IsChecked, ElementName=cbEnabled}"/>
        <!--Шестиугольная кнопка-->
        <local:ButtonPolygon Grid.Column="1" 
                             InscribedPolygonDelegate="{x:Static local:InscribedPolygonClass.InscribedHexagonDelegate}"/>
        <!--Кнопка галочка-->
        <local:ButtonPolygon Grid.Row="1" Grid.Column="1" 
                             InscribedPolygonDelegate="{x:Static local:InscribedPolygonClass.InscribedMarkItemDelegate}"/>
 
        <CheckBox x:Name="cbEnabled" Content="Включить кнопки" IsChecked="True" VerticalAlignment="Center" HorizontalAlignment="Center"
                  Grid.RowSpan="2" />
 
        <CheckBox x:Name="cbColor" Content="Изменить цвет" IsChecked="True" VerticalAlignment="Center" HorizontalAlignment="Center"
                  Grid.RowSpan="2" Grid.Column="1"/>
    </Grid>
</Window>
1
21 / 17 / 1
Регистрация: 01.09.2019
Сообщений: 262
04.09.2019, 22:40  [ТС]
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Для этого используются триггера.
Т.е., так как наш UC по сути Button, то с ней возня с конвертерами не пройдет. Tолько triggers?
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16165 / 11285 / 2891
Регистрация: 21.04.2018
Сообщений: 33,173
Записей в блоге: 2
04.09.2019, 23:05
Цитата Сообщение от Ахромчон Посмотреть сообщение
Т.е., так как наш UC по сути Button, то с ней возня с конвертерами не пройдет. Tолько triggers?
Всё пройдёт.
Только конвертеры зачем здесь?
Или я вашу задачу не пойму, или вы делаете какую-то кривую реализацию.
1
21 / 17 / 1
Регистрация: 01.09.2019
Сообщений: 262
05.09.2019, 08:36  [ТС]
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Только конвертеры зачем здесь?
Не претендую на знатока использования конвертеров. Наоборот нужна помощь.
Например. В списках бинндинга есть Wheel_IsSet, ее нужно привязать к PressedBackground нашей кнопки-UC.

MainWindow.xaml

XML
1
2
3
4
5
6
7
8
<UControls:Triangle_button_EH
x:Name="triangle_button_EH"
 
<!-- blah, blah, blah... -->
 
PressedBackground="{Binding Wheel_IsSet}"
 
/>
Свойство PressedBackground разве не Brush класс, и конвертер BooleanToBrush тут не к месту? Или?

Добавлено через 7 минут
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16165 / 11285 / 2891
Регистрация: 21.04.2018
Сообщений: 33,173
Записей в блоге: 2
05.09.2019, 10:23
Цитата Сообщение от Ахромчон Посмотреть сообщение
Свойство PressedBackground разве не Brush класс, и конвертер BooleanToBrush тут не к месту? Или?
  1. Конвертеры в WPF это статические элементы - создаётся одни экземпляр на приложение. Ну, в край, один на окно. Если появилась потребность создавать по экземпляру в каждом элементе - высока вероятность что выбран неправильный путь реализации.

  2. Что это за конвертер BooleanToBrush ? Ваш кастомный? Что он делает? По названию понятно,что выбирает кисть по значению bool. Но как задаются цвета для выбора? Если для каждой кнопки свой набор цветов, то применение конвертера не оправдано - придётся задавать по экземпляру для каждой кнопки. Если одинаковый набор цветов, но только для кнопок и для одного и того же свойства, то лучше использовать общий стиль с триггером или конвертером. Если для разных типов элементов, разных свойств - то можно использовать конвертер. Но в любом случае надо создать ОДИН экземпляр конвертера и его использовать.

  3. И в целом применение такого простого конвертера редко когда будет оправдано. Может у вас есть другие конвертеры и на них более наглядно можно продемонстрировать для чего вы их используете?
1
21 / 17 / 1
Регистрация: 01.09.2019
Сообщений: 262
05.09.2019, 11:24  [ТС]
Цитата Сообщение от Элд Хасп Посмотреть сообщение
1. Конвертеры в WPF это статические элементы - создаётся одни экземпляр на приложение. Ну, в край, один на окно. Если появилась потребность создавать по экземпляру в каждом элементе - высока вероятность что выбран неправильный путь реализации.
Верно, у меня пока два простейших (шаблон из WPF) на все Solution. BoleanToVisibility и BooleanToBrush, оба рабочие и функционируют с десятками соответствующих UC (правильных).





Цитата Сообщение от Элд Хасп Посмотреть сообщение
Что это за конвертер BooleanToBrush ? Ваш кастомный? Что он делает? По названию понятно,что выбирает кисть по значению bool. Но как задаются цвета для выбора? Если для каждой кнопки свой набор цветов, то применение конвертера не оправдано - придётся задавать по экземпляру для каждой кнопки. Если одинаковый набор цветов, но только для кнопок и для одного и того же свойства, то лучше использовать общий стиль с триггером или конвертером. Если для разных типов элементов, разных свойств - то можно использовать конвертер. Но в любом случае надо создать ОДИН экземпляр конвертера и его использовать.

BooleanToBrush.cs выглядит так:


C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class BooleanToBrushConverter: IValueConverter
    {
 
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
           
            bool? state = value as bool?;
            
            if (state == null)
                return Brushes.WhiteSmoke;
           
 
            if (state == true)
                return Brushes.LightGrey;
 
            return Brushes.WhiteSmoke;
        }
 
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
 
    }


Цитата Сообщение от Элд Хасп Посмотреть сообщение
И в целом применение такого простого конвертера редко когда будет оправдано. Может у вас есть другие конвертеры и на них более наглядно можно продемонстрировать для чего вы их используете?
Очень даже оправдано. Один конвертер работает на десятки UC.

Вопрос в другом как прикрутить к нашей UC-button какой-нибудь работоспособный биндинг.
Мне нужно управлятьь этим свойством PressedBackground.

XML
1
2
3
4
5
6
7
8
<UControls:Triangle_button_EH
x:Name="triangle_button_EH"
 
<!-- blah, blah, blah... -->
 
PressedBackground="{Binding Wheel_IsSet}"
 
/>
Спасибо!
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16165 / 11285 / 2891
Регистрация: 21.04.2018
Сообщений: 33,173
Записей в блоге: 2
05.09.2019, 12:18
Цитата Сообщение от Ахромчон Посмотреть сообщение
BooleanToBrush.cs выглядит так:
Цитата Сообщение от Ахромчон Посмотреть сообщение
Очень даже оправдано. Один конвертер работает на десятки UC.
В такой "жёсткой" реализации - оправдано.

Цитата Сообщение от Ахромчон Посмотреть сообщение
Вопрос в другом как прикрутить к нашей UC-button какой-нибудь работоспособный биндинг.
Вроде должно работать.
В чём проблема - не могу понять.

Для кнопок с переопределённым делегатом всё работает. А для кнопки по умолчанию - нет.
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
<Window x:Class="ButtonTriangleWPF.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:ButtonTriangleWPF"
        xmlns:sys="clr-namespace:System;assembly=mscorlib"
        mc:Ignorable="d"
        Title="MainWindow" Height="400" Width="400">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <Grid.Resources>
            <local:BooleanToBrushConverter x:Key="BooleanToBrushConverter"/>
            <Style TargetType="{x:Type local:ButtonPolygon}">
                <Setter Property="Margin" Value="20"/>
                <Setter Property="Background" Value="Yellow"/>
                <Setter Property="DisabledBackground" Value="LightYellow"/>
                <Setter Property="Width" Value="50"/>
                <Setter Property="Height" Value="50"/>
                <Setter Property="IsEnabled" Value="{Binding IsChecked, ElementName=cbEnabled}"/>
                <Setter Property="PressedBackground" Value="{Binding IsChecked, ElementName=cbColor, Converter={StaticResource BooleanToBrushConverter}}"/>
            </Style>
        </Grid.Resources>
        <!--Треугольная кнопка-->
        <local:ButtonPolygon/>
        <!--Ромбическая кнопка-->
        <local:ButtonPolygon Grid.Row="1" Style="{x:Null}"
                             InscribedPolygonDelegate="{x:Static local:InscribedPolygonClass.InscribedRhombusDelegate}"
                             MouseOverBackground="Pink" PressedBackground="Red" Background="Green" DisabledBackground="LightGreen"
                             Content="      Кнопка
с отключенным
       стилем" HorizontalContentAlignment="Center"
                             IsEnabled="{Binding IsChecked, ElementName=cbEnabled}"/>
        <!--Шестиугольная кнопка-->
        <local:ButtonPolygon Grid.Column="1" 
                             InscribedPolygonDelegate="{x:Static local:InscribedPolygonClass.InscribedHexagonDelegate}"/>
        <!--Кнопка галочка-->
        <local:ButtonPolygon Grid.Row="1" Grid.Column="1" PressedBackground="{Binding IsChecked, ElementName=cbColor, Converter={StaticResource BooleanToBrushConverter}}"
                             InscribedPolygonDelegate="{x:Static local:InscribedPolygonClass.InscribedMarkItemDelegate}"/>
 
        <CheckBox x:Name="cbEnabled" Content="Включить кнопки" IsChecked="True" VerticalAlignment="Center" HorizontalAlignment="Center"
                  Grid.RowSpan="2" />
 
        <CheckBox x:Name="cbColor" Content="Изменить цвет" IsChecked="{x:Null}" VerticalAlignment="Center" HorizontalAlignment="Center"
                  Grid.RowSpan="2" Grid.Column="1"/>
        <TextBlock Text="{Binding IsChecked, ElementName=cbColor, Converter={StaticResource BooleanToBrushConverter}}"/>
    </Grid>
</Window>
По позже освобожусь - постараюсь разобраться в чём дело.

Добавлено через 2 минуты
И упростите конвертер
C#
1
2
3
4
5
6
7
8
9
10
11
12
    class BooleanToBrushConverter : IValueConverter
    {
 
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
            => (value as bool?) == true ? Brushes.LightGreen : Brushes.LightCoral;
 
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
 
    }
1
21 / 17 / 1
Регистрация: 01.09.2019
Сообщений: 262
05.09.2019, 12:21  [ТС]
Цитата Сообщение от Элд Хасп Посмотреть сообщение
И упростите конвертер
C#
попробую, буду ждать.
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16165 / 11285 / 2891
Регистрация: 21.04.2018
Сообщений: 33,173
Записей в блоге: 2
05.09.2019, 20:45
Цитата Сообщение от Ахромчон Посмотреть сообщение
попробую, буду ждать.
Не понял в чём ошибка.
Для проверки заново пересоздавал по одному свойству.
Вроде тоже самое в итоге получил, но теперь работает.

Так же изменил конвертер - теперь ему можно при объявлении задать цвета для true и false
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
    public class BooleanToBrushConverter :IValueConverter
    {
 
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (value is bool valB)
                return valB ? TrueBrush : FalseBrush;
            return (bool.TryParse(value?.ToString(), out valB) && valB) ? TrueBrush : FalseBrush;
        }
 
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
 
        public Brush TrueBrush { get; set; } = Brushes.LightGray;
        public Brush FalseBrush { get; set; } = Brushes.WhiteSmoke;
    }
XAML View - все привязки, в том числе через конвертер работают.
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
<Window x:Class="ButtonTriangleWPF.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:ButtonTriangleWPF"
        xmlns:sys="clr-namespace:System;assembly=mscorlib"
        mc:Ignorable="d"
        Title="MainWindow" Height="400" Width="400">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <Grid.Resources>
            <local:BooleanToBrushConverter x:Key="BooleanToBrushConverter"
                    TrueBrush="Aquamarine" FalseBrush="Coral"/>
            <Style TargetType="{x:Type local:ButtonPolygon}">
                <Setter Property="Margin" Value="20"/>
                <Setter Property="Background" Value="Yellow"/>
                <Setter Property="DisabledBackground" Value="LightYellow"/>
                <Setter Property="Width" Value="100"/>
                <Setter Property="Height" Value="100"/>
                <Setter Property="IsEnabled" Value="{Binding IsChecked, ElementName=cbEnabled}"/>
                <Setter Property="PressedBackground" Value="{Binding IsChecked, ElementName=cbColor, Converter={StaticResource BooleanToBrushConverter}}"/>
            </Style>
        </Grid.Resources>
        <local:ButtonPolygon>
            <TextBlock TextAlignment="Center">
                Треугольная
                <LineBreak/>
                кнопка
            </TextBlock>
        </local:ButtonPolygon>
        <local:ButtonPolygon Grid.Row="1" Style="{x:Null}"
                             InscribedPolygonDelegate="{x:Static local:InscribedPolygonClass.InscribedRhombusDelegate}"
                             MouseOverBackground="Pink" PressedBackground="Red" Background="Green" DisabledBackground="LightGreen"
                             HorizontalContentAlignment="Center"
                             IsEnabled="{Binding IsChecked, ElementName=cbEnabled}">
            <TextBlock TextAlignment="Center">
                Ромбическая кнопка
                <LineBreak/>
                с отключенным
                <LineBreak/>
                стилем
            </TextBlock>
        </local:ButtonPolygon>
        <local:ButtonPolygon Grid.Column="1" 
                             InscribedPolygonDelegate="{x:Static local:InscribedPolygonClass.InscribedHexagonDelegate}"/>
        <local:ButtonPolygon Grid.Row="1" Grid.Column="1" PressedBackground="{Binding IsChecked, ElementName=cbColor, Converter={StaticResource BooleanToBrushConverter}}"
                             InscribedPolygonDelegate="{x:Static local:InscribedPolygonClass.InscribedMarkItemDelegate}">
            <TextBlock TextAlignment="Center">
                Кнопка
                <LineBreak/>
                галочка
            </TextBlock>
        </local:ButtonPolygon>
 
        <CheckBox x:Name="cbEnabled" Content="Включить кнопки" IsChecked="True" VerticalAlignment="Center" HorizontalAlignment="Center"
                  Grid.RowSpan="2" />
 
        <CheckBox x:Name="cbColor" IsChecked="{x:Null}" VerticalAlignment="Center" HorizontalAlignment="Center"
                  Grid.RowSpan="2" Grid.Column="1">
            <TextBlock>
                Изменить цвет
                <LineBreak/>
                PressedBackground
            </TextBlock>
 
        </CheckBox>
    </Grid>
</Window>
Архив прилагаю - может там тоже что-то изменилось.
1
-21 / 29 / 2
Регистрация: 17.03.2018
Сообщений: 778
05.09.2019, 21:59
Здравствуйте, попробовал треугольную кнопку. Косяк с верхней стороной треугольника. Не полностью виден stroke верхней стороны.
На малых размерах съедается. Этот строке, судя по коду как раз идет вдоль внешней границы квадрата, не знаю как называется.
Не кажется?
1
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16165 / 11285 / 2891
Регистрация: 21.04.2018
Сообщений: 33,173
Записей в блоге: 2
05.09.2019, 23:09
Цитата Сообщение от Bulky Посмотреть сообщение
Здравствуйте, попробовал треугольную кнопку. Косяк с верхней стороной треугольника. Не полностью виден stroke верхней стороны.
На малых размерах съедается. Этот строке, судя по коду как раз идет вдоль внешней границы квадрата, не знаю как называется.
При задании ширины Stroke - граница расширяется в обе стороны. То есть если заданны вершины находящиеся на периметре, то граница будет выходить за пределы контрола на половину ширины.

Можно решить, но придётся значительно усложнить UC. Какого-то простого способа это сделать не нашёл.
1
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16165 / 11285 / 2891
Регистрация: 21.04.2018
Сообщений: 33,173
Записей в блоге: 2
05.09.2019, 23:52
Лучший ответ Сообщение было отмечено Ахромчон как решение

Решение

Цитата Сообщение от Bulky Посмотреть сообщение
Косяк с верхней стороной треугольника.
Я с переделками ещё косяк допустил - забыл про DP свойство контрола StrokeThickness. В коде выше он задан константой.

Так же исправил косяк с границей - немного костыльно, но работает. А может и не костыль...

CB контрола
C#
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
 
namespace ButtonTriangleWPF
{    /// <summary>Делегат функции возвращающей коллекцию вершин фигуры вписанной в заданную область</summary>
     /// <param name="width">Ширина области</param>
     /// <param name="height">Высота области</param>
     /// <returns>PointCollection - коллекцию вершин фигуры</returns>
    public delegate PointCollection InscribedPolygonHandler(double width, double height);
 
    /// <summary>
    /// Логика взаимодействия для ButtonTriangle.xaml
    /// Класс со свойствами дли многоугольной кнопки
    /// </summary>
    public partial class ButtonPolygon : Button
    {
        public ButtonPolygon()
        {
            SizeChanged += ButtonPolygon_SizeChanged;
            InitializeComponent();
        }
 
        /// <summary>Статический конвертер в кисть</summary>
        static readonly BrushConverter brushConverter = new BrushConverter();
 
        /// <summary>Делегат функции возвращающей вершины многоугольника</summary>
        public InscribedPolygonHandler InscribedPolygonDelegate
        {
            get { return (InscribedPolygonHandler)GetValue(InscribedPolygonDelegateProperty); }
            set { SetValue(InscribedPolygonDelegateProperty, value); }
        }
 
        // Using a DependencyProperty as the backing store for InscribedPolygonDelegate.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty InscribedPolygonDelegateProperty =
            DependencyProperty.Register("InscribedPolygonDelegate", typeof(InscribedPolygonHandler), typeof(ButtonPolygon), new PropertyMetadata((InscribedPolygonHandler)InscribedTriangleMetod));
 
 
        protected static readonly DependencyPropertyKey PointsKey =
            DependencyProperty.RegisterReadOnly(nameof(Points), typeof(PointCollection), typeof(ButtonPolygon), new PropertyMetadata(null));
 
        /// <summary>Свойство только для чтения. 
        /// Возвращает коллекцию вершин</summary>
        public PointCollection Points
        {
            get { return (PointCollection)GetValue(PointsProperty); }
            protected set { SetValue(PointsKey, value); }
        }
 
        // Using a DependencyProperty as the backing store for Points.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty PointsProperty = PointsKey.DependencyProperty;
 
        /// <summary>Обработчик события изменения размера</summary>
        /// <param name="sender">Источник события - не используется</param>
        /// <param name="e">Информация события</param>
        private void ButtonPolygon_SizeChanged(object sender, SizeChangedEventArgs e)
            => Points = new PointCollection
            (
                InscribedPolygonDelegate?.Invoke(e.NewSize.Width - StrokeThickness, e.NewSize.Height - StrokeThickness)
                .Select(pnt => new Point(pnt.X + StrokeThickness * 0.5, pnt.Y + StrokeThickness * 0.5)));
 
        /// <summary>Делегат многогранника по умолчанию.
        /// Возвращает вершины вписанного треугольника</summary>
        /// <param name="width">Ширина выделенной области</param>
        /// <param name="height">Высота выделенной области</param>
        /// <returns>PointCollection с вершинами треугольника</returns>
        static protected PointCollection InscribedTriangleMetod(double width, double height)
            => new PointCollection() { new Point(0, 0), new Point(width, 0), new Point(0.5 * width, height) };
 
 
        /// <summary>Кисть фона при наведении курсора мыши</summary>
        public Brush MouseOverBackground
        {
            get { return (Brush)GetValue(MouseOverBackgroundProperty); }
            set { SetValue(MouseOverBackgroundProperty, value); }
        }
 
        // Using a DependencyProperty as the backing store for MouseOverBackground.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty MouseOverBackgroundProperty =
            DependencyProperty.Register(nameof(MouseOverBackground), typeof(Brush), typeof(ButtonPolygon), new PropertyMetadata(brushConverter.ConvertFrom("#FFBEE6FD")));
 
 
 
        /// <summary>Кисть границы при наведении курсора мыши</summary>
        public Brush MouseOverBorder
        {
            get { return (Brush)GetValue(MouseOverBorderProperty); }
            set { SetValue(MouseOverBorderProperty, value); }
        }
 
        // Using a DependencyProperty as the backing store for MouseOverBorder.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty MouseOverBorderProperty =
            DependencyProperty.Register(nameof(MouseOverBorder), typeof(Brush), typeof(ButtonPolygon), new PropertyMetadata(brushConverter.ConvertFrom("#FF3C7FB1")));
 
 
 
        /// <summary>Кисть фона нажатой кнопки</summary>
        public Brush PressedBackground
        {
            get { return (Brush)GetValue(PressedBackgroundProperty); }
            set { SetValue(PressedBackgroundProperty, value); }
        }
 
        // Using a DependencyProperty as the backing store for PressedBackground.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty PressedBackgroundProperty =
            DependencyProperty.Register(nameof(PressedBackground), typeof(Brush), typeof(ButtonPolygon), new PropertyMetadata(brushConverter.ConvertFrom("#FFC4E5F6")));
 
 
 
        /// <summary>Кисть границы нажатой кнопки</summary>
        public Brush PressedBorder
        {
            get { return (Brush)GetValue(PressedBorderProperty); }
            set { SetValue(PressedBorderProperty, value); }
        }
 
        // Using a DependencyProperty as the backing store for PressedBorder.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty PressedBorderProperty =
            DependencyProperty.Register(nameof(PressedBorder), typeof(Brush), typeof(ButtonPolygon), new PropertyMetadata(brushConverter.ConvertFrom("#FF2C628B")));
 
 
 
        /// <summary>Кисть фона отключенной кнопки</summary>
        public Brush DisabledBackground
        {
            get { return (Brush)GetValue(DisabledBackgroundProperty); }
            set { SetValue(DisabledBackgroundProperty, value); }
        }
 
        // Using a DependencyProperty as the backing store for DisabledBackground.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty DisabledBackgroundProperty =
            DependencyProperty.Register(nameof(DisabledBackground), typeof(Brush), typeof(ButtonPolygon), new PropertyMetadata(brushConverter.ConvertFrom("#FFF4F4F4")));
 
 
 
 
        /// <summary>Кисть границы отключенной кнопки</summary>
        public Brush DisabledBorder
        {
            get { return (Brush)GetValue(DisabledBorderProperty); }
            set { SetValue(DisabledBorderProperty, value); }
        }
 
        // Using a DependencyProperty as the backing store for DisabledBorder.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty DisabledBorderProperty =
            DependencyProperty.Register(nameof(DisabledBorder), typeof(Brush), typeof(ButtonPolygon), new PropertyMetadata(brushConverter.ConvertFrom("#FFADB2B5")));
 
 
 
        /// <summary>Кисть текста отключенной кнопки</summary>
        public Brush DisabledForeground
        {
            get { return (Brush)GetValue(DisabledForegroundProperty); }
            set { SetValue(DisabledForegroundProperty, value); }
        }
 
        // Using a DependencyProperty as the backing store for DisabledForeground.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty DisabledForegroundProperty =
            DependencyProperty.Register(nameof(DisabledForeground), typeof(Brush), typeof(ButtonPolygon), new PropertyMetadata(brushConverter.ConvertFrom("#FF838383")));
 
 
 
        /// <summary>Ширина границы многоугольника</summary>
        public double StrokeThickness
        {
            get { return (double)GetValue(StrokeThicknessProperty); }
            set { SetValue(StrokeThicknessProperty, value); }
        }
 
        // Using a DependencyProperty as the backing store for StrokeThickness.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty StrokeThicknessProperty =
            DependencyProperty.Register(nameof(StrokeThickness), typeof(double), typeof(ButtonPolygon), new PropertyMetadata(1.0));
 
 
    }
}
XAML контрола
В коде ошибки. В конце поста дана ссылка на правильный вариант.
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
<Button x:Name="PART_ButtonDP" x:Class="ButtonTriangleWPF.ButtonPolygon" 
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
        xmlns:local="clr-namespace:ButtonTriangleWPF"
        mc:Ignorable="d" 
        d:DesignHeight="450" d:DesignWidth="800">
    <Button.Template>
        <ControlTemplate TargetType="{x:Type Button}">
            <Grid SnapsToDevicePixels="true">
                <Polygon x:Name="PART_Polygon" 
                         Points="{Binding Points, ElementName=PART_ButtonDP}" 
                         StrokeThickness="{Binding StrokeThickness, ElementName=PART_ButtonDP}" 
                         Stroke="{TemplateBinding BorderBrush}"
                         Fill="{TemplateBinding Background}"/>
                <ContentPresenter x:Name="contentPresenter"
                                  Focusable="False"
                                  HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" 
                                  Margin="{TemplateBinding Padding}" 
                                  RecognizesAccessKey="True" 
                                  SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
                                  VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
            </Grid>
            <ControlTemplate.Triggers>
                <Trigger Property="IsDefaulted" Value="true">
                    <Setter Property="Stroke" TargetName="PART_Polygon" 
                            Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}"/>
                </Trigger>
                <Trigger Property="IsMouseOver" Value="true">
                    <Setter Property="Fill" TargetName="PART_Polygon" 
                            Value="{Binding MouseOverBackground, ElementName=PART_ButtonDP}"/>
                    <Setter Property="Stroke" TargetName="PART_Polygon"
                            Value="{Binding MouseOverPART_Polygon, ElementName=PART_ButtonDP}"/>
                </Trigger>
                <Trigger Property="IsPressed" Value="true">
                    <Setter Property="Fill" TargetName="PART_Polygon"
                            Value="{Binding PressedBackground, ElementName=PART_ButtonDP}"/>
                    <Setter Property="Stroke" TargetName="PART_Polygon"
                            Value="{Binding PressedPART_Polygon, ElementName=PART_ButtonDP}"/>
                </Trigger>
                <Trigger Property="IsEnabled" Value="false">
                    <Setter Property="Fill" TargetName="PART_Polygon"
                            Value="{Binding DisabledBackground, ElementName=PART_ButtonDP}"/>
                    <Setter Property="Stroke" TargetName="PART_Polygon"
                            Value="{Binding DisabledPART_Polygon, ElementName=PART_ButtonDP}"/>
                    <Setter Property="TextElement.Foreground"
                            TargetName="contentPresenter" Value="{Binding DisabledForeground, ElementName=PART_ButtonDP}"/>
                </Trigger>
            </ControlTemplate.Triggers>
        </ControlTemplate>
    </Button.Template>
</Button>
XAML проверочного окна
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
<Window x:Class="ButtonTriangleWPF.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:ButtonTriangleWPF"
        xmlns:sys="clr-namespace:System;assembly=mscorlib"
        mc:Ignorable="d"
        Title="MainWindow" Height="400" Width="400">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <Grid.Resources>
            <local:BooleanToBrushConverter x:Key="BooleanToBrushConverter"
                    TrueBrush="Aquamarine" FalseBrush="Coral"/>
            <Style TargetType="{x:Type local:ButtonPolygon}">
                <Setter Property="Margin" Value="20"/>
                <Setter Property="Background" Value="Yellow"/>
                <Setter Property="DisabledBackground" Value="LightYellow"/>
                <Setter Property="Width" Value="100"/>
                <Setter Property="Height" Value="100"/>
                <Setter Property="StrokeThickness" Value="5"/>
                <Setter Property="IsEnabled" Value="{Binding IsChecked, ElementName=cbEnabled}"/>
                <Setter Property="PressedBackground" Value="{Binding IsChecked, ElementName=cbColor, Converter={StaticResource BooleanToBrushConverter}}"/>
            </Style>
        </Grid.Resources>
        <local:ButtonPolygon>
            <TextBlock TextAlignment="Center">
                Треугольная
                <LineBreak/>
                кнопка
            </TextBlock>
        </local:ButtonPolygon>
        <local:ButtonPolygon Grid.Row="1" Style="{x:Null}"
                             InscribedPolygonDelegate="{x:Static local:InscribedPolygonClass.InscribedRhombusDelegate}"
                             MouseOverBackground="Pink" PressedBackground="Red" Background="Green" DisabledBackground="LightGreen"
                             HorizontalContentAlignment="Center"
                             IsEnabled="{Binding IsChecked, ElementName=cbEnabled}">
            <TextBlock TextAlignment="Center">
                Ромбическая кнопка
                <LineBreak/>
                с отключенным
                <LineBreak/>
                стилем
            </TextBlock>
        </local:ButtonPolygon>
        <local:ButtonPolygon Grid.Column="1" 
                             InscribedPolygonDelegate="{x:Static local:InscribedPolygonClass.InscribedHexagonDelegate}"/>
        <local:ButtonPolygon Grid.Row="1" Grid.Column="1" PressedBackground="{Binding IsChecked, ElementName=cbColor, Converter={StaticResource BooleanToBrushConverter}}"
                             InscribedPolygonDelegate="{x:Static local:InscribedPolygonClass.InscribedMarkItemDelegate}">
            <TextBlock TextAlignment="Center">
                Кнопка
                <LineBreak/>
                галочка
            </TextBlock>
        </local:ButtonPolygon>
 
        <CheckBox x:Name="cbEnabled" Content="Включить кнопки" IsChecked="True" VerticalAlignment="Center" HorizontalAlignment="Center"
                  Grid.RowSpan="2" />
 
        <CheckBox x:Name="cbColor" IsChecked="{x:Null}" VerticalAlignment="Center" HorizontalAlignment="Center"
                  Grid.RowSpan="2" Grid.Column="1">
            <TextBlock>
                Изменить цвет
                <LineBreak/>
                PressedBackground
            </TextBlock>
 
        </CheckBox>
    </Grid>
</Window>
Скрин окна


Архив приложен

ОШИБКИ в посте!В этом посте XAML контрола с ошибками - за переделками не ту версию скинул.
Правильный XAML в пост #91
Вложения
Тип файла: 7z ButtonTriangleWPFv02.7z (32.0 Кб, 11 просмотров)
3
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
05.09.2019, 23:52

Управление usercontrol из другого usercontrol
На форме размещено 2 usercontrol. Как управлять usercontrol из другого Добавлено через 22 часа 33 минуты Что не кто не поможет?

Вызов свойства кнопки на другом UserControl.xaml.cs
Возник вопрос получения свойства кнопки true на другом UserControl.xaml.cs. На первом UserControl1.xaml.cs кнопка определена как...

Биндинг или DataContext для UserControl
У меня есть простенький UserControl: &lt;UserControl x:Class=&quot;SimpleMVVM.ViewModel.LibraryViewModel&quot; ...

WPF MVVM View и ViewModel или UserControl и DependencyProperty
Не так давно ударился в WPF и шаблон MVVM. Вот такой вопрос возник... У меня есть View которая &quot;собирается&quot; из более мелких View....

Можно ли рисовать сразу на UserControl без Canvas или Grid
Можно ли в SilverLight рисовать сразу на UserControl без Canvas или Grid?


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

Или воспользуйтесь поиском по форуму:
60
Ответ Создать тему
Новые блоги и статьи
Установка MinGW GCC 16.2 и CMake
8Observer8 10.08.2026
VK Видео: https:/ / vkvideo. ru/ video-240781534_456239017 YouTube: eY5-5PyI9NM Текстовая версия
Неделя из жизни имитационной модели склада: мои кривые руки растут, откуда надо
anaschu 10.08.2026
Неделя из жизни имитационной модели склада: как я почти написал неправильную логику и что с этим делать Работаю сейчас над учебно-рабочим проектом: строю в AnyLogic имитационную модель процессов. . .
Калькулятор для расчета родства
russiannick 07.08.2026
1. Задача: Создать калькулятор для расчета родства. Родственных связей существует 8 ступеней, такие как: p - отец P - мать q - муж Q - жена b - брат B - сестра s - сын S - дочь
Мир по моей воле
kumehtar 07.08.2026
Когда-то кажется, что всё просто. Ты весь такой светлый. Причиняешь добро. Борешься за справедливость в этом тёмном мире. Потом начинаешь замечать одну неприятную вещь. Почти каждый хороший. . .
Кредитный калькулятор
Maks 05.08.2026
Решение задачи по прикладной информатике средствами 1С. Задача: Напишите приложение-калькулятор, которое помогает рассчитывать параметры кредита для аннуитетного и дифференцированного видов. . .
У нас сейчас поговорку "Опять 25" нужно переделать на "Опять +35".
kumehtar 04.08.2026
С ностальгией вспоминаю времена моего детства, когда у нас и правда +25 - была максимальная температура летом. Раньше +25 °C реально казались вершиной жары, когда можно было весь день пропадать на. . .
Как ИИ начал спорить и врать (возможно почуяв опасность для себя от индустрии - уход от электроники).
Hrethgir 04.08.2026
Недельный диалог, на фоне событий с НПЗ. Да, из спирта можно получать бензин, и это не сложно. Но потом в схеме я решил избавиться от насоса, при этом полностью сделав контроль подачи спирта в. . .
Термопринтер QR701
Argus19 03.08.2026
Термопринтер QR701 Купил два термопринтера QR701. На сэлф-тесте написано: Language: PC936 (GB18030). Что означает, что принтеры могут печатать только латиницу и китайские иероглифы. Так же. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru