Форум программистов, компьютерный форум, киберфорум
Наши страницы
C#: WPF, UWP и Silverlight
Войти
Регистрация
Восстановить пароль
 
Casper-SC
Эксперт .NET
4007 / 1919 / 375
Регистрация: 27.03.2010
Сообщений: 5,291
Записей в блоге: 1
1

[UWP/WPF] Сделать подмену значений свойств, если Enum изменился

20.07.2019, 17:04. Просмотров 214. Ответов 0
Метки нет (Все метки)

Всем привет.

Клонировать репозиторий: git clone https://CasperSC@bitbucket.org/CasperSC/extendedproperty.git (введение в Git)
Репозиторий

Кратко: мне нужно создать класс, который умеет менять значение своего свойства (Dependency property), когда меняется значение энума (Dependency property). При этом нужно уметь это настраивать из XAML, чтобы получив входной конфиг, генератор сгенерил XAML, который бы автоматом в дальнейшем после его добавлена в проект (или замены старого) применился к классу. Далее конфиг может измениться, генератор снова сгенерит новый XAML, сами данные поменяются, но принцип работы класса не изменится. Генератор здесь не рассматривается.

Конфиг. Конкрентый формат не важен, важно понимание, что он задаёт. От конфига не уйти, он есть и нужно реализовать работу кода так, чтобы если поменялся конфиг, то генератор сгенерил стили и т.д., оно всё применилось к коду и работает после того, как я новые стили добавлю в проект заменив старые:
Свойства StyleObject TStyle:
* Если TimeOfDay равен UntilNoon, то StyleObject.PrimaryColor зелёный
* Если TimeOfDay равен Afternoon, то StyleObject.PrimaryColor красный

* Если TimeOfDay равен UntilNoon, то SizeObject.Width 100
* Если TimeOfDay равен Afternoon, то SizeObject.Width 120



Подробно:
Есть класс, в котором есть Dependency property, у которого тип - это какой-то Enum. Нужно, чтобы при изменении значения Enum(a) менялись другие свойства. В некотором роде это должно работать, как подмена шаблона в DataTemplateSelector.

В чём трудность: есть конфиг файл, в котором заданы значения для, например, enum TimeOfDay { UntilNoon, Afternoon }. То есть, значения для свойств класса при разных значениях TimeOfDay. И есть две программы. Одна генератор ресурсов и стилей по этому конфигу, а вторая программа это основное ПО, которое стилизуется с помощью конфига.

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

Пример, из которого должно стать понятнее, что я хочу (TimeOfDayObject можно ещё разбить на два класса, сделать его базовым без конкретного энума, но мне пока это не важно, пока решить проблему нужно):
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
using System;
using Windows.UI.Xaml;
using ExtendedProperty.Controls.Config;
 
namespace ExtendedProperty.Base
{
    public class TimeOfDayObject<TValue> : DependencyObject
    {
        public static readonly DependencyProperty CommonValueProperty = DependencyProperty.Register(
            nameof(CommonValue), typeof(TValue), typeof(TimeOfDayObject<TValue>), new PropertyMetadata(null,
                (o, args) => ((TimeOfDayObject<TValue>)o).UpdateActualValue()));
 
        /// <summary>
        /// Основное значение. Если задано, другие значения, задающиеся состоянием перечисления игнорируются.
        /// </summary>
        public TValue CommonValue
        {
            get { return (TValue)GetValue(CommonValueProperty); }
            set { SetValue(CommonValueProperty, value); }
        }
 
        #region Values - Incomplete time of day
 
        public static readonly DependencyProperty UntilNoonValueProperty = DependencyProperty.Register(
            nameof(UntilNoonValue), typeof(TValue), typeof(TimeOfDayObject<TValue>), new PropertyMetadata(null,
                (o, args) =>
                {
                    var control = (TimeOfDayObject<TValue>)o;
                    control.UpdateActualValue(control.TimeOfDay);
                }));
 
        /// <summary>
        /// Значение для первой половины дня.
        /// </summary>
        public TValue UntilNoonValue
        {
            get { return (TValue)GetValue(UntilNoonValueProperty); }
            set { SetValue(UntilNoonValueProperty, value); }
        }
 
        public static readonly DependencyProperty AfternoonValueProperty = DependencyProperty.Register(
            nameof(AfternoonValue), typeof(TValue), typeof(TimeOfDayObject<TValue>), new PropertyMetadata(null,
                (o, args) =>
                {
                    var control = (TimeOfDayObject<TValue>)o;
                    control.UpdateActualValue(control.TimeOfDay);
                }));
 
        /// <summary>
        /// Значение для второй половины дня.
        /// </summary>
        public TValue AfternoonValue
        {
            get { return (TValue)GetValue(AfternoonValueProperty); }
            set { SetValue(AfternoonValueProperty, value); }
        }
 
        #endregion
 
        private static readonly DependencyProperty ActualValueProperty = DependencyProperty.Register(
            nameof(ActualValue), typeof(TValue), typeof(TimeOfDayObject<TValue>), new PropertyMetadata(null));
 
        public TValue ActualValue
        {
            get { return (TValue)GetValue(ActualValueProperty); }
            private set { SetValue(ActualValueProperty, value); }
        }
 
        public static readonly DependencyProperty TimeOfDayProperty = DependencyProperty.Register(
            nameof(TimeOfDay), typeof(TimeOfDay), typeof(TimeOfDayObject<TValue>), new PropertyMetadata(TimeOfDay.None, OnTimeOfDayChanged));
 
        public TimeOfDay TimeOfDay
        {
            get { return (TimeOfDay)GetValue(TimeOfDayProperty); }
            set { SetValue(TimeOfDayProperty, value); }
        }
 
        private static void OnTimeOfDayChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
        {
            var control = (TimeOfDayObject<TValue>)obj;
            control.UpdateActualValue((TimeOfDay)args.NewValue);
        }
 
        private void UpdateActualValue()
        {
            if (IsTheCommonValueSet())
            {
                ActualValue = CommonValue;
            }
        }
 
        private void UpdateActualValue(TimeOfDay timeOfDay)
        {
            if (IsTheCommonValueSet())
            {
                return;
            }
 
            if (IsTheValuesSetForIncompleteTimeOfDay())
            {
                switch (timeOfDay)
                {
                    case TimeOfDay.None:
                        ActualValue = default;
                        break;
 
                    case TimeOfDay.UntilNoon:
                        ActualValue = UntilNoonValue;
                        break;
 
                    case TimeOfDay.Afternoon:
                        ActualValue = AfternoonValue;
                        break;
 
                    default:
                        throw new ArgumentOutOfRangeException();
                }
            }
        }
 
        /// <summary>
        /// Установлены значения для времён дня.
        /// </summary>
        private bool IsTheValuesSetForIncompleteTimeOfDay()
        {
            return UntilNoonValue != null && AfternoonValue != null;
        }
 
        /// <summary>
        /// Установлены значения для времён дня.
        /// </summary>
        private bool IsTheCommonValueSet()
        {
            return CommonValue != null;
        }
 
        protected TimeOfDayObject()
        {
        }
    }
}
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
using Windows.UI.Xaml;
 
namespace ExtendedProperty.Controls.Button
{
    public class SizeObject : DependencyObject
    {
        public static readonly DependencyProperty WidthProperty = DependencyProperty.Register(
            nameof(Width), typeof(double), typeof(SizeObject), new PropertyMetadata(10d));
 
        public double Width
        {
            get { return (double) GetValue(WidthProperty); }
            set { SetValue(WidthProperty, value); }
        }
 
        public static readonly DependencyProperty HeightProperty = DependencyProperty.Register(
            nameof(Height), typeof(double), typeof(SizeObject), new PropertyMetadata(10d));
 
        public double Height
        {
            get { return (double) GetValue(HeightProperty); }
            set { SetValue(HeightProperty, value); }
        }
    }
}
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
namespace ExtendedProperty.Controls.Config
{
    /// <summary>
    /// Время дня.
    /// </summary>
    public enum TimeOfDay
    {
        /// <summary> Не используется. </summary>
        None,
 
        /// <summary> До полудня. </summary>
        UntilNoon,
 
        /// <summary> После полудня. </summary>
        Afternoon
    }
}
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
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using ExtendedProperty.Controls.Config;
 
namespace ExtendedProperty.Base
{
    public abstract class ButtonBase : Control
    {
        #region States
 
        public static readonly DependencyProperty IncompleteTimeProperty = DependencyProperty.Register(
            nameof(IncompleteTime), typeof(TimeOfDay), typeof(ButtonBase), new PropertyMetadata(TimeOfDay.None, OnIncompleteTimeChanged));
 
        public TimeOfDay IncompleteTime
        {
            get { return (TimeOfDay)GetValue(IncompleteTimeProperty); }
            set { SetValue(IncompleteTimeProperty, value); }
        }
 
        #endregion
        
        public event DependencyPropertyChangedEventHandler IncompleteTimeChanged;
 
        protected ButtonBase()
        {
            DefaultStyleKey = typeof(ButtonBase);
        }
 
        private static void OnIncompleteTimeChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
        {
            var control = (ButtonBase)obj;
 
            control.OnIncompleteTimeChanged(args);
            control.IncompleteTimeChanged?.Invoke(obj, args);
        }
 
        protected virtual void OnIncompleteTimeChanged(DependencyPropertyChangedEventArgs args)
        {
        }
    }
}
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
using System.Diagnostics;
using System.Threading;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Data;
using ExtendedProperty.Base;
 
namespace ExtendedProperty.Controls.Button
{
    // По другому в XAML не создать объект такого типа
    [DebuggerDisplay("CurrentInstanceNumber = {" + nameof(CurrentInstanceNumber) + "}")]
    public class ExStyle : TimeOfDayObject<StyleObject>
    {
        private static int _counter;
 
        public int CurrentInstanceNumber { get; }
 
        public ExStyle()
        {
            CurrentInstanceNumber = Interlocked.Increment(ref _counter);
        }
    }
 
    [DebuggerDisplay("CurrentInstanceNumber = {" + nameof(CurrentInstanceNumber) + "}")]
    public class ExSize : TimeOfDayObject<SizeObject>
    {
        private static int _counter;
 
        public int CurrentInstanceNumber { get; }
 
        public ExSize()
        {
            CurrentInstanceNumber = Interlocked.Increment(ref _counter);
        }
    }
 
    public class ButtonControl : ButtonBase
    {
        #region Common
 
        public static readonly DependencyProperty StrokeSizeProperty = DependencyProperty.Register(
            nameof(StrokeSize), typeof(int), typeof(ButtonControl), new PropertyMetadata(null));
 
        public int StrokeSize
        {
            get { return (int) GetValue(StrokeSizeProperty); }
            set { SetValue(StrokeSizeProperty, value); }
        }
 
        #endregion
 
        public static readonly DependencyProperty TStyleProperty = DependencyProperty.Register(
            nameof(TStyle), typeof(ExStyle), typeof(ButtonControl), new PropertyMetadata(null));
 
        public ExStyle TStyle
        {
            get { return (ExStyle)GetValue(TStyleProperty); }
            set { SetValue(TStyleProperty, value); }
        }
 
        public static readonly DependencyProperty SizeProperty = DependencyProperty.Register(
            nameof(Size), typeof(ExSize), typeof(ButtonControl), new PropertyMetadata(null));
 
        public ExSize Size
        {
            get { return (ExSize) GetValue(SizeProperty); }
            set { SetValue(SizeProperty, value); }
        }
        
        public ButtonControl()
        {
            Unloaded += OnUnloaded;
        }
 
        private void OnUnloaded(object sender, RoutedEventArgs e)
        {
            Unloaded -= OnUnloaded;
 
            ClearBindingValues();
        }
 
        protected override void OnApplyTemplate()
        {
            ClearBindingValues();
 
            BindingOperations.SetBinding(TStyle, ExStyle.TimeOfDayProperty,
                new Binding { Source = this, Path = new PropertyPath(nameof(IncompleteTime)), Mode = BindingMode.OneWay });
            
            BindingOperations.SetBinding(Size, ExSize.TimeOfDayProperty,
                new Binding { Source = this, Path = new PropertyPath(nameof(IncompleteTime)), Mode = BindingMode.OneWay });
 
            base.OnApplyTemplate();
        }
 
        private void ClearBindingValues()
        {
            TStyle.ClearValue(ExStyle.TimeOfDayProperty);
            Size.ClearValue(ExSize.TimeOfDayProperty);
        }
    }
}
Примерно это генерирует генератор (можно всё конкретно поменять, это пример). Далее если в 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
<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:controls="using:ExtendedProperty.Controls.Button">
 
    <!--  Common  -->
    <Style x:Key="CommonStyle" TargetType="controls:ButtonControl">
        <Setter Property="StrokeSize" Value="1" />
    </Style>
 
    <!--  Стиль по умолчанию для ButtonControl (без x:Key)  -->
    <Style BasedOn="{StaticResource CommonStyle}" TargetType="controls:ButtonControl">
        <Setter Property="Template" Value="{StaticResource ButtonTemplate}" />
        <Setter Property="TStyle">
            <Setter.Value>
                <controls:ExStyle UntilNoonValue="{StaticResource UntilNoonStyle}" AfternoonValue="{StaticResource AfternoonStyle}" />
            </Setter.Value>
        </Setter>
        <Setter Property="Size">
            <Setter.Value>
                <controls:ExSize UntilNoonValue="{StaticResource UntilNoonSize}" AfternoonValue="{StaticResource AfternoonSize}" />
            </Setter.Value>
        </Setter>
    </Style>
 
    <!--  UntilNoon Style  -->
    <controls:StyleObject x:Key="UntilNoonStyle">
        <controls:StyleObject.IconColor>
            <SolidColorBrush Color="Red" />
        </controls:StyleObject.IconColor>
        <controls:StyleObject.PrimaryColor>
            <SolidColorBrush Color="#893710" />
        </controls:StyleObject.PrimaryColor>
    </controls:StyleObject>
 
    <!--  Afternoon Style  -->
    <controls:StyleObject x:Key="AfternoonStyle">
        <controls:StyleObject.IconColor>
            <SolidColorBrush Color="#0D71C8" />
        </controls:StyleObject.IconColor>
        <controls:StyleObject.PrimaryColor>
            <SolidColorBrush Color="#063475" />
        </controls:StyleObject.PrimaryColor>
    </controls:StyleObject>
 
    <!--  UntilNoon Size  -->
    <controls:SizeObject
        x:Key="UntilNoonSize"
        Width="120"
        Height="20" />
 
    <!--  Afternoon Size  -->
    <controls:SizeObject
        x:Key="AfternoonSize"
        Width="180"
        Height="25" />
 
</ResourceDictionary>
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
<Page
    x:Class="ExtendedProperty.MainPage"
    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:local="using:ExtendedProperty"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:button="using:ExtendedProperty.Controls.Button"
    Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
    mc:Ignorable="d">
 
    <StackPanel
        Margin="0,80,0,0"
        HorizontalAlignment="Stretch"
        VerticalAlignment="Stretch">
 
        <Border
            Height="15"
            BorderBrush="#6EC308"
            BorderThickness="1" />
 
        <button:ButtonControl
            Margin="0,0,0,10"/>
 
        <button:ButtonControl
            x:Name="_button"
            Margin="0,0,0,10"
            IncompleteTime="Afternoon" />
 
    </StackPanel>
</Page>
В итоге мы получим по одному экземпляру ExStyle и ExSize из стиля для любого кол-ва контролов, которые я расположу на странице (если я правильно понял). В общем, такой подход не работает. Изменения применяемые к кнопке с именем _button автоматом срабатывают для кнопки без имени. Возможно, я где-то оишбся и не заметил. Пытаюсь придумать, как сделать всё это гибко, чтобы можно было быстро создавать вот такие настраиваемые свойства.

Добавлено через 8 минут
Сижу ещё думаю, может сделать не на свойствах в виде классов StyleObject и SizeObject, а в XAML просто задавать какое-то сопоставление в одном свойстве, а внутри базового класса написать простыню кода, которая будет вытягивать значения из ресурсов в коде и подставлять их. В общем, что-то ломаю голову, никак не придумаю, как лучше сделать.
0
QA
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
20.07.2019, 17:04
Ответы с готовыми решениями:

Запрос на подмену значений
Всем добрый день! Столкнулся с проблемой, вроде элементарной, но для меня непостежимой... Сутьзайду...

Как сделать подмену IP адреса?
Тема такая, есть WebBrowser на форме, нужно сделать так, чтобы при входе через него на сайт, сайт...

как сделать подмену адресса страницы?
как сделать подмену адресса страницы при ее страницы, допустим эзер щелкает на адресс:...

Условие, если Х не изменился, то
У меня Х бывает изменяется бывает нет. Что писать между If Then.

Найти файл, если его путь изменился
привет всем!))) вот допустим файл: &quot;класс.txt&quot; полный путь к ниму: &quot;E:\Documents and...

0
Answers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
20.07.2019, 17:04

Сайт изменился но Google и Yandex он по прежнему не изменился
Я полностью поменял название своего сайта но в поисковике главная страница сайта и все остальные...

Если файл изменился, то скопировать его в другое место
Интересует, как сравнить, что время изменилось. В Memo2.Lines вывожу дату создания файла в таймере....

Как достать html code из frame/iframe (ie), если изменился source?
hie! есть проблема: хочу достать хтмл из iframe's &lt;body &gt; - в принципе, могу: function doit(){...


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

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

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2019, vBulletin Solutions, Inc.
Рейтинг@Mail.ru