Deutsch
Germany.ruФорумы → Архив Досок→ Программирование

Заморочка интересная с WPF binding

1981  1 2 3 4 5 6 все
  moose коренной житель02.12.20 16:07
NEW 02.12.20 16:07 

знаю, что всего там еще не перевидал, но все же достаточно много.

наверное, неправильный выбрал дезигн, но лучше расскажу по порядку.


делаю 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(); }}, и тогда оно сработает.


допускаю, что это только для меня оказалось новостью, а для остальных - "и дураку понятно", но я пару часов протупил, решил исповедоваться : (

#1 
AlexNek патриот02.12.20 16:45
AlexNek
02.12.20 16:45 
в ответ moose 02.12.20 16:07, Последний раз изменено 02.12.20 16:47 (AlexNek)

Сорри, что написано вроде как понятно, но в чем проблема так и не понял. смущ Какое нибудь приложение есть, что неправильно работает?

Ну и у меня OnPropertyChanged () или со старыми версиями OnPropertyChanged (nameof(PropertyName));

Snoop пользовали?


Да, и для UI исрользую ObservableCollection<T>, а не List

#2 
  moose коренной житель02.12.20 17:23
NEW 02.12.20 17:23 
в ответ AlexNek 02.12.20 16:45

у меня не лист, а "свой объект". я список просто взял для примера. мог взять все что угодно кроме примитива.

проблема в том, что я не нашел лучшего дезигнерского решения что-нибудь перенастроить в контроле, кроме как вделать ему дэпэндэнси пропэрти и через типа обновление оного заставить контрол реагировать на событие. и оно срабатывает, если каждый раз передавать новую копию, а не тот же измененный объеат. хэндл должен быть не тот же, что при последнем обновлении.

все вроде теперь заработало, но нужно поковырять другие возможные варианты.


чтобы вас не отвлекать на 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");
#3 
AlexNek патриот02.12.20 18:47
AlexNek
NEW 02.12.20 18:47 
в ответ moose 02.12.20 17:23
и оно срабатывает, если каждый раз передавать новую копию, а не тот же измененный объект

Ну так абсолютно правильно срабатывает. Проперти то на объект, а не на его содержимое.

Если нужно отслеживать изменения в объекте, то объект нужно наследовать от INotifyPropertyChanged хотя бы.


Именно по этой причины для меняющегося списка вместо List используется ObservableCollection.


#4 
  moose коренной житель02.12.20 22:22
NEW 02.12.20 22:22 
в ответ AlexNek 02.12.20 18:47

что-то я недопонял, при чем здесь INotifyPropertyChanged и проперти-объект, и почему "хотя бы". поясните.

#5 
AlexNek патриот02.12.20 22:49
AlexNek
NEW 02.12.20 22:49 
в ответ moose 02.12.20 22:22, Последний раз изменено 02.12.20 23:04 (AlexNek)

Ну давайте так.

- Что может определить обычная проперть? Только то что ее значение изменилось. Что там происходит с объектом она просто так узнать не может.

Что бы определять изменение объекта нужно еще иметь какую то договоренность. Одна из них 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.

#6 
  moose коренной житель03.12.20 17:27
NEW 03.12.20 17:27 
в ответ AlexNek 02.12.20 22:49

вы мне не рассказывайте азы, я их давно прошел. я прошу прояснить, при чем здесь INotifyPropertyChanged к property-объекту (Person в моем последнем примере).

#7 
AlexNek патриот03.12.20 19:28
AlexNek
NEW 03.12.20 19:28 
в ответ moose 03.12.20 17:27

Сорри, это было такое пояснение.

Попробуем тогда с другого боку.

Вот мне дали объект Person на пользование. Как мне узнать, что внутри объекта произошли какие то изменения?

#8 
uscheswoi_82 местный житель03.12.20 20:47
uscheswoi_82
NEW 03.12.20 20:47 
в ответ AlexNek 03.12.20 19:28

НП.

WPF просто выбешивает, когда же наконец-то на HTML5 перейдём!!!

кто как обзывается, тот так сам называется... маску ношу чтобы не заразить антиваксеров... Дневник тяжелобольного инвалида
#9 
  moose коренной житель03.12.20 23:04
NEW 03.12.20 23:04 
в ответ AlexNek 03.12.20 19:28

это уже - из области философии. спросите перзону: у тебя все по-старому, или изменилось чего : )

#10 
  moose коренной житель03.12.20 23:07
NEW 03.12.20 23:07 
в ответ uscheswoi_82 03.12.20 20:47, Последний раз изменено 03.12.20 23:09 (moose)

хтмл5 еще выбесительнее. думаю, GUI еще ожидает возрождение в каком-нибудь гениальном языке его описания.

на сегодня хамл - наиболее удачное из всего что есть. ваши девки-монстры ужасны что в хтмл5, что в хамл.

не нравится хамл - учитесь говорить на opengl

#11 
AlexNek патриот03.12.20 23:54
AlexNek
NEW 03.12.20 23:54 
в ответ moose 03.12.20 23:04
это уже - из области философии

Никак нет - чистое программирование смущ


Если я хочу узнать изменилось ли что внутри объекта мне нужен канал обратной связи от объекта. В котором объект мне скажет, что его состояние изменилось.

Можно конечно еще поизвращаться на предмет сравнения сериализованной копии объекта или еще как. Но нам то извращения не нужны.


Или есть еще другая точка зрения?

#12 
AlexNek патриот03.12.20 23:55
AlexNek
NEW 03.12.20 23:55 
в ответ uscheswoi_82 03.12.20 20:47

Это для темы "просто поболтать", тут не хочу засирать, сорри.

#13 
uscheswoi_82 местный житель04.12.20 00:00
uscheswoi_82
NEW 04.12.20 00:00 
в ответ moose 03.12.20 23:07
хтмл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

кто как обзывается, тот так сам называется... маску ношу чтобы не заразить антиваксеров... Дневник тяжелобольного инвалида
#14 
uscheswoi_82 местный житель04.12.20 00:05
uscheswoi_82
NEW 04.12.20 00:05 
в ответ moose 03.12.20 23:07
- учитесь говорить на opengl

Зачем когда есть ThreeJS для ElectronsJS? https://github.com/jeromeetienne/electron-threejs-example а вместо Ajax net.Request - https://www.electronjs.org/docs/api/client-request

кто как обзывается, тот так сам называется... маску ношу чтобы не заразить антиваксеров... Дневник тяжелобольного инвалида
#15 
MrSanders коренной житель04.12.20 10:32
NEW 04.12.20 10:32 
в ответ moose 02.12.20 17:23, Последний раз изменено 04.12.20 10:33 (MrSanders)
    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()

#16 
Программист коренной житель04.12.20 15:28
NEW 04.12.20 15:28 
в ответ moose 02.12.20 17:23

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>


Работает.

#17 
MrSanders коренной житель04.12.20 16:05
NEW 04.12.20 16:05 
в ответ Программист 04.12.20 15:28
PropertyChanged(this, new PropertyChangedEventArgs("Person"));

Это не спортивно! Оно не само! :)

#18 
  moose коренной житель04.12.20 16:47
NEW 04.12.20 16:47 
в ответ AlexNek 03.12.20 23:54
Или есть еще другая точка зрения?

есть точка зрения, что мы пытаемся решать наши задачи, используя имеющиеся методы и парадигмы. для этого полезно знать, как они работают. один из аспектов я попытался изложить в первом посте.

вы тут же вспомнили почему-то INotifyPropertyChanged и ObservableCollection. с моей точки зрения, извините - некстати, спросил при чем тут это, вы так и не пояснили.
давайте будем считать, что проехали?

#19 
AlexNek патриот04.12.20 18:33
AlexNek
NEW 04.12.20 18:33 
в ответ moose 04.12.20 16:47
один из аспектов я попытался изложить в первом посте.

Сорри, тогда я так и не понял что именно вы хотели там пояснить.

Всё что понял - это то dependency property не реагирует на изменение внутреннего состояния объекта. При этом правильно не реагирует.


спросил при чем тут это, вы так и не пояснили

Ну так уже который раз пытаюсь это сделать но Вы совершенно не хотите в этом процессе участвовать.


с моей точки зрения, извините - некстати

ну с моей точки зрения, именно в этом проблема и заключается. Но если вы считаете это тупиком и не желаете даже смотреть в эту сторону, то я никак не смогу это изменить.

Пытался уже заходить с совершенно разных сторон, но вы никак не хотите обсуждать и эти аспекты.


давайте будем считать, что проехали?

Ну если вы изложите точно что вам требуется, я еще могу попробовать сделать пример.

Хотите контрол с двумя кнопочками, управляемый внешним объектом?

#20 
1 2 3 4 5 6 все