MVVM - PropertyChanged ў мадэлі або ViewModel?

Я прайшоў праз некалькі MVVM падручнікаў, і я бачыў гэта зроблена ў абодвух напрамках. Большасць з іх выкарыстоўваюць у ViewModel для PropertyChanged (што я і рабіў), але я наткнуўся на той, які зрабіў гэта ў мадэлі. Ці з'яўляюцца абодва метаду прымальныя? Калі так, то якія перавагі/недахопы розных метадаў?

18
Вось што я зразумеў. Я быў зьбянтэжаны, калі я ўбачыў адзін прыклад прывязкі ў мадэлях.
дададзена аўтар Jason D, крыніца
@Coder. Прывязка дадзеных інфраструктуры ўжо прапануе больш чым дастаткова «развязкі». Абкручванне ўсіх вашых асоб у псеўда ракурсе мадэлі як раз і прыводзіць да ўцечак памяці, няўзгодненасць UI/дадзеных і іншым тонкім памылак. Даданне абстракцыі дзеля абстракцыі проста не з'яўляецца добрай ідэяй.
дададзена аўтар Jonathan Allen, крыніца
Мадэль прызначана толькі мець бізнес-логіку прыкладання. Лепш мець злучаюць ўласцівасці ў ViewModel, якія будуць гаспадарчыя суб'екты развязкі і View
дададзена аўтар Kurubaran, крыніца

7 адказы

Шаблоны Microsoft, і практыка, вынаходнік MVVM, і я ўсё не згодныя з абраным адказам.

<�Р> Як правіла, мадэль рэалізуе сродкі, якія дазваляюць лёгка прывязаць да выгляду. Як правіла, гэта азначае, што ён падтрымлівае ўласцівасць і збор зменены апавяшчэння праз інтэрфейсы INotifyPropertyChanged і INotifyCollectionChanged. Мадэлі класаў, якія ўяўляюць сабой калекцыі аб'ектаў, як правіла, з'яўляюцца вытворнымі ад класа ObservableCollection, які забяспечвае рэалізацыю INotifyCollectionChanged інтэрфейсу.

-- Microsoft Patterns and Practices: http://msdn.microsoft.com/en-us/library/gg405484%28v=pandp.40%29.aspx#sec4

<�Р> У гэтай кропцы прывязкі дадзеных ўваходзіць у гульню. У простых прыкладах, выгляд дадзеных звязаны непасрэдна да мадэлі. Часткі мадэлі проста адлюстроўваюцца ў прадстаўленні з дапамогай аднабаковага звязвання дадзеных. Іншыя часткі мадэлі можа быць адрэдагаваныя непасрэдна звязваецца паказальнымі двухбаковым да дадзеных. Напрыклад, лагічнае значэнне ў мадэлі дадзеных можа быць звязаны з CheckBox, або поле радкі ў TextBox. </Р>

-- John Gossman, inventor of MVVM: http://blogs.msdn.com/b/johngossman/archive/2005/10/08/478683.aspx

My own article: http://www.infoq.com/articles/View-Model-Definition


Гэта анты-мадэль, каб мець «выгляд-мадэль», якая проста абгортвае мадэль і выстаўляе адзін і той жа спіс уласцівасцяў. Праца па паказах мадэлі з'яўляецца выклік знешніх службаў і выставіць індывідуальную і калекцыю мадэляў, якія вяртаюць гэтыя паслугі.

прычыны:

  1. Калі мадэль абнаўляецца непасрэдна, выгляд-мадэль не будзе ведаць, каб страляць ўласцівасць змененае падзея. Гэта прыводзіць да таго, карыстацкаму інтэрфейсу, каб выйсці з сінхранізацыі.
  2. Гэта сур'ёзна абмяжоўвае вашыя варыянты для адпраўкі паведамленняў паміж бацькам і дзіцем View-мадэллю.
  3. Калі мадэль мае сваё ўласнае ўласцівасць зменена апавяшчэнне, # 1 і 2 не з'яўляюцца праблемай. Замест гэтага, вы павінны турбавацца аб уцечках памяці, калі ўпакоўшчык VM выходзіць з вобласці бачнасці, але мадэль не робіць.
  4. Калі вашы мадэлі з'яўляюцца складанымі, з вялікай колькасцю дзяцей і аб'ектамі, то вы павінны ісці па ўсім дрэве і стварыць другі граф аб'ектаў, што цень першы. Гэта можа быць даволі стомным і памылак.
  5. абматаць калекцыі асабліва цяжка працаваць. Кожны раз, калі нешта (UI або бэкенд) ўстаўляе або выдаляе элемент з калекцыі, калекцыя ценяў павінна быць абноўлена, каб адпавядаць. Такі код сапраўды цяжка атрымаць правы.

Гэта не значыць, што вы ніколі не будзеце мець патрэбу ў выглядзе-мадэлі, якая абгортвае мадэль. Калі выгляд-мадэль дае ўласцівасці, якія істотна адрозніваецца ад мадэлі і не можа быць проста замаўчалі з IValueConverter, затым абкручванне выгляд-мадэль мае сэнс.

Іншая прычына, магчыма, спатрэбіцца абгортачную выгляд-мадэлі з'яўляецца тое, што вашы класы дадзеных не падтрымліваюць прывязку дадзеных па нейкай прычыне. Але нават тады, гэта, як правіла, лепш проста стварыць нармальную, звязваюць мадэль і скапіяваць дадзеныя з зыходных класаў дадзеных.

І, вядома, на ваш погляд, мадэль будзе мець UI спецыфічныя ўласцівасці, такія як, які элемент у калекцыі ў цяперашні час выбраны.

27
дададзена
Гэты артыкул з'яўляецца поўным смеццем і аўтар паняцця не мае, што ён кажа. Адзіная прычына, чаму ён сыходзіць з абгортваць кожны аб'ект кліента ў CustomerViewModel з'яўляецца тое, што яго аб'ект кліента трывіяльна. Калі б гэта быў складаны аб'ект са сваімі калекцыямі (напрыклад, ўласцівасць Orders) уся карціна разваліцца.
дададзена аўтар Jonathan Allen, крыніца
Што тычыцца паслуг, якія змяняюць мадэль, рэальная карціна MVVM робіць гэта бяспечным (пры ўмове, вы паслухаеце резьб правілы). Але ў той час як гэта дае вам магчымасць, ці не робіць гэты варыянт сэнс залежыць ад вашага прыкладання.
дададзена аўтар Jonathan Allen, крыніца
DI не мае значэння, шаблон MVVM не гаворыць, як ВМ і мадэлі створаныя. MVVM тычыцца толькі сябе сувязь паміж трыма. VM ніколі не павінны «распаўсюджвацца мадэль» да меркавання, ён павінен проста выставіць яго і дазволіць прывязку дадзеных, каб зрабіць усё астатняе. Што тычыцца каманд, то яны павінны быць выкарыстаны, калі двухбаковая прывязка дадзеных не будзе працаваць (напрыклад пстрычкі кнопкі).
дададзена аўтар Jonathan Allen, крыніца
Проста не значыць «не вытворчасць». Простыя сродкі, што з'яўляецца карціна, што большая частка кода павінна прытрымлівацца.
дададзена аўтар Jonathan Allen, крыніца
дададзена аўтар Jonathan Allen, крыніца
Так як вы, здаецца, апантаны асоб над тэхнічнымі дэталямі, як пра гэта цытата з Джона Госсман, чалавек, які на самай справе вынайшаў шаблон MVVM: «На дадзены момант прывязкі дадзеных уступае ў гульню ў простых прыкладах, выгляд дадзеных звязаны непасрэдна. мадэль. частка мадэлі проста адлюстроўваецца ў прадстаўленні з дапамогай аднабаковы звязвання дадзеных. Іншыя часткі мадэлі можа быць адрэдагавана шляхам непасрэднага звязвання элементаў кіравання двухбаковае да дадзеных. Напрыклад, лагічнае значэнне ў мадэлі можа быць дадзеныя прывязваецца да CheckBox або радковага поля да TextBox «.
дададзена аўтар Jonathan Allen, крыніца
ViewModel, што робіць выклік сховішча, калі вы выкарыстоўваеце адзін. Калі няма, то ён выклікае знешнюю службу непасрэдна. Канструкцыя выгляду-мадэлі не змяняецца ў любым выпадку.
дададзена аўтар Jonathan Allen, крыніца
@JonathanAllen Такім чынам, у мяне ёсць пытанне: што, тое, пра Dependency Injection (DI), г.зн. View Model насычана спасылкамі на яго мадэлі (ы) з DI? В.М., а затым, здабывае дадзеныя з мадэлі (працуе на ёй; перакладае яго; і г.д.), распаўсюджваецца, што мадэль з выглядам, а затым дзейнічае ў якасці пасярэдніка паміж мадэллю і выглядам. Медыяцыя палягчаецца з дапамогай каманд, ці не так? Я адчуваю, як з абслугоўваннем (ы), абнаўленне (ы) мадэль (ы) толькі дадае непатрэбную складанасць праграмы - ці, рызыкуе празмерна модульнасці праграмы (я супер новай для ўсяго гэтага).
дададзена аўтар Thomas, крыніца
Калі ласка, паглядзіце на гэтае пытанне: stackoverflow.com/questions/16947122/…
дададзена аўтар Mare Infinitus, крыніца
Я вельмі рады пачуць Ваша тлумачэнне другой частцы падкрэсліваецца, што я адправіў. Вы проста прымушаюць мяне ўсміхацца, ты вельмі творчы!
дададзена аўтар Mare Infinitus, крыніца
Калі вы, па меншай меры, прачытаць артыкул, магчыма, нават вы знойдзеце цэнтральныя часткі. "простыя прыклады" на самой справе не код прадукцыі. Непасрэдна з гэтага артыкула: <�б> На практыцы, аднак, толькі невялікая частка інтэрфейсу прыкладання можа быць дадзеныя звязаны непасрэдна да мадэлі Магчыма, вы не так шмат вопыту ў рэальных прыкладаннях, але наўпрост прывязка да мадэлі з'яўляецца не проста не прыдатны ў кампаніях і праектах, якія я працаваў. Але гэта сапраўды добры старт, што вы адкрыты для пачаткоўцаў кіраўніцтва для MVVM. Я разумею, што.
дададзена аўтар Mare Infinitus, крыніца
Паглядзіце на мой адказ, і іншыя мае каментары. Вы працуеце з гэтым Джош Сміт, які напісаў гэты артыкул? І вы думаеце, што ён не так добры? Дык чаму, чорт вазьмі, ён MVP па працы з WPF, і вы не?
дададзена аўтар Mare Infinitus, крыніца
Аўтар «сыходзіць», таму што <�б> ён разумее, што ён кажа. Вы прапаведуеце, што няма ніякай неабходнасці ў ViewModel наогул, што прама не так. Прывязка да мадэлі непасрэдна з'яўляецца выключным выпадкам, а не звычайны выпадак. І гэтае пытанне тут пра "што рабіць». Магчыма, вы перачытайце пытанне і мой адказ. Думка, што некаторыя чытання можа дапамагчы вам зразумець, як працуе MVVM, але, здаецца, гэта губляецца высілак. Асабліва, калі гэтыя патрабаванні становяцца ўсё больш складанымі існуе больш высокая патрэба ў добрай архітэктуры і дызайну. Але чаму я павінен турбавацца, калі вы не клапоціцеся пра такія рэчы.
дададзена аўтар Mare Infinitus, крыніца
магчыма, гэты артыкул можа праліць некаторы святло, як гэта здаецца вельмі трэба MSDN .microsoft.com/EN-US/часопіс/dd419663.aspx # id0090102
дададзена аўтар Mare Infinitus, крыніца
выклік знешніх паслуг з'яўляецца часткай ўзроўню інфраструктуры, а не часткі ViewModel. Вы калі-небудзь чулі пра сховішча шаблону? Здаецца, вы жывяце да гэтага часу ў свеце формаў.
дададзена аўтар Mare Infinitus, крыніца
@JonathanAllen Дзякуй. Вы робіце некалькі вельмі добрых момантаў. Я згодны, што абгортка віртуальныя машыны ўяўляюць сабой адходы кода і нічога не дадаюць да структуры праекта, акрамя як зрабіць яго больш складаным. Віртуальныя машыны павінны несці адказнасць за кіраванне прагледжана логікай, ня паглыбляючыся ў мадэль, дзе фактычны бізнес-логіка. Маючы абалонку віртуальных машын на вяршыні, што не дадае нічога, акрамя складанасці.
дададзена аўтар Farawin, крыніца

<�Код> INotifyPropertyChanged інтэрфейс (INPC) выкарыстоўваецца для Binding .

Такім чынам, у сярэднім выпадку, вы хочаце рэалізаваць яго ў ViewModel .

<�Код> ViewModel выкарыстоўваецца адвязаць Model з вашага Выгляд , таму няма неабходнасці мець INPC ў вашым Model </код >, так як вы не хочаце, прывязак у свой Model .

У большасці выпадкаў, нават для невялікіх уласцівасцяў, вы яшчэ вельмі маленькі ViewModel .

If you want a solid base for MVVM, you are probably going to use some kind of MVVM Framework like caliburn.micro. Using it will give you a ViewModelBase (or here NotifyPropertyChangedBase) so that you do not have to implement those interface members yourself and can just use NotifyOfPropertyChange(() => MyProperty), which is way easier and less error prone.

UPDATE As there seem to be many Windows Forms developers out there, here is an excellent article that will give deeper understanding of what MVVM is about: MSDN Magazine on MVVM

Я звязаны асабліва частка пра DataModel, што гаворка ідзе пра.

15
дададзена
Падручнік, які дапамог мне найбольш ўключалі рамкі пад назвай MicroMVVM, якая была вельмі добра. Гэта дазваляе RaisePropertyChanged (() => Property і ў мяне не было ніякіх праблем да гэтага часу.
дададзена аўтар Jason D, крыніца
Як Caliburn.micro у параўнанні з MVVM Light? Я паспрабаваў трохі, і не клапаціцца пра яго шмат.
дададзена аўтар Jason D, крыніца
Выдатна! Я праверу гэта. Дзякуй за вашу дапамогу.
дададзена аўтар Jason D, крыніца
Я проста паспрабаваў Caliburn.Micro, і я да гэтага часу аддаю перавагу рамкі я выкарыстаў раней.
дададзена аўтар Jason D, крыніца
@DennisE, калі вы выкарыстоўваеце C# 5, то вам не трэба RaisePropertyChanged (() => Уласцівасць) больш. Замест гэтага вы можаце выкарыстоўваць вызначэнне функцыі як несапраўдным RaisePropertyChanged ([CallerName] радкі ИмениСвойства = NULL) , а затым напісаць RaisePropertyChanged (); ў самым інкубатары. Кампілятар аўтаматычна дадасць імя ўласцівасці для вас, прадухіляючы памылкі.
дададзена аўтар Jonathan Allen, крыніца
«Падзел праблем» не з'яўляецца тэхнічным аргумент, гэта тое, што людзі кажуць, калі яны не могуць інакш апраўдаць іх канструкцыю.
дададзена аўтар Jonathan Allen, крыніца
Акрамя таго, няма абсалютна ніякіх прычын, каб пазбегнуць прывязкі да мадэлі дадзеных. Прывязка дадзеных было спецыяльна распрацавана такім чынам, каб вы маглі спакойна слухаць уласнасці змянілі апавяшчэння аб мадэлях, ня уводзячы ўцечкі памяці або іншыя праблемы.
дададзена аўтар Jonathan Allen, крыніца
Гэта жудасная ідэя. Калі што-небудзь непасрэдна змяняе ўласцівасць на мадэлі, то не будзе узняты падзея на выгляд-мадэлі. Гэта азначае, што карыстацкі інтэрфейс і асноўныя дадзеныя больш не будуць быць сінхранізаваныя.
дададзена аўтар Jonathan Allen, крыніца
ТАК просіць мяне пракаментаваць, чаму я downvoted гэты адказ: таму што адказ Джонатан Ален на самай справе ў адпаведнасці з MPP.
дададзена аўтар Thomas, крыніца
@JonathanAllen Вы проста прапусцілі цэнтральную кропку, што MVVM а. Задаць пытанне пра гэта, калі вы не давяраеце мне.
дададзена аўтар Mare Infinitus, крыніца
Гэта добры пачатак выкарыстоўваць рамкі. Caliburn.micro найбольш дапамог мне, так як яна забяспечвае ActionMessages і ў EventAggregator, які з'яўляецца вельмі моцным.
дададзена аўтар Mare Infinitus, крыніца
Магчыма, гэты артыкул дапаможа вам japf.fr/2009/10/а-хуткі тур-з існуючых-MVVM-фреймворков
дададзена аўтар Mare Infinitus, крыніца
Рады, калі я магу дапамагчы. Гэта параўнанне, як уяўляецца, больш актуальным: catel.catenalogic.com/3.2/…
дададзена аўтар Mare Infinitus, крыніца
@JonathanAllen Гэты падзел інтарэсаў. Калі ваша мадэль атрымлівае змянялі, ViewModel ужо павінен ведаць пра гэта. Гэта частка таго, што ViewModel а.
дададзена аўтар Mare Infinitus, крыніца

Будзе абсалютна згодны з Джонатанам Аленам.

Калі ў вас няма нічога, каб дадаць да вашай «View-мадэлі" (каманды, праглядаць спецыфічныя ўласцівасці, якія ўплываюць на ўяўленні і г.д.), то я б пэўна рэалізаваць INotifyPropertyChanged ў мадэлі і выкрываць, што непасрэдна (калі вы можаце - на «мадэль» не можа быць вашым). Мала таго, што вы ў канчатковым выніку паўтараць шмат шаблоннага кода, захоўваючы пры гэтым два сінхронна з'яўляецца абсалютнай болю.

INotifyPropertyChanged не від спецыяльнага інтэрфейсу, ён толькі робіць менавіта тое, што вынікае з назвы - выклікае падзея пры змене ўласцівасці. WinForms, wpf і Silverlight проста так, каб падтрымаць яго для звязвання - Я, вядома, выкарыстаў яго на працягу не-прэзентацыйных мэтаў!

4
дададзена
Для чаго гэта каштуе, я згодны з тым, што вы сказалі @CharlesMager.
дададзена аўтар Jonathan Allen, крыніца
Цьфу няма. Увесь сэнс мець View-мадэлі з'яўляецца тое, што ён дазваляе аддзяліць дадзеныя ад знешніх аперацый па дадзеных. Як толькі вы пачынаеце змешвання ICommands як Ратуйце з нармальнымі ўласцівасцямі, як First/Last Name вы пакінулі шаблон. Ўнутраныя аперацыі, такія як праверка і разліковыя ўласцівасці (напрыклад, FULLNAME) павінны быць у мадэлях і выпрабаванага блоку, але не больш.
дададзена аўтар Jonathan Allen, крыніца
(Цяпер я перачытаў тое, што вы сказалі, я не ўпэўнены, што вы не згаджаючыся з тым, што я толькі што напісаў вышэй - але гэта даволі цяжка прытрымлівацца!)
дададзена аўтар Charles Mager, крыніца
Але навошта мне турбавацца? Калі ў мяне ёсць выгляд, які адлюстроўвае толькі для чытання сеткі даных "пунктаў", было б значна прасцей, каб звязаць гэтую сетку з ObservableCollection чым павінны рабская стварыць <�код > ItemViewModel , каб абгарнуць яго, код для сінхранізацыі змяненняў у ніжэйлеглых элементаў да агню адпаведны PropertyChanged падзеі, код сінхранізацыі асноўны калекцыі ў калекцыю ViewModel і г.д. Было б прасцей проста звязваюцца непасрэдна з мадэллю ў дадзеным выпадку - гэта нават тое, што кажа Prism Guidance: msdn.microsoft.com/en-us/library/…
дададзена аўтар Charles Mager, крыніца
@CharlesMager: Калі ласка, паглядзіце на гэтае пытанне: stackoverflow.com/questions/10437241/… І я пачаў новае пытанне па гэтай тэме тут: stackoverflow.com/questions/16947122/…
дададзена аўтар Mare Infinitus, крыніца
У вас няма ViewModel, каб мець ViewModel. Справа ў тым, што вы можаце лёгка дадаць такія паводзіны, калі вам гэта трэба, таму што вы прынялі рашэнне правільнага дызайну ў першую чаргу. Рэалізацыя добрага дызайну, калі вам гэта трэба вялікі беспарадак, і гэта каштавала значна больш, чым з невялікай ViewModel ў першую чаргу. Вялікім выключэннем з'яўляецца тое, што вы не тыя «што дадаць», не маючы гэтага. Рэкамендую шлях (людзі, якія маюць глыбокія веды аб дызайне, а не тыя, ад InfoQ) з'яўляецца выставіць мадэль у вашай ViewModel тады.
дададзена аўтар Mare Infinitus, крыніца

INotifyPropertyChanged павінны ажыццяўляцца усімі тыпамі, якія спажываюцца на думку (калі, калі ён мае толькі пастаянныя значэння, вядома).

Ці ёсць вярнуць мадэлі (не ViewModels) да выгляду? Калі так, то ён павінен рэалізаваць INotifyPropertyChanged.

1
дададзена
Пастаянныя значэння складаней. З пункту гледжання дызайну API вы не хочаце падвяргаць гэты інтэрфейс і заблытаць спажыўцоў. Але недахопы ў дадзенай архітэктуры звязвання азначаюць, што можа спатрэбіцца, каб зрабіць гэта ў любым выпадку. См @ спасылка HighCore для атрымання дадатковай інфармацыі.
дададзена аўтар Jonathan Allen, крыніца

As a rule of thumb, any object that you will bind to (even if you don't need Two-Way binding and Property Change Notification), must implement INotifyPropertyChanged. This is because failing to do so May cause memory leaks

1
дададзена

Стваральнік MVVM, JohnGossman, гаворыцца ў гэта артыкул блога (згадваны @ Джонатан Ален), што:

<�Р> У простых прыкладах, выгляд дадзеных звязаны непасрэдна да мадэлі.   Часткі мадэлі проста адлюстроўваецца ў акне прагляду з дапамогай аднабаковых дадзеных   звязванне. Іншыя часткі мадэлі можа быць адрэдагаваныя непасрэдна звязванне   кантралюе двухбаковы да дадзеных. Напрыклад, лагічнае значэнне ў мадэлі можа   Дадзеныя быць прывязаныя да CheckBox, або поле радкі ў TextBox. </Р>      <�Р> На практыцы, аднак, толькі невялікая падмноства інтэрфейсу праграмы могуць быць дадзеныя   звязаныя непасрэдна да мадэлі, асабліва калі мадэль з'яўляецца ўжо існуючым   клас або схемы дадзеных, над якімі распрацоўшчык прыкладання не мае   кантроль.   

Я аддаю перавагу прытрымлівацца практыцы, якія ўсё яшчэ ўжываюцца, калі праграма маштабуецца. Калі «На практыцы [...], толькі невялікая частка інтэрфейсу прыкладання можа быць дадзеныя звязаны непасрэдна да мадэлі», гэта, здаецца, не будзе добрая практыка, каб сачыць, як я не збіраюся вырашаць толькі «просты выпадкі »або" невялікае падмноства інтэрфейсу прыкладання ".
Для «простых выпадкаў» Я б нават не выкарыстоўваць MVVM, каб пачаць з.

1
дададзена

While I'm generally in favor of a model implementing INPC the call for INPC in a composite view model is when it exposes inferred properties that are bindable to the view. IMO since INPC is baked into System.dll, a model implementing it may be considered POCO. For collections there is a performance benefit of model based INPC. On a 64 bit platform a wrapper VM would have an 8 factor multiplier on the byte size (load the SOS debugger extension for actual size) of ObservableCollection compared to ObservableCollection.

1
дададзена