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

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

01.09.2019, 19:54. Показов 15581. Ответов 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
 Аватар для Элд Хасп
16140 / 11264 / 2888
Регистрация: 21.04.2018
Сообщений: 33,109
Записей в блоге: 2
01.09.2019, 20:54
Цитата Сообщение от Ахромчон Посмотреть сообщение
Хотелось бы UC со свойствами кнопки.
Мудрёно что-то.
Не понял чего реализовать-то хотите.
0
21 / 17 / 1
Регистрация: 01.09.2019
Сообщений: 262
01.09.2019, 21:13  [ТС]
да вот, не знаю...

Вообще нужен UserControl, который бы доставался из ToolBox (сверху). Как это обычно у UC.
Но свойства у него похожие на кастомную кнопку типа "scrolling down". Жмешь - меняет цвет Fill (зеленый). отпускаешь -Fill (белый)дефолтный. Event handler как у кнопки.
Да еще с возможность привязки Fill через биндинг. Например, прилетает Bool, -цвет меняет с дефолтного на такой же как при нажатии.
Миниатюры
Кастомная кнопка в UserControl или UserControl со свойствами кнопки  
0
21 / 17 / 1
Регистрация: 01.09.2019
Сообщений: 262
01.09.2019, 21:24  [ТС]
да, с polygon, что-то не так, углы до краев немного недостают, хотя координаты ясно заложены. Концы stroke загруглил, а они все-равно непонятно какие.

Вот код можете прикинуть у себя?

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
<UserControl x:Class="Button_testing.UserControls.Polygon_button_1"
             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"
            Width="90"
            Height="90"
            HorizontalAlignment="Center"
            VerticalAlignment="Center"
            >
 
 
                <Button.Template>
                    <ControlTemplate TargetType="{x:Type Button}">
 
                        <Grid Margin="0">
 
                        <Polygon
                        StrokeEndLineCap="Round"
                        StrokeStartLineCap="Round"
                        Fill="LawnGreen"
                        Points="0,0 90,0 45,90"
                        Stroke="Black"
                        StrokeThickness="0.5"/>
 
                        </Grid>
 
 
                    </ControlTemplate>
 
                </Button.Template>
            </Button>
 
 
        </Grid>
 
    
</UserControl>
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16140 / 11264 / 2888
Регистрация: 21.04.2018
Сообщений: 33,109
Записей в блоге: 2
01.09.2019, 21:31
Цитата Сообщение от Ахромчон Посмотреть сообщение
Вообще нужен UserControl, который бы доставался из ToolBox (сверху). Как это обычно у UC.
Но свойства у него похожие на кастомную кнопку...
В WPF элементы выбираются не по внешнему виду, а по ПОВЕДЕНИЮ!
У кнопки поведение - это выполнение команды по клику.
Вашему UC такое поведение нужно?
Если нет, то не надо и кнопку в него пихать.

Опишите подробнее поведение которое вы хотите от своего UC. Его внешний вид в разных состояниях.
Вот что это такое Event handler как у кнопки? Что ещё за Event handler?

Добавлено через 1 минуту
Цитата Сообщение от Ахромчон Посмотреть сообщение
Вот код можете прикинуть у себя?
Если вам нужна треугольная кнопка, то просто задайте шаблон для неё.

Сейчас скину пример.
0
21 / 17 / 1
Регистрация: 01.09.2019
Сообщений: 262
01.09.2019, 21:40  [ТС]
Элд Хасп,

Да, поведение как у кнопки.

Графически как на скрине выше. Форма не меняется.

1) Дефолтный цвет, например белый.

2) при нажатии меняется на зеленый,

3) отпускаешь -белый,

4) возможность биндинга свойства Fill,


event handler как у кнопки. "button click"


Цитата Сообщение от Элд Хасп Посмотреть сообщение
Если вам нужна треугольная кнопка, то просто задайте шаблон для неё.
У меня в коде выше уже есть шаблон. Это не удобно каждый раз шаблон. Два десятка шаблонов. Для таких целей делается User Control.
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16140 / 11264 / 2888
Регистрация: 21.04.2018
Сообщений: 33,109
Записей в блоге: 2
01.09.2019, 22:41
Вот пример шаблона и его использования
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
78
79
80
81
82
83
84
85
86
87
88
    <Window.Resources>
        <local:SizeToTriangleConverter x:Key="SizeToTriangleConverter"/>
        <Style x:Key="FocusVisual">
            <Setter Property="Control.Template">
                <Setter.Value>
                    <ControlTemplate>
                        <Rectangle Margin="2" SnapsToDevicePixels="true" Stroke="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}" StrokeThickness="1" StrokeDashArray="1 2"/>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
        <SolidColorBrush x:Key="Button.Static.Background" Color="#FFDDDDDD"/>
        <SolidColorBrush x:Key="Button.Static.Border" Color="#FF707070"/>
        <SolidColorBrush x:Key="Button.MouseOver.Background" Color="#FFBEE6FD"/>
        <SolidColorBrush x:Key="Button.MouseOver.Border" Color="#FF3C7FB1"/>
        <SolidColorBrush x:Key="Button.Pressed.Background" Color="#FFC4E5F6"/>
        <SolidColorBrush x:Key="Button.Pressed.Border" Color="#FF2C628B"/>
        <SolidColorBrush x:Key="Button.Disabled.Background" Color="#FFF4F4F4"/>
        <SolidColorBrush x:Key="Button.Disabled.Border" Color="#FFADB2B5"/>
        <sys:Double x:Key="Triangle.StrokeThickness">1</sys:Double>
        <Style x:Key="Button.Template.Triangle" TargetType="{x:Type Button}">
            <Setter Property="FocusVisualStyle" Value="{StaticResource FocusVisual}"/>
            <Setter Property="Background" Value="{StaticResource Button.Static.Background}"/>
            <Setter Property="BorderBrush" Value="{StaticResource Button.Static.Border}"/>
            <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
            <Setter Property="BorderThickness" Value="1"/>
            <Setter Property="HorizontalContentAlignment" Value="Center"/>
            <Setter Property="VerticalContentAlignment" Value="Center"/>
            <Setter Property="Padding" Value="1"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type Button}">
                        <Grid SnapsToDevicePixels="true">
                            <Grid x:Name="PART_Grid"  Margin="{TemplateBinding Padding}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}">
                                <Polygon x:Name="PART_Polygon" Grid.ColumnSpan="2" Points="{Binding Tag, RelativeSource={RelativeSource Self}}"  
                                     Stroke="{TemplateBinding BorderBrush}" StrokeThickness="{DynamicResource Triangle.StrokeThickness}"
                                     Fill="{TemplateBinding Background}">
                                    <Polygon.Tag>
                                        <MultiBinding Converter="{StaticResource SizeToTriangleConverter}">
                                            <Binding Path="ActualWidth" ElementName="PART_Grid" Mode="OneWay"/>
                                            <Binding  Path="ActualHeight" ElementName="PART_Grid" Mode="OneWay"/>
                                        </MultiBinding>
                                    </Polygon.Tag>
                                </Polygon>
                            </Grid>
                        </Grid>
                        <ControlTemplate.Triggers>
                            <Trigger Property="IsMouseOver" Value="true">
                                <Setter Property="Fill" TargetName="PART_Polygon" Value="{DynamicResource Button.MouseOver.Background}"/>
                                <Setter Property="Stroke" TargetName="PART_Polygon" Value="{DynamicResource Button.MouseOver.Border}"/>
                            </Trigger>
                            <Trigger Property="IsPressed" Value="true">
                                <Setter Property="Fill" TargetName="PART_Polygon" Value="{DynamicResource Button.Pressed.Background}"/>
                                <Setter Property="Stroke" TargetName="PART_Polygon" Value="{DynamicResource Button.Pressed.Border}"/>
                            </Trigger>
                            <Trigger Property="IsEnabled" Value="false">
                                <Setter Property="Fill" TargetName="PART_Polygon" Value="{DynamicResource Button.Disabled.Background}"/>
                                <Setter Property="Stroke" TargetName="PART_Polygon" Value="{DynamicResource Button.Disabled.Border}"/>
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </Window.Resources>
    <Grid>
        <Button Style="{DynamicResource Button.Template.Triangle}"
                BorderBrush="LightBlue" Background="LightGreen"
               IsEnabled="False">
            <Button.Resources>
                <!--Толщина границы-->
                <sys:Double x:Key="Triangle.StrokeThickness">5</sys:Double>
 
                <!--Цвета при наведении курсора мыши-->
                <SolidColorBrush x:Key="Button.MouseOver.Background" Color="Green"/>
                <SolidColorBrush x:Key="Button.MouseOver.Border" Color="Blue"/>
                
                <!--Цвета при нажатии-->
                <SolidColorBrush x:Key="Button.Pressed.Background" Color="Pink"/>
                <SolidColorBrush x:Key="Button.Pressed.Border" Color="Red"/>
                
                <!--Цвета при неактивной конопке-->
                <SolidColorBrush x:Key="Button.Disabled.Background" Color="LightGreen" Opacity="0.5"/>
                <SolidColorBrush x:Key="Button.Disabled.Border" Color="LightBlue" Opacity="0.5"/>
 
            </Button.Resources>
        </Button>
    </Grid>
Добавлено через 3 минуты
Цитата Сообщение от Ахромчон Посмотреть сообщение
У меня в коде выше уже есть шаблон. Это не удобно каждый раз шаблон. Два десятка шаблонов. Для таких целей делается User Control.
UserControl имеет смысл делать только если вам нужно сочетание нескольких элементов.
Все шаблоны надо держать отдельно в словаре, в окне же подключаете нужные словари и просто указываете в элементе какой шаблон надо взять.

Если вам нужна кастомная кнопка, то можно переопределить класс кнопки - это лучше чем делать UserContolr.

Добавлено через 27 секунд
Забыл код конвертера скинуть

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
    public class SizeToTriangleConverter : IMultiValueConverter
    {
        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
        {
            if
            (
                values?.Length == 2
                && double.TryParse(values[0]?.ToString(), out double width)
                && double.TryParse(values[1]?.ToString(), out double height))
                return new PointCollection(new Point[] { new Point(0, 0), new Point(width, 0), new Point(0.5 * width, height) });
            return null;
        }
 
        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
0
21 / 17 / 1
Регистрация: 01.09.2019
Сообщений: 262
01.09.2019, 22:58  [ТС]
Элд Хасп,

Что-то много всего для такой простой задачи. Завтра потестирую.
В отличие от UC который перетащил на поле и пользуешься, не понимаю как пользоваться вашим кодом, куда вставлять, а потом как пользоваться.

Куда <Window.Resources> вставлять?
Куда <Grid>?
И куда конвертер?
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16140 / 11264 / 2888
Регистрация: 21.04.2018
Сообщений: 33,109
Записей в блоге: 2
01.09.2019, 23:41
Вот переопределённая кнопка
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
    /// <summary>
    /// Логика взаимодействия для ButtonTriangle.xaml
    /// </summary>
    public partial class ButtonTriangle : Button
    {
        public ButtonTriangle()
        {
            InitializeComponent();
        }
 
        static BrushConverter brushConverter = new BrushConverter();
 
        public PointCollection Points
        {
            get { return (PointCollection)GetValue(PointsProperty); }
            set { SetValue(PointsProperty, value); }
        }
 
        // Using a DependencyProperty as the backing store for Points.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty PointsProperty =
            DependencyProperty.Register(nameof(Points), typeof(PointCollection), typeof(ButtonTriangle), new PropertyMetadata(null));
 
        private void PART_Grid_SizeChanged(object sender, SizeChangedEventArgs e) 
            => Points = new PointCollection(new Point[] { new Point(0, 0), new Point(e.NewSize.Width, 0), new Point(0.5 * e.NewSize.Width, e.NewSize.Height) });
 
 
 
        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(ButtonTriangle), new PropertyMetadata(1.0));
 
 
 
        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(ButtonTriangle), new PropertyMetadata(brushConverter.ConvertFrom("#FFBEE6FD")));
 
 
 
        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(ButtonTriangle), new PropertyMetadata(brushConverter.ConvertFrom("#FF3C7FB1")));
 
 
 
        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(ButtonTriangle), new PropertyMetadata(brushConverter.ConvertFrom("#FFC4E5F6")));
 
 
 
        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(ButtonTriangle), new PropertyMetadata(brushConverter.ConvertFrom("#FF2C628B")));
 
 
 
        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(ButtonTriangle), new PropertyMetadata(brushConverter.ConvertFrom("#FFF4F4F4")));
 
 
 
 
        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(ButtonTriangle), new PropertyMetadata(brushConverter.ConvertFrom("#FFADB2B5")));
 
 
 
 
    }
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
<Button x:Name="PART_MainButton" x:Class="CyberForum.ButtonTriangle"
             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:CyberForum"
             xmlns:sys="clr-namespace:System;assembly=mscorlib"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800">
    <Button.Resources>
        <Style x:Key="FocusVisual">
            <Setter Property="Control.Template">
                <Setter.Value>
                    <ControlTemplate>
                        <Rectangle Margin="2" SnapsToDevicePixels="true" Stroke="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}" StrokeThickness="1" StrokeDashArray="1 2"/>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
        <SolidColorBrush x:Key="Button.Static.Background" Color="#FFDDDDDD"/>
        <SolidColorBrush x:Key="Button.Static.Border" Color="#FF707070"/>
        <!--<SolidColorBrush x:Key="Button.MouseOver.Background" Color="#FFBEE6FD"/>
        <SolidColorBrush x:Key="Button.MouseOver.Border" Color="#FF3C7FB1"/>
        <SolidColorBrush x:Key="Button.Pressed.Background" Color="#FFC4E5F6"/>
        <SolidColorBrush x:Key="Button.Pressed.Border" Color="#FF2C628B"/>
        <SolidColorBrush x:Key="Button.Disabled.Background" Color="#FFF4F4F4"/>
        <SolidColorBrush x:Key="Button.Disabled.Border" Color="#FFADB2B5"/>
        <sys:Double x:Key="Triangle.StrokeThickness">1</sys:Double>-->
        <Style x:Key="Button.Template.Triangle" TargetType="{x:Type Button}">
            <Setter Property="FocusVisualStyle" Value="{StaticResource FocusVisual}"/>
            <Setter Property="Background" Value="{StaticResource Button.Static.Background}"/>
            <Setter Property="BorderBrush" Value="{StaticResource Button.Static.Border}"/>
            <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
            <Setter Property="BorderThickness" Value="1"/>
            <Setter Property="HorizontalContentAlignment" Value="Center"/>
            <Setter Property="VerticalContentAlignment" Value="Center"/>
            <Setter Property="Padding" Value="1"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type Button}">
                        <Grid SnapsToDevicePixels="true">
                            <Grid x:Name="PART_Grid"  Margin="{TemplateBinding Padding}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
                                  SizeChanged="PART_Grid_SizeChanged">
                                <Polygon x:Name="PART_Polygon" Grid.ColumnSpan="2" Points="{Binding Points, Mode=OneWay, ElementName=PART_MainButton}"  
                                     Stroke="{TemplateBinding BorderBrush}" StrokeThickness="{Binding StrokeThickness, Mode=OneWay, ElementName=PART_MainButton}"
                                     Fill="{TemplateBinding Background}"/>
                            </Grid>
                        </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}"/>
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </Button.Resources>
    <Button.Style>
        <Binding Mode="OneWay" Source="{StaticResource Button.Template.Triangle}"/>
    </Button.Style>
</Button>
Её использование
XML
1
2
3
4
5
        <local:ButtonTriangle BorderBrush="LightBlue" Background="LightGreen"
                              IsEnabled="True" StrokeThickness="5"
                              MouseOverBackground="Green" MouseOverBorder="Blue"
                              PressedBackground="Pink" PressedBorder="Red"
                              DisabledBackground="#7F90EE90" DisabledBorder="#7FADD8E6"/>
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16140 / 11264 / 2888
Регистрация: 21.04.2018
Сообщений: 33,109
Записей в блоге: 2
01.09.2019, 23:46
Цитата Сообщение от Ахромчон Посмотреть сообщение
Куда <Window.Resources> вставлять?
Это ресурсы окна.
Вы, вообще, что-то знаете про ресурсы, словари в XAML?
Это относится к базовым знаниям. Без них изучать что-то более сложное - бессмыслен.

Цитата Сообщение от Ахромчон Посмотреть сообщение
Куда <Grid>?
Это основной элемент окна.
У вас может быть тоже Grid, Может другой. Это роль не играет - просто пример использования.

Цитата Сообщение от Ахромчон Посмотреть сообщение
И куда конвертер?
Это обычный класс.
Добавляете в проект класс с этим именем, а в тело класса вставляете код.
0
21 / 17 / 1
Регистрация: 01.09.2019
Сообщений: 262
02.09.2019, 09:27  [ТС]
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Это ресурсы окна.
Вы, вообще, что-то знаете про ресурсы, словари в XAML?
Это относится к базовым знаниям. Без них изучать что-то более сложное - бессмыслен.
Начал тестировать, чудной подход, но интересно что из этого получится. Т.к. вы всегда помогаете по делу.
Если ресурсы окна, то это обычно так выглядит:

XML
1
2
3
4
5
6
7
8
9
<Window>
 
<Window.Resources>
 
<!-- Черным по белому видно само окно и встроенные в него ресурсы-->
 
</Window.Resources>
 
</Window>
У вас же button везде и ресурсы именно button. Поэтому и вопросы. Не видел я еще такого.

Добавлено через 15 минут
Можно это в проекте увидеть , как единое целое?
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16140 / 11264 / 2888
Регистрация: 21.04.2018
Сообщений: 33,109
Записей в блоге: 2
02.09.2019, 12:06
Цитата Сообщение от Ахромчон Посмотреть сообщение
Можно это в проекте увидеть , как единое целое?
Я не делал отдельного решения.
У меня есть проект для мелких тестовых кодов. В нём несколько десятков различных задач. Вот в нём и делал.

Опишу полный состав обоих вариантов
В проекте с пространством имён namespace CyberForum нужны следующие файлы:

Сначала вариант с шаблоном

Файл конвертера для получения точек вписанного треугольника SizeToTriangleConverter.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
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
using System.Windows.Media;
 
namespace CyberForum
{
    /// <summary>Класс конвертера - возвращает PointCollection с точками вписанными в заданные размеры</summary>
    public class SizeToTriangleConverter : IMultiValueConverter
    {
        /// <summary>Получает размеры и возвращает точки вписанного треугольника</summary>
        /// <param name="values">Массив с размерами</param>
        /// <param name="targetType"></param>
        /// <param name="parameter"></param>
        /// <param name="culture"></param>
        /// <returns>PointCollection с точками треугольника</returns>
        /// <remarks>В конвертер должны быть по привязкам переданы values[0]=Width и values[1]=Height
        /// области в которую надо вписать треугольник. Конвертер возвращает коллекцию вершин треугольника
        /// у которого верхняя сторона совпадает с верхней стороной переданной области, нижняя вершина 
        /// находится по середине нижней стороны области.
        /// Можно изменив получаемую фигуру изменив возвращаемую коллекцию точек.</remarks>
        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
        {
            if
            (
                values?.Length == 2
                && double.TryParse(values[0]?.ToString(), out double width)
                && double.TryParse(values[1]?.ToString(), out double height))
                return new PointCollection(new Point[] { new Point(0, 0), new Point(width, 0), new Point(0.5 * width, height) });
            return null;
        }
 
        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
}
Этот конвертер нужен для автоматического получения списка точек вершин треугольника в области выделенной для кнопки. Если нужна другая фигура, то надо создать подобный конвертер изменив возвращаемый список.

Для шаблона сначала получил дефолтный шаблон кнопки и внёс в него необходимые изменения. Шаблон лежит в ресурсах окна. Но так сделано для удобства примера. При реальном использовании этот шаблон нужно держать в словаре. А словарь подключить к ресурсам приложения в файле App.xaml. Для возможности изменения цветов в шаблоне используются привязки к DynamicResource. Изменяя соответствующие ресурсы в более близком расположении - будут меняться и заданные ими цвета. Контент кнопки не выводится - я не увидел, что вы его используете поэтому сделал также. Но если нужно вывести контент -надо в шаблон добавить ConntentPresenter поверх Polygon

В примере по шаблону создаётся две кнопки. Одна с дефолтными значениями, вторая со значениями задаваемыми из собственных ресурсов. Так же есть CheckBox для проверки цветов не активных кнопок.

Файл MainWindow.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
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
<Window x:Class="CyberForum.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:CyberForum"
        xmlns:sys="clr-namespace:System;assembly=mscorlib"
        mc:Ignorable="d" 
        Title="MainWindow" Width="300" Height="600"
        >
    <Window.Resources>
        <local:SizeToTriangleConverter x:Key="SizeToTriangleConverter"/>
        <Style x:Key="FocusVisual">
            <Setter Property="Control.Template">
                <Setter.Value>
                    <ControlTemplate>
                        <Rectangle Margin="2" SnapsToDevicePixels="true" Stroke="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}" StrokeThickness="1" StrokeDashArray="1 2"/>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
        <SolidColorBrush x:Key="Button.Static.Background" Color="#FFDDDDDD"/>
        <SolidColorBrush x:Key="Button.Static.Border" Color="#FF707070"/>
        <SolidColorBrush x:Key="Button.MouseOver.Background" Color="#FFBEE6FD"/>
        <SolidColorBrush x:Key="Button.MouseOver.Border" Color="#FF3C7FB1"/>
        <SolidColorBrush x:Key="Button.Pressed.Background" Color="#FFC4E5F6"/>
        <SolidColorBrush x:Key="Button.Pressed.Border" Color="#FF2C628B"/>
        <SolidColorBrush x:Key="Button.Disabled.Background" Color="#FFF4F4F4"/>
        <SolidColorBrush x:Key="Button.Disabled.Border" Color="#FFADB2B5"/>
        <sys:Double x:Key="Triangle.StrokeThickness">1</sys:Double>
        <Style x:Key="Button.Template.Triangle" TargetType="{x:Type Button}">
            <Setter Property="FocusVisualStyle" Value="{StaticResource FocusVisual}"/>
            <Setter Property="Background" Value="{StaticResource Button.Static.Background}"/>
            <Setter Property="BorderBrush" Value="{StaticResource Button.Static.Border}"/>
            <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
            <Setter Property="BorderThickness" Value="1"/>
            <Setter Property="HorizontalContentAlignment" Value="Center"/>
            <Setter Property="VerticalContentAlignment" Value="Center"/>
            <Setter Property="Padding" Value="1"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type Button}">
                        <Grid SnapsToDevicePixels="true">
                            <Grid x:Name="PART_Grid"  Margin="{TemplateBinding Padding}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}">
                                <Polygon x:Name="PART_Polygon" Grid.ColumnSpan="2" Points="{Binding Tag, RelativeSource={RelativeSource Self}}"  
                                     Stroke="{TemplateBinding BorderBrush}" StrokeThickness="{DynamicResource Triangle.StrokeThickness}"
                                     Fill="{TemplateBinding Background}">
                                    <Polygon.Tag>
                                        <MultiBinding Converter="{StaticResource SizeToTriangleConverter}">
                                            <Binding Path="ActualWidth" ElementName="PART_Grid" Mode="OneWay"/>
                                            <Binding  Path="ActualHeight" ElementName="PART_Grid" Mode="OneWay"/>
                                        </MultiBinding>
                                    </Polygon.Tag>
                                </Polygon>
                            </Grid>
                        </Grid>
                        <ControlTemplate.Triggers>
                            <Trigger Property="IsMouseOver" Value="true">
                                <Setter Property="Fill" TargetName="PART_Polygon" Value="{DynamicResource Button.MouseOver.Background}"/>
                                <Setter Property="Stroke" TargetName="PART_Polygon" Value="{DynamicResource Button.MouseOver.Border}"/>
                            </Trigger>
                            <Trigger Property="IsPressed" Value="true">
                                <Setter Property="Fill" TargetName="PART_Polygon" Value="{DynamicResource Button.Pressed.Background}"/>
                                <Setter Property="Stroke" TargetName="PART_Polygon" Value="{DynamicResource Button.Pressed.Border}"/>
                            </Trigger>
                            <Trigger Property="IsEnabled" Value="false">
                                <Setter Property="Fill" TargetName="PART_Polygon" Value="{DynamicResource Button.Disabled.Background}"/>
                                <Setter Property="Stroke" TargetName="PART_Polygon" Value="{DynamicResource Button.Disabled.Border}"/>
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </Window.Resources>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition Height="Auto"/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <!--Кнопка с дефолтными цветами и шириной границы -->
        <Button Margin="20"
                Style="{StaticResource Button.Template.Triangle}"
                IsEnabled="{Binding IsChecked, ElementName=cbEnabled}"/>
        
        <!--Кнопка с заданными в ресурсах цветами и шириной границы -->
        <Button Grid.Row="2" Margin="20"
                Style="{DynamicResource Button.Template.Triangle}"
                BorderBrush="LightBlue" Background="LightGreen"
                IsEnabled="{Binding IsChecked, ElementName=cbEnabled}">
            <Button.Resources>
                <!--Толщина границы-->
                <sys:Double x:Key="Triangle.StrokeThickness">5</sys:Double>
 
                <!--Цвета при наведении курсора мыши-->
                <SolidColorBrush x:Key="Button.MouseOver.Background" Color="Green"/>
                <SolidColorBrush x:Key="Button.MouseOver.Border" Color="Blue"/>
 
                <!--Цвета при нажатии-->
                <SolidColorBrush x:Key="Button.Pressed.Background" Color="Pink"/>
                <SolidColorBrush x:Key="Button.Pressed.Border" Color="Red"/>
 
                <!--Цвета для неактивной кнопки-->
                <SolidColorBrush x:Key="Button.Disabled.Background" Color="LightGreen" Opacity="0.5"/>
                <SolidColorBrush x:Key="Button.Disabled.Border" Color="LightBlue" Opacity="0.5"/>
 
            </Button.Resources>
        </Button>
        
        <!--CheckBox для проверки цвета неактивной кнопки-->
        <Border Grid.Row="1" BorderThickness="2" BorderBrush="Gray" Padding="5">
            <CheckBox x:Name="cbEnabled" Content="Включить кнопки" IsChecked="False"/>
        </Border>
    </Grid>
</Window>
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16140 / 11264 / 2888
Регистрация: 21.04.2018
Сообщений: 33,109
Записей в блоге: 2
02.09.2019, 12:28
Цитата Сообщение от Ахромчон Посмотреть сообщение
в проекте увидеть
Второй вариант.

Создаём кастомную кнопку.
Для этого добавляем в проект UserControl с названием ButtonTriangle. Потом меняем в созданной рыбе базовый класс заменяя в xaml и xaml.cs UserControl на Button
XML
1
2
3
4
5
6
7
8
<Button      x:Class="CyberForum.ButtonTriangle"
             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:CyberForum"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800">
C#
1
2
3
4
5
6
7
8
9
    /// <summary>
    /// Логика взаимодействия для ButtonTriangle.xaml
    /// </summary>
    public partial class ButtonTriangle : Button
    {
        public ButtonTriangle()
        {
            InitializeComponent();
        }
Так как в данном случае для изменения параметров кнопки (толщины границы и цветов) нужны внешние свойства, то в CB надо задать все эти DP-свойства. Так же так как мы получаем доступ к событиям элементов шаблона, то вместо конвертера будем использовать событие изменения размеров и в нём вычислять список вершин. Так как шаблон уже готовый есть, то сделаем на его базе. Заменим только получение списка вершин в Polygon. Вычисляемый список вершин в событии <Grid x:Name="PART_Grid" SizeChanged="PART_Grid_SizeChanged"> будем помещать в свойство контрола Points и будем получать оттуда по привязке ElementName=PART_MainButton. Так же с остальными необходимыми значениями (ширина границы и цвета) - все они получают значения по привязкам ElementName=PART_MainButton.

Файл ButtonTriangle.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
<Button x:Name="PART_MainButton" x:Class="CyberForum.ButtonTriangle"
        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"
        mc:Ignorable="d" 
        d:DesignHeight="450" d:DesignWidth="800">
    <Button.Resources>
        <Style x:Key="FocusVisual">
            <Setter Property="Control.Template">
                <Setter.Value>
                    <ControlTemplate>
                        <Rectangle Margin="2" SnapsToDevicePixels="true" Stroke="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}" StrokeThickness="1" StrokeDashArray="1 2"/>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
        <SolidColorBrush x:Key="Button.Static.Background" Color="#FFDDDDDD"/>
        <SolidColorBrush x:Key="Button.Static.Border" Color="#FF707070"/>
        <Style x:Key="Button.Template.Triangle" TargetType="{x:Type Button}">
            <Setter Property="FocusVisualStyle" Value="{StaticResource FocusVisual}"/>
            <Setter Property="Background" Value="{StaticResource Button.Static.Background}"/>
            <Setter Property="BorderBrush" Value="{StaticResource Button.Static.Border}"/>
            <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
            <Setter Property="BorderThickness" Value="1"/>
            <Setter Property="HorizontalContentAlignment" Value="Center"/>
            <Setter Property="VerticalContentAlignment" Value="Center"/>
            <Setter Property="Padding" Value="1"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type Button}">
                        <Grid SnapsToDevicePixels="true">
                            <Grid x:Name="PART_Grid"  Margin="{TemplateBinding Padding}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
                                  SizeChanged="PART_Grid_SizeChanged">
                                <Polygon x:Name="PART_Polygon" Grid.ColumnSpan="2" Points="{Binding Points, Mode=OneWay, ElementName=PART_MainButton}"  
                                     Stroke="{TemplateBinding BorderBrush}" StrokeThickness="{Binding StrokeThickness, Mode=OneWay, ElementName=PART_MainButton}"
                                     Fill="{TemplateBinding Background}"/>
                            </Grid>
                        </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}"/>
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </Button.Resources>
    <Button.Style>
        <Binding Mode="OneWay" Source="{StaticResource Button.Template.Triangle}"/>
    </Button.Style>
</Button>
Файл ButtonTriangle.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
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
 
namespace CyberForum
{
    /// <summary>
    /// Логика взаимодействия для ButtonTriangle.xaml
    /// </summary>
    public partial class ButtonTriangle : Button
    {
        public ButtonTriangle()
        {
            InitializeComponent();
        }
 
        static BrushConverter brushConverter = new BrushConverter();
 
        public PointCollection Points
        {
            get { return (PointCollection)GetValue(PointsProperty); }
            set { SetValue(PointsProperty, value); }
        }
 
        // Using a DependencyProperty as the backing store for Points.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty PointsProperty =
            DependencyProperty.Register(nameof(Points), typeof(PointCollection), typeof(ButtonTriangle), new PropertyMetadata(null));
 
        private void PART_Grid_SizeChanged(object sender, SizeChangedEventArgs e) 
            => Points = new PointCollection(new Point[] { new Point(0, 0), new Point(e.NewSize.Width, 0), new Point(0.5 * e.NewSize.Width, e.NewSize.Height) });
 
 
 
        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(ButtonTriangle), new PropertyMetadata(1.0));
 
 
 
        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(ButtonTriangle), new PropertyMetadata(brushConverter.ConvertFrom("#FFBEE6FD")));
 
 
 
        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(ButtonTriangle), new PropertyMetadata(brushConverter.ConvertFrom("#FF3C7FB1")));
 
 
 
        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(ButtonTriangle), new PropertyMetadata(brushConverter.ConvertFrom("#FFC4E5F6")));
 
 
 
        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(ButtonTriangle), new PropertyMetadata(brushConverter.ConvertFrom("#FF2C628B")));
 
 
 
        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(ButtonTriangle), new PropertyMetadata(brushConverter.ConvertFrom("#FFF4F4F4")));
 
 
 
 
        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(ButtonTriangle), new PropertyMetadata(brushConverter.ConvertFrom("#FFADB2B5")));
 
    }
}
Пример использования - аналогичен предыдущему.

Файл MainWindow.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
<Window x:Class="CyberForum.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:CyberForum"
        mc:Ignorable="d" 
        Title="MainWindow" Width="300" Height="600"
        >
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition Height="Auto"/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <!--Кнопка с дефолтными цветами и шириной границы -->
        <local:ButtonTriangle Margin="20"
                              IsEnabled="{Binding IsChecked, ElementName=cbEnabled}"/>
        
        <!--Кнопка с заданными в ресурсах цветами и шириной границы -->
        <local:ButtonTriangle Grid.Row="2" Margin="20" BorderBrush="LightBlue" Background="LightGreen"
                              IsEnabled="{Binding IsChecked, ElementName=cbEnabled}" StrokeThickness="5"
                              MouseOverBackground="Green" MouseOverBorder="Blue"
                              PressedBackground="Pink" PressedBorder="Red"
                              DisabledBackground="#7F90EE90" DisabledBorder="#7FADD8E6"/>
        
        <!--CheckBox для проверки цвета неактивной кнопки-->
        <Border Grid.Row="1" BorderThickness="2" BorderBrush="Gray" Padding="5">
            <CheckBox x:Name="cbEnabled" Content="Включить кнопки" IsChecked="False"/>
        </Border>
    </Grid>
</Window>
0
21 / 17 / 1
Регистрация: 01.09.2019
Сообщений: 262
02.09.2019, 14:01  [ТС]
Добрый день,
попытался имплементировать вар1 в свое тестовое решение.

SizeToTriangleConverter.cs выдал кучу ошибок, часть которых удалось убрать, часть нет. Список ниже.

-type SizeToTriangleConverter already defines a member convert with the same parameter types. Та же история c ConvertBack.

-invalid expression term 'double'.

-the term 'width' does not exist in the current context.
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16140 / 11264 / 2888
Регистрация: 21.04.2018
Сообщений: 33,109
Записей в блоге: 2
02.09.2019, 15:19
Цитата Сообщение от Ахромчон Посмотреть сообщение
выдал кучу ошибок, часть которых удалось убрать, часть нет. Список ниже.
Навскидку - у вас в решении почему-то два класса SizeToTriangleConverter.
Что лишнее задублировали.
1
21 / 17 / 1
Регистрация: 01.09.2019
Сообщений: 262
02.09.2019, 15:29  [ТС]
Вскидка оказалась верной.

Все еще ругается на:

-invalid expression term 'double'.

-the term 'width' does not exist in the current context.
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16140 / 11264 / 2888
Регистрация: 21.04.2018
Сообщений: 33,109
Записей в блоге: 2
02.09.2019, 15:35
Цитата Сообщение от Ахромчон Посмотреть сообщение
попытался имплементировать вар1 в свое тестовое решение.
Цитата Сообщение от Ахромчон Посмотреть сообщение
Все еще ругается на:
Скидываю архив проекта - специально создал для проверки обоих вариантов
Вложения
Тип файла: 7z ButtonTriangleWPF.7z (26.4 Кб, 12 просмотров)
1
21 / 17 / 1
Регистрация: 01.09.2019
Сообщений: 262
02.09.2019, 17:20  [ТС]
Спасибо,


чтобы запустить пришлось установить свежий netframework 4.8.
Проект исполняется.
Что странно,
в конвертере 'красное подчеркивание' под:

double; invalid expression term.
width; the name 'width' does not exist in the current context.
height; the name 'height' does not exist in the current context.


остается как писал выше. Хотя проект исполняется. Что может быть?

Добавлено через 6 минут
файл ButtonTriangle.xaml что есть на научном языке? Это и есть UC?
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16140 / 11264 / 2888
Регистрация: 21.04.2018
Сообщений: 33,109
Записей в блоге: 2
02.09.2019, 21:53
Ахромчон -> файл ButtonTriangle.xaml что есть на научном языке? Это и есть UC?
В данном случае, производный от Button класс.

Добавлено через 2 минуты
Ахромчон -> в конвертере 'красное подчеркивание' под:
Не знаю в чем может быть проблема.
0
21 / 17 / 1
Регистрация: 01.09.2019
Сообщений: 262
02.09.2019, 22:02  [ТС]
Цитата Сообщение от Элд Хасп Посмотреть сообщение
Ахромчон -> в конвертере 'красное подчеркивание' под:
Не знаю в чем может быть проблема.
Т.к. вариант с конвертером "косячный" с точки зрения 'чистоты' проекта, какие-то непонятные ошибки на ровном месте, я имплементировал второй, тот который UC. Второй 'чистый' и завтра буду тестить с ним биндинг.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
02.09.2019, 22:02
Помогаю со студенческими работами здесь

Управление 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?


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

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Новые блоги и статьи
SDL3 для Desktop (MinGW): Создаём пустое окно с нуля для 2D-графики на SDL3, Си и C++
8Observer8 10.03.2026
Содержание блога Финальные проекты на Си и на C++: hello-sdl3-c. zip hello-sdl3-cpp. zip Результат:
Установка CMake и MinGW 13.1 для сборки С и C++ приложений из консоли и из Qt Creator в EXE
8Observer8 10.03.2026
Содержание блога MinGW - это коллекция инструментов для сборки приложений в EXE. CMake - это система сборки приложений. Здесь описаны базовые шаги для старта программирования с помощью CMake и. . .
Как дизайн сайта влияет на конверсию: 7 решений, которые реально повышают заявки
Neotwalker 08.03.2026
Многие до сих пор воспринимают дизайн сайта как “красивую оболочку”. На практике всё иначе: дизайн напрямую влияет на то, оставит человек заявку или уйдёт через несколько секунд. Даже если у вас. . .
Модульная разработка через nuget packages
DevAlt 07.03.2026
Сложившийся в . Net-среде способ разработки чаще всего предполагает монорепозиторий в котором находятся все исходники. При создании нового решения, мы просто добавляем нужные проекты и имеем. . .
Модульный подход на примере F#
DevAlt 06.03.2026
В блоге дяди Боба наткнулся на такое определение: В этой книге («Подход, основанный на вариантах использования») Ивар утверждает, что архитектура программного обеспечения — это структуры,. . .
Управление камерой с помощью скрипта OrbitControls.js на Three.js: Вращение, зум и панорамирование
8Observer8 05.03.2026
Содержание блога Финальная демка в браузере работает на Desktop и мобильных браузерах. Итоговый код: orbit-controls-threejs-js. zip. Сканируйте QR-код на мобильном. Вращайте камеру одним пальцем,. . .
SDL3 для Web (WebAssembly): Синхронизация спрайтов SDL3 и тел Box2D
8Observer8 04.03.2026
Содержание блога Финальная демка в браузере. Итоговый код: finish-sync-physics-sprites-sdl3-c. zip На первой гифке отладочные линии отключены, а на второй включены:. . .
SDL3 для Web (WebAssembly): Идентификация объектов на Box2D v3 - использование userData и событий коллизий
8Observer8 02.03.2026
Содержание блога Финальная демка в браузере. Итоговый код: finish-collision-events-sdl3-c. zip Сканируйте QR-код на мобильном и вы увидите, что появится джойстик для управления главным героем. . . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru