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

Снова WPF

894  
  max2_2000 знакомое лицо29.01.22 23:01
NEW 29.01.22 23:01 

для "бывалых" задачка, уверен, примитивная.

имеем UserControl, в нем - TextBox.

нужно "организовать" Binding mode="OneWayToSource", в общем, чтобы при изменении текста в этом текстбоксе объект DataContent этого UserControl (или его Parent`a) был уведомлен (был вызван setter прибайнднутого проперти).

повсюду натыкаюсь на примеры, как апдэйтить текст в обратную сторону, но это - не проблема. а в обратную сторону - как будто только мне впервые такое понадобилось.

ссылку на работающий пример - идеальная подсказка.

спасибо!

#1 
NightWatch коренной житель30.01.22 11:00
NightWatch
NEW 30.01.22 11:00 
в ответ max2_2000 29.01.22 23:01, Последний раз изменено 30.01.22 12:19 (NightWatch)
повсюду натыкаюсь на примеры, как апдэйтить текст в обратную сторону, но это - не проблема. а в обратную сторону - как будто только мне впервые такое понадобилось.

А в чем сложность поменять в примерах Mode на OneWayToSource?

чтобы при изменении текста в этом текстбоксе

По умолчанию у свойства Text установлен UpdateSourceTrigger в LostFocus. Вероятно, у Binding тебе его надо установить в PropertyChanged, чтобы изменения происходили при наборе текста.

#2 
alex445 коренной житель30.01.22 14:36
NEW 30.01.22 14:36 
в ответ max2_2000 29.01.22 23:01, Последний раз изменено 30.01.22 14:36 (alex445)

От вью ко вью модели байндинг работает и так, безо всяких дополнительных реализаций. Указываешь вью контекст данных, и как-то внутри она сама вью модель обновляет. А от вью модели ко вью - нужно реализовать INotifyPropertyChanged во вью модели.

#3 
  max2_2000 знакомое лицо30.01.22 15:30
NEW 30.01.22 15:30 
в ответ NightWatch 30.01.22 11:00

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


есть UserControl (пусть будет MyUC). в нем один из элементов - Canvas.

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

т.е. где-то в MyUC вызывается некий метод void mouseLB_up(object sender, MouseButtonEventArgs e) {.

и что мы там должны делать, чтобы DataContent каким-то образом "забрал" некий объект?

некошерный метод - в этом методе кастнуть this.DataContent в наш класс, и вызвать его какое-нибудь метод. но тогда нафига нам все эти танцы с мввм-ами? нужно, чтобы по той же схеме все срабатывало. знаю, можно через Interaction.Triggers привязать команду. но не знаю, как в нее параметры подвесить.

в общем, метаюсь в растерянности. даже иногда выпить хочется.


#4 
alex445 коренной житель30.01.22 15:45
NEW 30.01.22 15:45 
в ответ max2_2000 30.01.22 15:30
и что мы там должны делать, чтобы DataContent каким-то образом "забрал" некий объект?

Через байндинги. Если надо много разных параметров передать - гуглите что-то вроде "pass multiple parameters to view model" or "multi binding".

#5 
alex445 коренной житель30.01.22 15:54
NEW 30.01.22 15:54 
в ответ max2_2000 30.01.22 15:30
но не просто уведомление, а с некими параметрами. пусть даже просто координаты клика

"Пусть даже", хех. Как раз это не "пусть даже", а вполне себе усложнённый случай. Мышь не является частью вью, поэтому придётся городить какой-то сервис (класс), который будет отслеживать положение мыши, и вязать его со вью или вью моделью. Например, через прикрепляемые поведения. Ну или в коуд бехайнд вью присваивать координаты мыши вью модели, которая доступна через свойство DataContext.

#6 
  max2_2000 знакомое лицо30.01.22 15:57
NEW 30.01.22 15:57 
в ответ alex445 30.01.22 15:54, Последний раз изменено 30.01.22 15:59 (max2_2000)
Мышь не является частью вью

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


зы. мои пояснения немного понос напоминают, но по сравнению с вашими - образец четкости.


#7 
alex445 коренной житель30.01.22 16:19
NEW 30.01.22 16:19 
в ответ max2_2000 30.01.22 15:57
ух, как интересно. наверное, она лежит где-то в базе данных, или из интернета скачивается.

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

How do I get the current mouse screen coordinates in WPF? - Stack Overflow

Кстати, иногда не возбраняется использовать ссылки на WinForms библиотеки. Раньше я в WPF использовал диалог открытия окна, например, из Форм.

#8 
  max2_2000 знакомое лицо30.01.22 16:38
NEW 30.01.22 16:38 
в ответ alex445 30.01.22 16:19
но она не является частью вью WPF приложения.

вы, конечно, с большим опытом, и мне не поверите, но я вам ничего другого не могу сообщить, кроме как то, что мышь (как и клавиатура, и не только), безусловно, относятся к GUI. то, что эта аббревиатура означает graphical user interface, не означает, что к этому интерфейсу относятся только пикселы на экране.


#9 
NightWatch коренной житель30.01.22 16:42
NightWatch
30.01.22 16:42 
в ответ max2_2000 30.01.22 15:30, Последний раз изменено 30.01.22 16:43 (NightWatch)

В MyUC создаешь свое dependency property. Как, описано здесь.

Если, необходимо, делаешь его readonly (Read-only dependency properties).

при клике на канву

При клике обновляешь значение свойства.

#10 
  max2_2000 знакомое лицо30.01.22 17:08
NEW 30.01.22 17:08 
в ответ NightWatch 30.01.22 16:42
В MyUC создаешь свое dependency property. Как, описано здесь

.я их уже с закрытыми глазами создаю. но все работает без проблем, пока они обновляются СНАРУЖИ, через байндинг. а в обратную сторону что-то пока не найду как.


При клике обновляешь значение свойства.

как? например, вот наше проперти:

public object testobject {
    get { return GetValue(testobjectProperty); }
    set { SetValue(testobjectProperty, value); }
}
public static readonly DependencyProperty testobjectProperty = DependencyProperty.Register("testobject",
                                                                                typeof(object),
                                                                                typeof(MyUC),
                                                                                new FrameworkPropertyMetadata(
                                                                                new PropertyChangedCallback(new_testobject)));
private static void new_testobject(DependencyObject source, DependencyPropertyChangedEventArgs e) {
    (source as MyUC).process_testobject(e.NewValue);
}
...

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

        void mouseLB_up(object sender, MouseButtonEventArgs e) {
            this.testobject = e;
        }
#11 
  max2_2000 знакомое лицо30.01.22 17:19
NEW 30.01.22 17:19 
в ответ NightWatch 30.01.22 16:42

оно сработало! спасибо вам большое! могу только добавить "как просто открывался ларчик".

#12 
alex445 коренной житель30.01.22 18:54
NEW 30.01.22 18:54 
в ответ max2_2000 30.01.22 17:08, Последний раз изменено 30.01.22 18:58 (alex445)

Это всё костыли - работа с обработчиками событий, ещё конвертеры некоторые используют. Более верный путь - добавлять поведения (Behaviors):


<Canvas>

<i:Interaction.Behaviors>

<mouseMoveMvvm:MouseBehaviour MouseX="{Binding PanelX, Mode=OneWayToSource}" MouseY="{Binding PanelY, Mode=OneWayToSource}" />

</i:Interaction.Behaviors>

</Canvas>


С ними можно много чего сделать. Например


<ListBox>

<i:Interaction.Behaviors>

<behaviors:ScrollSelectedItemIntoView />

</i:Interaction.Behaviors>

</ListBox>


А так будете на каждую задачу костыли городить с обработчиками в code behind. Поведения же как раз на dependency properties завязаны и тоже могут использовать события контролов, но лучше всё организуют и проще с их помощью добавлять функциональность потом в другие места (повторное использование).

#13 
  max2_2000 знакомое лицо30.01.22 22:03
NEW 30.01.22 22:03 
в ответ alex445 30.01.22 18:54

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

#14 
alex445 коренной житель31.01.22 00:26
NEW 31.01.22 00:26 
в ответ alex445 30.01.22 18:54
<behaviors:ScrollSelectedItemIntoView />

Кстати, эта штука незаменима, когда делаешь какой CRUD и надо открыть объект для редактирования. Свойства типа выбранного элемента из коллекции можно отобразить комбобоксом или листбоксом. Так вот, в листбоксе выбранный кодом (не пользователем через UI) элемент автоматом не показывается в видимой области списка. Так что приходится приделывать ему такое поведение.

#15 
alex445 коренной житель31.01.22 00:42
NEW 31.01.22 00:42 
в ответ max2_2000 30.01.22 22:03, Последний раз изменено 31.01.22 00:43 (alex445)
а если вы хотели бы не координаты передавать, а какие-то более релевантные вещи, в контроле на основании этих координат вычисленные? давайте на привычном вам языке. вы предлагаете метод, который способен передать координаты мыши, которые вообще-то к вью-модели, а тем более к модели, никакого отношения не имеют. я рассматривал этот вариант, но скорее предпочел бы вызвать метод вью-модели из вью непосредственно, так как вытаскивать во вьюмодель не принадлежащий ей функционалитет - последний вариант. тогда, например, если вы когда-то из эстетических соображений измените что-то в этой канве, и нужно будет эти значения иначе вычислять, вам придется делать изменения и во вью, и во вью-модели. а бог не для этого дал нам идею разделения ответственности.

Вычислять можно в:


вью:

- конвертерах,

- code behind вью (в событиях, например),

- коде контролов (через dependency property например),


вью модель:

- свойствах вью моделей,

- командах вью моделей,

- методах вью моделей (например, через InvokeCommandAction).


Выбирайте, что вам угодно.

#16 
  max2_2000 знакомое лицо31.01.22 11:58
NEW 31.01.22 11:58 
в ответ alex445 31.01.22 00:42

все понял. пошел выбирать.

#17 
alex445 коренной житель31.01.22 14:08
NEW 31.01.22 14:08 
в ответ max2_2000 31.01.22 11:58
все понял. пошел выбирать.

Не всё так просто. Изначально в WPF была поддержка команд лишь для некоторых контролов. Потом добавили вызов любого метода через расширение InvokeCommandAction из Expression Blend SDK, что по сути отменило потребность в командах. Но это расширение поддерживает только старые версии фреймворка (по 4.5 вроде), а для новых оно не работает. Но вроде как люди свои вещи для этого разработали - где-то находил замену.

#18