|
Правильное размещение функционала и привязки команд
|
|||
---|---|---|---|
#18+
Наверное, замучил всех своими "детскими" вопросами... Извините если, что .... Но я опять за своё :) У меня вопрос по правильному размещению функционала и привязки команд. Для объяснения простой пример. Код ViewModel - коллекция строк и методы для добавления, удаления и изменения элементов коллекции, и свойства для биндинга команд Код: 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.
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.
Привязка к VM в коде окна Код: c# 1. 2. 3. 4. 5. 6. 7.
С кнопкой Add - вопросов ни каких. Она биндится в VM из View. Вроде все принципы WPF и MVVM соблюдаются. С кнопкой Remove - уже у меня сомнения. Приходится из шаблона биндить её к свойству DataContext окна. Но, по идее, шаблон не должен ничего знать про окно. Понимаю, что не правильно, но не знаю как сделать правильно. С кнопкой Save - вообще, ступор. В метод сохранения надо передать текущее значение строки (оно служит идентификатором, который я для уменьшения кода примера не вводил) и новое значение из TextBox (он связан с VM в режиме OneWay). Как их оба одновременно передать не соображу ни как. ... |
|||
:
Нравится:
Не нравится:
|
|||
31.10.2018, 13:53 |
|
Правильное размещение функционала и привязки команд
|
|||
---|---|---|---|
#18+
команды всплывают по визуальному дереву, так как работают на маршрутизированных команда, их можно обрабатывать на уровне ListBox, а не ListBoxItem ... |
|||
:
Нравится:
Не нравится:
|
|||
31.10.2018, 14:29 |
|
Правильное размещение функционала и привязки команд
|
|||
---|---|---|---|
#18+
Roman Mejtesкоманды всплывают по визуальному дереву, так как работают на маршрутизированных команда, их можно обрабатывать на уровне ListBox, а не ListBoxItemНо саму же команду надо как-то присоединить к кнопке. Как это можно сделать не ссылаясь на общую VM, а используя информацию доступную только ListBoxItem (ControlTemplate )? ... |
|||
:
Нравится:
Не нравится:
|
|||
31.10.2018, 15:32 |
|
Правильное размещение функционала и привязки команд
|
|||
---|---|---|---|
#18+
Eld HaspНо саму же команду надо как-то присоединить к кнопке.Команду можно присоединить к кнопке на уровне ListBoxItem. И при нажатии кнопки команда начнет всплывать. А ловить и переадресовывать ее на RelayCommand нужно уже выше . ... |
|||
:
Нравится:
Не нравится:
|
|||
31.10.2018, 15:40 |
|
Правильное размещение функционала и привязки команд
|
|||
---|---|---|---|
#18+
Shocker.ProEld HaspНо саму же команду надо как-то присоединить к кнопке.Команду можно присоединить к кнопке на уровне ListBoxItem. И при нажатии кнопки команда начнет всплывать. А ловить и переадресовывать ее на RelayCommand нужно уже выше .Не дошло... Если команда у меня на уровне VM, как её присоединить на уровне ListBoxItem? На уровне ListBoxItem этой же команды нет. Или надо какую-то другую команду присоединить? Можно здесь подробнее и на примере. ... |
|||
:
Нравится:
Не нравится:
|
|||
31.10.2018, 15:52 |
|
Правильное размещение функционала и привязки команд
|
|||
---|---|---|---|
#18+
Мне тут как-то в голову пришла гениальная идея для таких случаев, хотя может она и банальная, интересно мнение Романа на этот счет. Берем простейший класс без визуального оформления: Код: c# 1. 2. 3.
Используем его как контейнер для ListBox, при этом явно привязавшись к модели Код: xml 1. 2. 3. 4.
А затем внутри шаблона для ListBoxItem-а просто ссылаемся на него Код: xml 1.
Я не пробовал это с командами - но что мешает свойство Command привязать таким образом к VM (не забыв про CommandParameter="{Binding}", чтобы знать, какой именно элемент вызывал команду) ... |
|||
:
Нравится:
Не нравится:
|
|||
31.10.2018, 15:58 |
|
Правильное размещение функционала и привязки команд
|
|||
---|---|---|---|
#18+
Eld HaspЕсли команда у меня на уровне VM, как её присоединить на уровне ListBoxItem? На уровне ListBoxItem этой же команды нетТы путаешь саму команду, которая определяется как public static readonly и видна отовсюду и привязку ее к ICommand. Нужно просто еще раз повнимательней перечитать теорию. Однако, выше я привел пример, который, вероятно, позволит обойтись без всплывающей команды, привязавшись напрямую из кнопки к модели. ... |
|||
:
Нравится:
Не нравится:
|
|||
31.10.2018, 16:00 |
|
Правильное размещение функционала и привязки команд
|
|||
---|---|---|---|
#18+
Для биндинга элемента ItemsControl на свойство датаконтекста самого ItemsControl я обычно использую решение Джоша Смита. А если в параметр команды нужно передать составное значение, состоящее частично из значений свойст датаконтекста вложенного элемента, частично - из значений свойств датаконтекста вышестоящего элемента, то вышепредложенный ElementSpy+мультибиндинг+IMultuValueConverter эту проблему вполне решают. ... |
|||
:
Нравится:
Не нравится:
|
|||
31.10.2018, 17:08 |
|
Правильное размещение функционала и привязки команд
|
|||
---|---|---|---|
#18+
В данном примере, при вызове команды ApplicationCommands.Delete для элемента списка, будет вызвана команда DeleteCommand из модели MainModel и элемент удалится. Кнопка удаления как и в вашем примере находится в шаблоне элемента списка. Код: 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.
Код: 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.
Код: 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.
можно, примерно, вот так. Только тут всё на коленке сделано, лишь бы работало. Но пример рабочий и используется вместо своей команды, ApplicationCommand'а, а лучше своей пользоваться ... |
|||
:
Нравится:
Не нравится:
|
|||
31.10.2018, 19:06 |
|
Правильное размещение функционала и привязки команд
|
|||
---|---|---|---|
#18+
Roman MejtesВ данном примере, при вызове команды ApplicationCommands.Delete для элемента списка, будет вызвана команда DeleteCommand из модели MainModel и элемент удалится. Кнопка удаления как и в вашем примере находится в шаблоне элемента списка ...... можно, примерно, вот так. Только тут всё на коленке сделано, лишь бы работало. Но пример рабочий и используется вместо своей команды, ApplicationCommand'а, а лучше своей пользоватьсяДа, мне бы лишь принцип понять. А в целом, правильно ли биндить, элементы шаблона (или DataTemplate) не к свойствам Item? Может более верным будет создание в объекте Item'а нужных свойств во ViewModel и биндить к ним? В принципе (почитал ещё вчера, сегодня), в этом отношении команда - это тоже свойство, метод и его можно создать в каждом объекте Item'а. Как концептуально, белее верно это будет сделать? ... |
|||
:
Нравится:
Не нравится:
|
|||
01.11.2018, 12:49 |
|
Правильное размещение функционала и привязки команд
|
|||
---|---|---|---|
#18+
Eld HaspКак концептуально, белее верно это будет сделать?ты сделал оба варианта? Тогда уже сам можешь сделать вывод что тебе проще. Паттерн MV**** никто 100 процентно по буквам не разделяет. Т..к.с некоторого момента издержки больше профита. Главное что вьюКонтроллер класс без гуи полностью поддерживает состояние объекта. Imho ... |
|||
:
Нравится:
Не нравится:
|
|||
01.11.2018, 12:58 |
|
Правильное размещение функционала и привязки команд
|
|||
---|---|---|---|
#18+
Eld HaspА в целом, правильно ли биндить, элементы шаблона (или DataTemplate) не к свойствам Item? Может более верным будет создание в объекте Item'а нужных свойств во ViewModel и биндить к ним? В принципе (почитал ещё вчера, сегодня), в этом отношении команда - это тоже свойство, метод и его можно создать в каждом объекте Item'а. Как концептуально, белее верно это будет сделать? Можно, но ведь под ListBoxItem у тебя отдельная вьюмодель и она по-правильному ничего не знает о своем родителе. Но ведь информация о нажатой кнопке нужна не самому элементу, а родителю. Тогда в родительской модели придется подписываться на события модели Item-а. А это значит, что придется обрабатывать добавление и удаление Item-ов в коллекцию (отписываться тоже обязательно, чтобы не было утечки памяти), то есть либо организовывать прокси для записи в коллекцию, либо отслеживать все события изменения коллекции. В общем, гораздо проще воспользоваться всплытием команды. ... |
|||
:
Нравится:
Не нравится:
|
|||
01.11.2018, 13:06 |
|
Правильное размещение функционала и привязки команд
|
|||
---|---|---|---|
#18+
Eld HaspКак концептуально, белее верно это будет сделать?Вот допустим у меня есть ListBox отображающий два свойства Name, Vaulue. Значение Value индивидуально для каждого Item'a, а Name оно одно и тоже. И меняется в зависимости от какого-то внешнего (по отношению к Item) свойства ViewModel. Я сейчас делаю таким образом. Когда создаю список для ListBox, то в ViewModel прописываю в каждом свойстве Name списка одно и тоже значение из общего свойства. Верный ли такой подход? Если верный, то может верным будет и поступить так с командами? ... |
|||
:
Нравится:
Не нравится:
|
|||
01.11.2018, 13:12 |
|
Правильное размещение функционала и привязки команд
|
|||
---|---|---|---|
#18+
Eld HaspЕсли верный, то может верным будет и поступить так с командами?нет. Name - это свойство уровня модели. Команда - это уровень представления. Команда - свойство кнопки на форме, на уровне модели кнопки нет. Можно на уровне модели обработать команду кнопки. И если нажатие кнопки нужно обрабатывать только в пределах модели Item-а, то это годится. Но если нажатие кнопки в Item-е требуется отслеживать выше по иерархии - этот подход превратится в головняк (см, что я писал выше) ... |
|||
:
Нравится:
Не нравится:
|
|||
01.11.2018, 13:21 |
|
Правильное размещение функционала и привязки команд
|
|||
---|---|---|---|
#18+
Shocker.ProМожно, но ведь под ListBoxItem у тебя отдельная вьюмодель и она по-правильному ничего не знает о своем родителе. Но ведь информация о нажатой кнопке нужна не самому элементу, а родителю. Тогда в родительской модели придется подписываться на события модели Item-а. А это значит, что придется обрабатывать добавление и удаление Item-ов в коллекцию (отписываться тоже обязательно, чтобы не было утечки памяти), то есть либо организовывать прокси для записи в коллекцию, либо отслеживать все события изменения коллекции. В общем, гораздо проще воспользоваться всплытием команды.Нет, может я Вас не правильно понимаю, может я не правильно свою мысль изложил. Сделать на уровне VM в каждом объекте Item'а свойство ссылающееся на общую команду. То есть, то что делалось в шаблоне с привязкой команды к DataContext окна (это же VM), сделать явно в VM. И тогда в шаблоне будет привязка команды к свойству Item'а. Получается VM знает о связях между отображаемыми данными - но это ей и положено знать. А View этой информацией не владеет, и может работать замкнуто внутри себя. ... |
|||
:
Нравится:
Не нравится:
|
|||
01.11.2018, 13:25 |
|
Правильное размещение функционала и привязки команд
|
|||
---|---|---|---|
#18+
Shocker.Proнет. Name - это свойство уровня модели. Команда - это уровень представления. Команда - свойство кнопки на форме, на уровне модели кнопки нет. Можно на уровне модели обработать команду кнопки. И если нажатие кнопки нужно обрабатывать только в пределах модели Item-а, то это годится. Но если нажатие кнопки в Item-е требуется отслеживать выше по иерархии - этот подход превратится в головняк (см, что я писал выше)Команда - уровень представления. Но привязки для неё создаются в VM. Методы которые она вызывает - это, по моему, вообще, уровень модели. Просто в примере модели для простоты нет, но теоретически изменять данные должна именно модель. Разве не так? То что Вы пишите - я внимательно читаю. И пытаюсь "переварить". Отсюда и "детские" вопросы. ... |
|||
:
Нравится:
Не нравится:
|
|||
01.11.2018, 13:31 |
|
Правильное размещение функционала и привязки команд
|
|||
---|---|---|---|
#18+
Eld HaspСделать на уровне VM в каждом объекте Item'а свойство ссылающееся на общую команду. То есть, то что делалось в шаблоне с привязкой команды к DataContext окна (это же VM), сделать явно в VM. И тогда в шаблоне будет привязка команды к свойству Item'а.Ссылка из ребенка на родителя - фиговая идея. Не делайте так в принципе (не только тут). ... |
|||
:
Нравится:
Не нравится:
|
|||
01.11.2018, 13:36 |
|
Правильное размещение функционала и привязки команд
|
|||
---|---|---|---|
#18+
Shocker.Pro, если у всех элементов дерева одинаковое время жизни, то это не так критично. Циклические ссылки сборщиком учитываются, все будет очищено, как только будет удалена ссылка на корневой элемент. Eld Hasp, Команды тут, слишком хорошо заходят, чтоб их игнорировать, это универсальный инструмент, который используется в WPF приложениях. Это их предназначение и не надо придумывать велосипед. RoutedCommand сама по себе определена на уровне View и является часть представления. Никакой связи с моделью представления такая команда не имеет и действует только в пределах визального дерева. Какой то элемент управления "возбуждает" маршрутизируемую команду, а какой то элемент выше по дереву её обрабатывает. Если вы посмотрите реализацию элементов управления в WPF, то там так и сделано (команды ApplicationCommands и д.р.). И для такого функционала никакая модель представления не нужна, по сути команда это обычное RoutedEvent. Но так как часто необходимо команду выполнить на уровне VM команду можно вызвать напрямую из модели представления через связывание (Binding), либо как я привел пример выше, скомбинировать оба подхода, на одному уровне представление возбуждается команда, а любом уровне выше команда обрабатывается. Не надо забывать, что каждая ссылка на другой объект, это L байт и если список элементов очень большой, умножайте на N. GC приходится работать дольше. Всё это ударит по перфомансу и если сейчас это не критично, то потом может сыграть злую шутку. ... |
|||
:
Нравится:
Не нравится:
|
|||
01.11.2018, 14:24 |
|
Правильное размещение функционала и привязки команд
|
|||
---|---|---|---|
#18+
Roman Mejtesесли у всех элементов дерева одинаковое время жизни, то это не так критично. Циклические ссылки сборщиком учитываются, все будет очищено, как только будет удалена ссылка на корневой элемент.Да, но десктопное приложение может не закрываться днями и неделями. При этом, если список элементов подвержен фильтрации, то он может обновляться часто, полностью очищаясь. И если забыть про отписку от событий, все элементы очищаемого списка из памяти не исчезнут - здравствуй утечка. Можно, конечно, использовать слабосвязанные события, но тут нет никакого смысла. ... |
|||
:
Нравится:
Не нравится:
|
|||
01.11.2018, 14:36 |
|
Правильное размещение функционала и привязки команд
|
|||
---|---|---|---|
#18+
Shocker.Proесли список элементов подвержен фильтрацииимеется ввиду, конечно, не встроенная фильтрация представления, а именно перезагрузка списка ... |
|||
:
Нравится:
Не нравится:
|
|||
01.11.2018, 14:37 |
|
Правильное размещение функционала и привязки команд
|
|||
---|---|---|---|
#18+
Roman MejtesВ данном примере, при вызове команды ApplicationCommands.Delete для элемента списка.........Смотрю я на Ваши примеры и охватывает меня уныние от понимания ничтожности собственных знаний.......... :( ... |
|||
:
Нравится:
Не нравится:
|
|||
01.11.2018, 15:48 |
|
Правильное размещение функционала и привязки команд
|
|||
---|---|---|---|
#18+
[quot Shocker.Pro]Roman Mejtes......... И если забыть про отписку от событий, все элементы очищаемого списка из памяти не исчезнут - здравствуй утечка .............. То есть привязка команды содержит в себе подписку на событие? И при изменении списка, если в нём содержатся привязанные команды, элементы списка не отправятся в мусор? Из-за подписки на событие они будут оставаться в памяти? ... |
|||
:
Нравится:
Не нравится:
|
|||
01.11.2018, 15:54 |
|
Правильное размещение функционала и привязки команд
|
|||
---|---|---|---|
#18+
Eld HaspТо есть привязка команды содержит в себе подписку на событие? И при изменении списка, если в нём содержатся привязанные команды, элементы списка не отправятся в мусор? Из-за подписки на событие они будут оставаться в памяти?Нет. Я же говорил про обычные события внутри вьюмодели. Команды как раз-таки построены на слабосвязанных событиях, так что за них можно не раздумывать. ... |
|||
:
Нравится:
Не нравится:
|
|||
01.11.2018, 16:03 |
|
Правильное размещение функционала и привязки команд
|
|||
---|---|---|---|
#18+
Что-то долго до меня всё доходит. С вашей помощью и подсказками, сделал так. Код ViewModel Код: 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.
CommandsCollection и RelayCommand - не менял. Полностью из поста 21720777 от Roman Mejtes . Словарь ExampleCommandDict.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. 59. 60. 61. 62. 63.
И само окно ExampleCommand.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.
Из того, что понял. - Каких-то "стандартных" методов для подключения кастомных команд в списочных элементах в WPF не предусмотрено. Поэтому и пришлось создавать класс ContextHolder, который отлавливает команды из вложенных элементов и в котором можно указать привязки команд на методы VM. - Для "отлова команды" в классе CommandBinding используется привязка к одной из команд класса RoutedUICommand. Это обязательное условие? - Если использовать напрямую команды из класса RoutedUICommand, то они требуют присоединения обработчика в самом окне на уровне View. Какая-то, как мне кажется, не завершённость в реализации... Или я опять чего-то не до понял? ... |
|||
:
Нравится:
Не нравится:
|
|||
03.11.2018, 15:58 |
|
Правильное размещение функционала и привязки команд
|
|||
---|---|---|---|
#18+
Eld Hasp- Для "отлова команды" в классе CommandBinding используется привязка к одной из команд класса RoutedUICommand. Это обязательное условие?Это не привязка. Я советовал перечитать, что собой представляет команда. Команда - это просто экземпляр класса "RoutedUICommand", присвоенный статической переменной. Команда САМА ПО СЕБЕ ничего не делает - это просто маркер. Button заставляет всплывать экземпляр, присвоенный статической переменной ApplicationCommands.New. Он отлавливается уровнем выше с помощью local:CommandBinding. Но этот "уловитель" должен же знать, на какую команду реагировать, иначе он будет реагировать на все команды, которые придут "снизу". Поэтому в его свойстве RoutedCommand указывается тот самый маркер, который нужно отлавливать именно ему. ... |
|||
:
Нравится:
Не нравится:
|
|||
03.11.2018, 16:19 |
|
|
start [/forum/topic.php?fid=21&msg=39726692&tid=1440275]: |
0ms |
get settings: |
8ms |
get forum list: |
11ms |
check forum access: |
4ms |
check topic access: |
4ms |
track hit: |
52ms |
get topic data: |
12ms |
get forum data: |
3ms |
get page messages: |
75ms |
get tp. blocked users: |
2ms |
others: | 12ms |
total: | 183ms |
0 / 0 |