Форум программистов, компьютерный форум, киберфорум
C#: WPF, UWP и Silverlight
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
Рейтинг 4.57/14: Рейтинг темы: голосов - 14, средняя оценка - 4.57
 Аватар для limeniye
1182 / 624 / 160
Регистрация: 19.04.2018
Сообщений: 2,923

ReactiveUI.Foody propetychanged

26.06.2022, 02:22. Показов 3562. Ответов 53
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Есть свойство:
C#
1
2
        [Reactive]
        public string? Name { get; set; }
Собственно пытаюсь отследить его изменения
C#
1
            this.WhenAnyObservable(x => x.Name).Subscribe(x => System.Diagnostics.Debug.WriteLine(x));
Но так как оно не Observable -- параметр не подходит.

В ответе от Someone007 в теме
https://www.cyberforum.ru/wpf-... st16027540

Я вижу немного другую реализацию объявления:
C#
1
2
        private readonly ObservableAsPropertyHelper<string> _selectedItemsAsText;
        public string SelectedItemsAsText => _selectedItemsAsText.Value;
С ней я поигрался, но проблему свою решить таки не смог.

Можно сделать через ReactiveProperty<string?> Name { get; set; }, по идее должно заработать, но тогда в View придётся постоянно указывать .Value, что, по сути, является нарушением MVVM, View ничего не должна знать о том, как устроены свойства.
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
26.06.2022, 02:22
Ответы с готовыми решениями:

ReactiveUI и навигация
Есть ли в сети или у кого примеры (не)простейшей навигации с использованием данного фреймворка?

ReactiveUI составное свойство
Вроде бы и к WPF, а вроде и вообще к фреймворку. Но тем не менее: public class Model { public string Name {get;set;} public...

ReactiveUI: изменение свойства элемента коллекции
Есть класс: public class Unit : INotifyPropertyChanged { public int Mode { get; set; } ...

53
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16166 / 11286 / 2892
Регистрация: 21.04.2018
Сообщений: 33,176
Записей в блоге: 2
27.06.2022, 12:30
Студворк — интернет-сервис помощи студентам
Цитата Сообщение от limeniye Посмотреть сообщение
Ну у меня вот так вот IsValid="{Binding ConnectVM.IsValidName}"
Я не об этом.
Я о том какой код в действительности создают ReactivUI и Reactiv.Fody.
Особенно последний, он же вносит изменения в CIL уже после компиляции Шарпа.

Добавлено через 1 минуту
И понять какие он внёс изменения можно либо через дизассемблер CIL, либо через рефлексию в рунтайм.
0
1341 / 920 / 265
Регистрация: 08.08.2014
Сообщений: 2,775
27.06.2022, 13:22
Цитата Сообщение от limeniye Посмотреть сообщение
Такой вопрос ещё: зачем Вы делаете DisposeWith?
Разве тут подписка не на этот же тип? По идее не обязательно.
Это скорее для упрощения написания и ревизии кода. Когда в одной VM в одном блоке идут подписки и на свои свойства, и на свойства внешний моделей/сервисов, то необходимость каждый раз задумываться где нужна явная отписка, а где нет, и риски ошибок повышает, и проверку кода усложняет.
0
1341 / 920 / 265
Регистрация: 08.08.2014
Сообщений: 2,775
27.06.2022, 13:45
Проверил на минимальном примере - всё ок работает.

В т.ч. с биндингом на свойство вложенной VM.
Вложения
Тип файла: zip WpfRxExp.zip (5.7 Кб, 2 просмотров)
0
 Аватар для limeniye
1182 / 624 / 160
Регистрация: 19.04.2018
Сообщений: 2,923
27.06.2022, 16:04  [ТС]
kotelok, Элд Хасп, собрал простой пример:
Вложения
Тип файла: zip WpfApp2.zip (10.4 Кб, 6 просмотров)
0
1341 / 920 / 265
Регистрация: 08.08.2014
Сообщений: 2,775
27.06.2022, 16:20
А что именно должно в UI происходить?

У меня работает так, что при вводе любого текста, кроме пробелов и пустой строки, появляется зелёная галочка. Если данные удалить (или оставить только пробелы), галочка исчезает.
0
 Аватар для limeniye
1182 / 624 / 160
Регистрация: 19.04.2018
Сообщений: 2,923
27.06.2022, 16:38  [ТС]
Цитата Сообщение от kotelok Посмотреть сообщение
У меня работает так, что при вводе любого текста, кроме пробелов и пустой строки, появляется зелёная галочка. Если данные удалить (или оставить только пробелы), галочка исчезает.
Верно, теперь попробуйте поставить private set, о котором, собственно, и идёт речь
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16166 / 11286 / 2892
Регистрация: 21.04.2018
Сообщений: 33,176
Записей в блоге: 2
27.06.2022, 17:45
limeniye, у меня комп полетел.....
Ремонту не подлежит.
Когда возьму новый - пока не знаю.
1
 Аватар для limeniye
1182 / 624 / 160
Регистрация: 19.04.2018
Сообщений: 2,923
27.06.2022, 18:31  [ТС]
Элд Хасп,

Добавлено через 18 секунд

Не по теме:

давно?



Добавлено через 1 минуту
Элд Хасп, ну, как вариант, можно через TeamViwer поключиться, через телефон
0
27.06.2022, 18:36

Не по теме:

Цитата Сообщение от limeniye Посмотреть сообщение
давно?
Вчера вечером ближе к ночи просто сам выключился и не стал включаться.
Думал проблема с БП, но оказалось нет.
Комп старый - почти 12 лет.
Полетел проц.
Но тестирование показало что уже все комплектующие "просели": диск, мат.плата, ОЗУ, БП.
Поэтом ремонтировать смысла нет.

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

Сейчас работаю с другого, но он не мой и без Студии.

0
27.06.2022, 18:55  [ТС]

Не по теме:

Элд Хасп, без студии? Кем же Вы работаете? Не WPF разработчиком чтоль?

0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16166 / 11286 / 2892
Регистрация: 21.04.2018
Сообщений: 33,176
Записей в блоге: 2
27.06.2022, 19:17
Цитата Сообщение от limeniye Посмотреть сообщение
Не WPF разработчиком чтоль?
Не - я любитель.
0
1341 / 920 / 265
Регистрация: 08.08.2014
Сообщений: 2,775
28.06.2022, 08:26
Цитата Сообщение от limeniye Посмотреть сообщение
Верно, теперь попробуйте поставить private set, о котором, собственно, и идёт речь
С Fody всё ок, т.е. 'PropertyChanged' для свойства 'IsValidName' продолжает приходить.

Однако, после первого срабатывания, WPF почему-то удаляет биндинг на свойство 'StateBox.IsValidProperty' для экземпляра 'local:StateTextBox'.

Задайте для 'local:StateTextBox' какое-нибудь имя:
XML
1
<local:StateTextBox x:Name="StateBoxRef" ..
А потом на разных этапах проверьте для него результат вызова этого метода:
C#
1
var bindigExpression = StateBoxRef.GetBindingExpression(StateTextBox.IsValidProperty);
Изначально он возвращает экземпляр выражения привязки, но после первого срабатывания начинает возвращать 'null'.

В подробности вдаваться сложно, но тут, вроде, описано что-то похожее, и там тоже (в ответе) упоминается удаление привязки после первого срабатывания:
https://stackoverflow.com/ques... -only-once
0
 Аватар для limeniye
1182 / 624 / 160
Регистрация: 19.04.2018
Сообщений: 2,923
28.06.2022, 11:32  [ТС]
kotelok, я понимаю, что у меня пропадает привязка, вот как это решить?
Весьма странное поведение программы. С ссылкой на источник ознакомился, но там внятного ответа не нашёл.
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16166 / 11286 / 2892
Регистрация: 21.04.2018
Сообщений: 33,176
Записей в блоге: 2
28.06.2022, 11:34
Цитата Сообщение от kotelok Посмотреть сообщение
Изначально он возвращает экземпляр выражения привязки, но после первого срабатывания начинает возвращать 'null'.
Если свойству задана привязка изменяющая источник, но источник не имеет публичного сеттера, то при изменении целевого свойства не от источника, привязка отваливается.
Тем самым подтверждается моё предположение, что указанным образом изменяется не свойство источник, а целевое свойство (или используется PropertyDescriptor, с аналогичными последствиями).
1
 Аватар для limeniye
1182 / 624 / 160
Регистрация: 19.04.2018
Сообщений: 2,923
28.06.2022, 11:39  [ТС]
Элд Хасп, как я понял у kotelok, с другими свойствами, работает private set.
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16166 / 11286 / 2892
Регистрация: 21.04.2018
Сообщений: 33,176
Записей в блоге: 2
28.06.2022, 11:40
Цитата Сообщение от limeniye Посмотреть сообщение
я понимаю, что у меня пропадает привязка, вот как это решить?
Это всё относится к малодокументируемой области.
Нужно смотреть исходники, анализировать, тестировать в рунтайм, проверять CIL через рефлексию и т.д.
Ближайшее время помочь этим не смогу.
0
1341 / 920 / 265
Регистрация: 08.08.2014
Сообщений: 2,775
28.06.2022, 14:06
Лучший ответ Сообщение было отмечено limeniye как решение

Решение

Цитата Сообщение от limeniye Посмотреть сообщение
я понимаю, что у меня пропадает привязка, вот как это решить?
Добавлено через 7 минут
Всё, нашёл. Проблема в рекурсивном вызове событий изменения DP-свойств друг-другом (IsValid меняет Status, Status меняет IsValid и т.д.). Почему проявляется только с приватным сетером - не знаю. Вероятно как-то связано с направлением привязки (Mode) и "особенностями внутренней реализации WPF".

В методе 'System.Windows.DependencyObject.SetValu e', похоже нет проверки на то, что значение такое же.

Соответственно, проблема обходится таким образом. Далее это можно как-то более красиво во вспомогательный метод оформить, который перед вызовом 'SetValue' будет проверку на эквивалентность делать и скипать 'SetValue', если значение не изменилось:
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
        protected virtual void OnStatusPropertyChanged(DependencyPropertyChangedEventArgs e)
        {
            
            var newValue = (StatusEnum)e.NewValue;
            var oldValue = (StatusEnum)e.OldValue;
 
            if (newValue != oldValue)
            {
                if (newValue == StatusEnum.Success)
                {
                    if (IsValid != true)
                        IsValid = true;
                }
                else if (newValue == StatusEnum.Fail)
                {
                    if (IsValid != false)
                        IsValid = false;
                }
                else
                {
                    if (IsValid != null)
                        IsValid = null;
                }
            }
        }
 
        protected virtual void OnIsValidPropertyChanged(DependencyPropertyChangedEventArgs e)
        {
            var newValue = (bool?)e.NewValue;
            var oldValue = (bool?)e.OldValue;
 
            if (newValue != oldValue)
            {
                if (newValue == true)
                {
                    if (Status != StatusEnum.Success)
                        Status = StatusEnum.Success;
                }
                else if (newValue == false)
                {
                    if (Status != StatusEnum.Fail)
                        Status = StatusEnum.Fail;
                }
                else
                {
                    if (Status != StatusEnum.Empty)
                        Status = StatusEnum.Empty;
                }
            }
        }
Добавлено через 44 минуты
В исходниках, кстати, нет никаких явных проверок на ошибки рекурсивных вызовов, однако, там и в самом деле, на первый взгляд:
1. Не наблюдается сравнения нового значения с текущим.
2. При каждом срабатывании выполняется отключение старой привязки и создание новой. И вот если новую создать не получилось, то остаётся 'null'.
https://github.com/dotnet/wpf/... ct.cs#L647
1
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16166 / 11286 / 2892
Регистрация: 21.04.2018
Сообщений: 33,176
Записей в блоге: 2
28.06.2022, 14:45
Лучший ответ Сообщение было отмечено limeniye как решение

Решение

Цитата Сообщение от kotelok Посмотреть сообщение
Всё, нашёл. Проблема в рекурсивном вызове событий изменения DP-свойств друг-другом
Область ошибки верно определили, но причина немного сложнее.
Проблема не в рекурсии - она не возникает, так как методы PropertyChangedCallback вызываются только при изменении значения.
Если присваивается тоже самое значение, то метод вызван не будет.
Кстати, это и пример для правильной реализации INPC.PropertyChanged, который лучше вызывать не при присвоении значения, а при его изменении.

Что касается самой проблемы, то это изменение значения DP-свойства, которому задана привязка, методом SetValue() - он вызывается "под капотом" оболочки CLR свойства.
Если свойству задана привязка в направлении к источнику (TwoWay, OneWayToSource), но у свойства источника нет публичного сеттера, или задан привязка только от источника (OneWay), то такие привязки при изменении целевого свойства отваливаются.
По идее можно обрабатывать все эти состояния перед присвоением, но это не типично для WPF и лучше так не делать.

В данном случае, ошибка не в самой реализации, а концептуальная.
Для чего нужны два свойства с такой зависимостью друг от друга?
По бизнес логике они одно и тоже.
Вся их функция это двунаправленная конвертация Nullable<bool> <-> StatusEnum.
Но такая конвертация - это задача конвертера, и нет необходимости для этого дублировать одно и тоже свойство, но с разными типами.

Сам конвертер:
C#
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
    /// <summary>
    /// This converter are extension of EnumConverter for StatusEnum. Is handling <see cref="bool"/> and <see cref="Nullable{T}">Nullable&lt;bool&gt;</see> values.
    /// </summary>
    /// <remarks> <see langword="null"/> - <see cref="StatusEnum.Empty"/>; <br/>
    /// <see langword="true"/> - <see cref="StatusEnum.Success"/>; <br/> 
    /// <see langword="false"/> - <see cref="StatusEnum.Fail"/>;</remarks>
    public class StatusEnumConverter : EnumConverter
    {
        public StatusEnumConverter() 
            : base(typeof(StatusEnum))
        {
        }
 
        public override bool CanConvertFrom(ITypeDescriptorContext? context, Type sourceType)
        {
            if (sourceType == typeof(bool) || sourceType == typeof(bool?))
                return true;
 
            return base.CanConvertFrom(context, sourceType);
        }
 
        public override bool CanConvertTo(ITypeDescriptorContext? context, Type? destinationType)
        {
            if (destinationType == typeof(bool) || destinationType == typeof(bool?))
                return true;
 
            return base.CanConvertTo(context, destinationType);
        }
 
        public override object? ConvertFrom(ITypeDescriptorContext? context, CultureInfo? culture, object value)
        {
            Type? type = value?.GetType();
 
            if (type == typeof(bool) || type == null || type ==  typeof(bool?))
            {
                return value is null ? StatusEnum.Empty : (bool)value ? StatusEnum.Success : StatusEnum.Fail;
            }
 
            return base.ConvertFrom(context, culture, value);
        }
 
        public override object? ConvertTo(ITypeDescriptorContext? context, CultureInfo? culture, object? value, Type destinationType)
        {
            StatusEnum valueStatusEnum = (StatusEnum)(value ?? throw new ArgumentNullException(nameof(value)));
 
            if (destinationType == typeof(bool) || destinationType == typeof(bool?))
            {
                return valueStatusEnum switch 
                {
                    StatusEnum.Success => true,
                    StatusEnum.Fail => false,
                    _ => null
                };
            }
 
            return base.ConvertTo(context, culture, value, destinationType);
        }
 
        public override bool IsValid(ITypeDescriptorContext? context, object? value)
        {
            if (value is bool? || value is bool || value is null)
            {
                return true;
            }
 
            return base.IsValid(context, value);
        }
    }
И его подключение к перечислению:
C#
80
81
    [TypeConverter(typeof(StatusEnumConverter))]
    public enum StatusEnum
После этого свойство IsValid нужно, вообще, удалить, а свойство Status упростить:
C#
138
139
140
        public static readonly DependencyProperty StatusProperty =
            DependencyProperty.Register(nameof(Status), typeof(StatusEnum),
               typeof(StateTextBox), new FrameworkPropertyMetadata(StatusEnum.Empty));
Добавлено через 9 минут
limeniye, метод ConvertTo реализован немного ущербно.
Если свойство источник bool, то ему нельзя возвращать null - будет ошибка привязки и она может отвалится.
Нужно задать два разных if для bool и Nullable<bool>.
Для bool возвращать только два значения:
C#
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
            if (destinationType == typeof(bool))
            {
                return valueStatusEnum switch 
                {
                    StatusEnum.Success => true,
                    _ => false
                };
            }
            if (destinationType == typeof(bool?))
            {
                return valueStatusEnum switch 
                {
                    StatusEnum.Success => true,
                    StatusEnum.Fail => false,
                    _ => null
                };
            }
2
 Аватар для limeniye
1182 / 624 / 160
Регистрация: 19.04.2018
Сообщений: 2,923
28.06.2022, 17:36  [ТС]
Элд Хасп, kotelok, всем большое спасибо за участие в теме и Ваши ответы :3
0
Модератор
Эксперт .NET
 Аватар для Элд Хасп
16166 / 11286 / 2892
Регистрация: 21.04.2018
Сообщений: 33,176
Записей в блоге: 2
28.06.2022, 18:31
limeniye, ещё одна мысль в голову пришла.
Возможно дефолтный EnumConverter может правильно конвертировать целочисленные типы.
Так, что возможно, вы получили "бесплатную" конвертацию в целые свойства, и точно получили в стринг свойства.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
28.06.2022, 18:31

ReactiveUI уведомления и цепочки
Каким образом с помощью ReactiveUI сделать подобное? public string From { get; set;} public bool IsKit { get; set; } ...

Пример запроса reactiveui / refit
Может кто поделиться примером кода либы reactiveui / refit конкретнее нужен POST запрос с FormData


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

Или воспользуйтесь поиском по форуму:
40
Ответ Создать тему
Новые блоги и статьи
Запустил конкурс "тем и промптов для текстовых квестов созданных почти чисто ИИ"
Adler 06.10.2026
Всем привет! За последние три-четыре дня я создал более 16 текстовых квестовых игр используя преимущественно по одному запросу к ИИ на игру. Мне так понравилось смотреть все ветки/ сцены во всех. . .
ИИ не может найти нужный язык в списке
Supersumestria 05.10.2026
Я ему даю вот такое изображение и прошу найти и подчеркнуть немецкий язык. Возвращает он вот это: https:/ / i. **********/ vqBWLe2. png Нужную строчку в 3й колонке просто выдумал. . Это. . .
Новая последняя моя музыка в SUNO
zorxor 05.10.2026
Здравствуйте, дорогие мои друзья! С большой радостью я хотел бы представить вам свою новую последнею музыку, которую сгенерировала мне по моей просьбе нейросеть SUNO. С уважением, zorxor. Это. . .
Программный домашний кинотеатр
russiannick 27.09.2026
Сподобился на программный домашний кинотеатр. В качестве ЯВУ по традиции выбрал js. В помощники взял Яндекс-Алису. Было создано три зала на разные интересы. исторические и ретро сериал Хичкок. . .
Беседа с ИИ о программистах, недопускающих к созданию и правке кода генеративные ИИ и причины этого
zorxor 21.09.2026
Раньше я радовался или получал некоторые эмоции, пусть небольшие, но всё же, от самого процесса написания кода, рекомпиляции и запуска, видя постепенное развитие программы и прочее. А теперь лень. . .
Мобильное приложение ColorStep
pavlinmavlin 17.09.2026
Реализовал приложение Красный, Зеленый, Синий в Unity3d + c#. Название изменил на ColorStep. Приложение прошло модерацию и теперь доступно для скачивания. Делал его сам, шаг за шагом — и вот,. . .
Запрет дублирования строк в табличной части
Maks 13.09.2026
Реализация из решения ниже выполнена на нетиповом справочнике "Нормы ТО" с табличной часть "Виды ТО", разработанного в КА2, со следующими реквизитами: - ВидТО (СправочникСсылка. ВидыТО); - ВидГСМ. . .
Скрипты Tampermonkey для CyberForum, ChatGPT, Claude и пр.
Jin X 06.09.2026
Скрипты Tampermonkey для CyberForum, ChatGPT, Claude и пр. Работая с форумом и нейросетями в браузере часто хочется что-то подкорректировать или добавить какого-то функционала. Ниже прикреплён. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru