Проблеми със свързването на WPF, когато не е зададен DataContext

Успешно създадох редица потребителски контроли с различна функционалност, настройвайки DataContext на всяка контрола на „това“. Винаги съм имал проблеми, когато се опитвах да ги разделя на по-малки „вътрешни“ потребителски контроли, които ще бъдат по-използваеми. Проблемът е следният:

Когато DataContext е настроен на „this“, мога да се свържа със свойствата в кода отзад – не е необходимо те да са DependencyProperties. Когато се свързва с обикновени свойства, изпълнението на програмата въвежда кода отзад, където мога да правя неща като превключване на елементи в ListBox или други неща, които не мога да правя в xaml.

Но когато създам нов „вътрешен“ UserControl, който се хоства в оригиналната контрола и преместя тези свойства във вътрешната контрола, сега трябва да ги надстроя, за да бъдат DependencyProperties, така че да мога да се обвържа с тях от оригиналната контрола. Когато се свързва с DependencyProperties, изпълнението на програмата никога не въвежда кода отзад и за мен ТОВА е проблемът. Между другото, аз не задавам DataContext във вътрешната контрола, а вместо това задавам свойството Name на основния елемент и използвам синтаксиса ElementName=UserControlName в обвързването на свойствата на вътрешната контрола.

Наясно съм, че мога да добавя ValidateValueCallbackHandler към DependencyProperty, за да получа достъп до кода отзад, когато обвързаната стойност се променя, но това трябва да е статичен метод, така че нямам достъп до нестатични членове (т.е. целия ми клас) .

Един пример е, че имам контрола DurationPicker, която показва TimeSegments обекти в ListBoxes. Обектите TimeSegments са основно ObservableCollection от обекти TimeSegment и TimeSegment има свойства StartDate, EndDate и Duration. Имам свойство MinutesPerSegment в контролата DurationPicker, което беше обвързано със стойности от ComboBox. Работи идеално. Бих могъл да променя стойността на ComboBox и кодът отзад ще постави правилния брой TimeSegment обекти с правилните нови стойности в ListBox.

След това създадох вътрешната контрола, която съдържа обект TimeSegments и ListBox, за да го покажа. Сега свойството MinutesPerSegment трябваше да се превърне в DependencyProperty, за да мога да се обвържа с него от външния контрол и изпълнението на програмата никога не въвежда кода отзад, така че сега не мога да променя броя на TimeSegmentobjects в колекцията.

Още нещо, което трябва да отбележим. Мога успешно да се свържа с DependencyProperties на вътрешния контрол от външния контрол - мога да видя промените, показващи се в потребителския интерфейс. Проблемът е просто, че имам нужда от изпълнение на програмата, за да въведа кода зад нея, когато определени обвързани свойства се актуализират.

Какъв е правилният начин да направите това? Много благодаря.

РЕДАКТИРАНЕ - В примера, ако създам обектите TimeSegments във външния контрол и ги обвържа с вътрешния контрол, тогава той все още работи. Това е така, защото свойството MinutesPerSegment във външната контрола е обикновено свойство... Искам обаче всеки обект TimeSegments да се обработва в собствената му вътрешна контрола TimeSegmentsRow... и така проблемът.


person Sheridan    schedule 28.11.2010    source източник


Отговори (1)


Първо, не е необходимо да задавате DataContext на this само за да активирате обвързването към свойствата на вашата персонализирана контрола. Това е лоша идея, в случай че някой реши да зададе друг контекст на данни за ваш контрол. Вместо това можете да използвате относително обвързване.

{Binding Path=PathToProperty, 
         RelativeSource={RelativeSource AncestorType=
                         {x:Type namespaceAlias:typeOfYourControl}}}

и декларирайте псевдоним на пространство от имена за вашата персонализирана контрола в xaml

xmlns:namespaceAlias="clr-namespace:YourLibraryNamespace;assembly=YourLibraryAssemblyName"

Второ, wpf няма да използва вашият инструмент за получаване и настройка на свойства за достъп до вашите свойства на зависимост, ето защо не трябва да има допълнителна логика извън GetValue и SetValue. Можете да посочите PropertyChangedCallback, когато регистрирате своя собственост, за да добавите някои логика при промяна на собствеността.

person alpha-mouse    schedule 28.11.2010
comment
Благодаря за съвета относно DataContext=this, но това не е ли същото като именуване на основния елемент UserControl и използване на ElementName? Освен това делегатът PropertyChangedCallback е статичен като ValidateValueCallback, така че не мога да получа достъп до членовете на класа от там. Искате да кажете, че няма начин да се извика нестатичен метод, когато несвързано свързано с данни свойство се промени? - person Sheridan; 28.11.2010
comment
Статичният метод PropertyChangedCallback получава DependencyObject в първия параметър. Този DependencyObject е вашият контрол, така че можете да го прехвърлите към вашия тип контрол и да използвате всички членове. - person alpha-mouse; 28.11.2010
comment
Точно това преследвах! Много благодаря! :) - person Sheridan; 29.11.2010