Заморочка интересная с WPF binding
знаю, что всего там еще не перевидал, но все же достаточно много.
наверное, неправильный выбрал дезигн, но лучше расскажу по порядку.
делаю UserControl, в котором, кроме прочего есть несколько клавиш, которые нужно периодически конфигурировать. т.е. делать их видимыми/активными...
для этого решил добавить к контролу DependencyProperty типа некого объекта. в окне, в которое вставлен контрол, этому проперти присвоено значение Binding, объект, который лежит в DataContext, имеет соответствующий проперти и говорит периодически OnPropertyChanged ("blablabla");
наблюдаю картину, которую не ожидал увидеть, и не сразу понял, в чем дело.
в этом же контроле имеются и другие DependencyProperties, которые типа примитивов: строки, целые ... некоторые я использую просто чтобы "передать сообщение" контролу. само проперти у объекта DataContext просто всегда возвращает одно и то же значение, просто пишу OnPropertyChanged ("blablabla");, и в PropertyChangedCallback юзэрконтрола делаю что надо по этому событию.
но те, где проперти типа объект, ведут себя не как ожидал. их нужно действительно поменять, причем не что-то там у них внутри, а другой объект прислать, иначе по OnPropertyChanged ("blablabla") происходит считывание объекта из DataContext, но PropertyChangedCallback не вызывается! т.е., например, если ваш объект - это, например, List(string), вы его создали и OnPropertyChanged ("blablabla"), PropertyChangedCallback вызовется. затем допишете к этому списку еще строчечку и снова вызовете OnPropertyChanged ("blablabla") - уйдет как в болото, и даже круги не пойдут. "оно" уже имеет тот же самый объект, и делать ничего не хочет. т.е. вы должны слать новый объеат. например, брать ваш список и делать public List(string) superlist { get { return _superlist.ToList(); }}, и тогда оно сработает.
допускаю, что это только для меня оказалось новостью, а для остальных - "и дураку понятно", но я пару часов протупил, решил исповедоваться : (
Сорри, что написано вроде как понятно, но в чем проблема так и не понял. Какое нибудь приложение есть, что неправильно работает?
Ну и у меня OnPropertyChanged () или со старыми версиями OnPropertyChanged (nameof(PropertyName));
Snoop пользовали?
Да, и для UI исрользую ObservableCollection<T>, а не List
у меня не лист, а "свой объект". я список просто взял для примера. мог взять все что угодно кроме примитива.
проблема в том, что я не нашел лучшего дезигнерского решения что-нибудь перенастроить в контроле, кроме как вделать ему дэпэндэнси пропэрти и через типа обновление оного заставить контрол реагировать на событие. и оно срабатывает, если каждый раз передавать новую копию, а не тот же измененный объеат. хэндл должен быть не тот же, что при последнем обновлении.
все вроде теперь заработало, но нужно поковырять другие возможные варианты.
чтобы вас не отвлекать на List, ObservableCollection и прочую муть, возьмем класс
public class Person { public string Name { get; set; } public int Age { get; set; } public Person (string n, int a){ Name = n; Age = a; } }
так вот если вы сделаете так:
private Person _person = new Person ("Name0", 10); public Person person { get { return _person; }} ... _person.Age++; OnPropertyChanged ("person"); ...
, то тичего не произойдет.
а так - другое дело
_person = new Person (_person.Name, _person.Age+1); OnPropertyChanged ("person");
и оно срабатывает, если каждый раз передавать новую копию, а не тот же измененный объект
Ну так абсолютно правильно срабатывает. Проперти то на объект, а не на его содержимое.
Если нужно отслеживать изменения в объекте, то объект нужно наследовать от INotifyPropertyChanged хотя бы.
Именно по этой причины для меняющегося списка вместо List используется ObservableCollection.
Ну давайте так.
- Что может определить обычная проперть? Только то что ее значение изменилось. Что там происходит с объектом она просто так узнать не может.
Что бы определять изменение объекта нужно еще иметь какую то договоренность. Одна из них INotifyPropertyChanged интерфейс.
Так что изменение объекта нужно отслеживать самостоятельно, если его поля не используются напрямую в юсер контроле.
Счас еще гляну, что там Маркс с Энгельсом написали по этому поводу. Поумнее тогда ответ будет.
https://docs.microsoft.com/en-us/dotnet/api/system.windows...
To detect source changes in one-way or two-way bindings, the source must
implement a suitable property change notification mechanism such as INotifyPropertyChanged.
НП.
WPF просто выбешивает, когда же наконец-то на HTML5 перейдём!!!
хтмл5 еще выбесительнее. думаю, GUI еще ожидает возрождение в каком-нибудь гениальном языке его описания.
на сегодня хамл - наиболее удачное из всего что есть. ваши девки-монстры ужасны что в хтмл5, что в хамл.
не нравится хамл - учитесь говорить на opengl
это уже - из области философии
Никак нет - чистое программирование
Если я хочу узнать изменилось ли что внутри объекта мне нужен канал обратной связи от объекта. В котором объект мне скажет, что его состояние изменилось.
Можно конечно еще поизвращаться на предмет сравнения сериализованной копии объекта или еще как. Но нам то извращения не нужны.
Или есть еще другая точка зрения?
хтмл5 еще выбесительнее. думаю,
А ничего что большие компании перешли на десктопные веб App? https://ru.wikipedia.org/wiki/Electron С ElectronJS начал программировать несколько месяцев назад.
Допустим Visual Studio Code полностью написана на HTML5 и JavaScript - https://www.electronjs.org/apps/visual-studio-code
Тоже самое с Twitch - https://www.electronjs.org/apps/twitch
И скайп - https://www.electronjs.org/apps/skype
Моё любимое приложение Pencil которым я уже минимум как год пользуюсь - https://www.electronjs.org/apps/pencil
Единственный минус пока полупрозрачность в Windows 8.x глючит вроде как - https://github.com/arkenthera/electron-vibrancy/blob/maste...
Мне понравилось как получилось вот это десктопной веб App:
P.S. Допустим пишишь на HTML5 и JavaScript, а потом своё веб приложение переносишь в KaiOS https://kaiosinfo.ru/programmirovanie или вообще в Ionic - https://ionicframework.com/docs
- учитесь говорить на opengl
Зачем когда есть ThreeJS для ElectronsJS? https://github.com/jeromeetienne/electron-threejs-example а вместо Ajax net.Request - https://www.electronjs.org/docs/api/client-request
private Person _person = new Person ("Name0", 10); public Person person { get { return _person; }} ... _person.Age++; OnPropertyChanged ("person"); ...
, то тичего не произойдет.
Аболютно верно. Правильное поведение.
а так - другое дело
_person = new Person (_person.Name, _person.Age+1); OnPropertyChanged ("person");
И снова совершенно верно. Правильное поведение. В первом примере значение поля "person" не изменилось, как указывало оно на что-то вроде 0x2376894A, так и продолжило на него указывать.
Во втором случае значение "person" изменилось. Новый объект, новый адрес. Даже на такое среагирует (возраст не меняем):
_person = new Person (_person.Name, _person.Age);
Хотя с точки зрения банальной эрудиции как раз сейчас-то у нас в проперти "person" ничего не изменилось.
Похоже на разницу в == и equals()
ViewModel:
public class MainViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public MainViewModel()
{
Foo = new RelayCommand(Do_Foo);
}
private Person _person = new Person("John Smith", 33);
public Person Person
{
get
{
return _person;
}
}
public ICommand Foo { get; private set; }
private void Do_Foo(object obj)
{
_person.Age++;
PropertyChanged(this, new PropertyChangedEventArgs("Person"));
}
}
XAML:
<Window x:Class="WpfApplication1.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:WpfApplication1"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<local:MainViewModel />
</Window.DataContext>
<StackPanel>
<TextBlock>
<Run Text="Person name:" />
<Run Text="{Binding Person.Name, Mode=OneWay}" />
</TextBlock>
<TextBlock>
<Run Text="Person age:" />
<Run Text="{Binding Person.Age, Mode=OneWay}" />
</TextBlock>
<Button Content="Do Foo" Command="{Binding Foo}" />
</StackPanel>
</Window>
Работает.
Или есть еще другая точка зрения?
есть точка зрения, что мы пытаемся решать наши задачи, используя имеющиеся методы и парадигмы. для этого полезно знать, как они работают. один из аспектов я попытался изложить в первом посте.
вы тут же вспомнили почему-то INotifyPropertyChanged и ObservableCollection. с моей точки зрения, извините - некстати, спросил при чем тут это, вы так и не пояснили.
давайте будем считать, что проехали?
один из аспектов я попытался изложить в первом посте.
Сорри, тогда я так и не понял что именно вы хотели там пояснить.
Всё что понял - это то dependency property не реагирует на изменение внутреннего состояния объекта. При этом правильно не реагирует.
спросил при чем тут это, вы так и не пояснили
Ну так уже который раз пытаюсь это сделать но Вы совершенно не хотите в этом процессе участвовать.
с моей точки зрения, извините - некстати
ну с моей точки зрения, именно в этом проблема и заключается. Но если вы считаете это тупиком и не желаете даже смотреть в эту сторону, то я никак не смогу это изменить.
Пытался уже заходить с совершенно разных сторон, но вы никак не хотите обсуждать и эти аспекты.
давайте будем считать, что проехали?
Ну если вы изложите точно что вам требуется, я еще могу попробовать сделать пример.
Хотите контрол с двумя кнопочками, управляемый внешним объектом?