Silverlight как да зададете контекста на данни на елемент от списъчно поле към основния модел на изглед за изгледа, в който се намира

В моя проект имам Listbox, който използва шаблон за данни. В този шаблон за данни имам бутон. Когато списъкът генерира резултати, източникът на елемент за този списък е зададен на някаква колекция от свойства, нека го наречем Резултати[0].

Проблемът, който имам, е, че когато щракна върху бутона за извикване на метод от модела на изгледа, методът не може да бъде намерен, защото извикването търси контекста на списъка, а не основния изглед. Използвам набор от инструменти SimpleMVVM, който използва локатор, подобен на инструментариума MVVMLight.

Един подход, който предприех, беше изрично да задам контекста на данните на бутона, като декларирам модела на изглед в ресурсите за потребителски контрол и го задам статично.

<UserControl.Resources>
    <formatter:HighlightConverter x:Key="FormatConverter" />
    <vml:SearchViewModel x:Key="vm" />
</UserControl.Resources>

и след това бутонът съдържа

<HyperlinkButton HorizontalAlignment="Left"
    Click="Button_Click"
    Content="{Binding Type}"
    Style="{StaticResource ListBoxtTitleHyperlink}">
 <i:Interaction.Triggers>
     <i:EventTrigger EventName="Click">
        <ei:CallMethodAction MethodName="GetDetailID" TargetObject="{Binding Source={StaticResource vm}}" />
     </i:EventTrigger>
 </i:Interaction.Triggers>
</HyperlinkButton>

Това работи във факта, че вече мога да получа достъп до метода, но той създава нов модел на изглед, вместо да ми позволи достъп до основния изгледмодел на изгледа. Следователно губя всички свойства, които може да съм имал в предишния модел на изглед, така че не мога да ги предам на метода като параметри.

Моята реализация може да е изключена тук. Така че съм отворен за предложения. В сценарии като този кой е най-добрият подход да имате бутон в шаблон с данни в списъчно поле, който да извиква метод от модела на изгледа и да предава параметрите на метода, които са извлечени от избрания елемент от списъчно поле?

За да видите пълното внедряване на кода, можете да изтеглите примерния проект от Папка на SkyDrive

Актуализация Започвам награда за този въпрос, тъй като ме озадачи. Чувствайте се свободни да изтеглите примерния проект за справка. За по-голяма яснота намерението на този въпрос е да научите как да постигнете следното 1. Изберете ред от списъчно поле 2. Събитието selectionchanged ще зададе свойство на текстовата стойност, показана в потребителския интерфейс (двупосочно обвързване на RecordID с помощта на Inotify 3. Щракнете върху бутона в шаблона на елемента и извикайте метода, съхранен в ViewModel, като използвате тригери за взаимодействие и показване в кутия за съобщения стойността на свойството RecordID.

Стъпки I и 2 са направени. Там, където съм заседнал, е да разбера как да накарам бутона, който е част от шаблона на елемент от списъчната кутия, да намери основния модел на изглед и да извика метода на тази виртуална машина, без да инстанцира нов ViewModel, който би нулирал всички съхранени преди това свойства.

Благодаря предварително


person rlcrews    schedule 12.08.2011    source източник


Отговори (2)


Добавете ресурса програмно. Свързването на StaticResource може да се оплаква по време на проектиране, но по време на изпълнение трябва просто да работи.

UserControl има свойство Resources, което връща препратка към ResourceDictionary. Можете да добавите ViewModel към това и ефектът ще бъде същият като вашия Xaml пример, с изключение на това, че можете да използвате повторно съществуващия ViewModel.

Ако приемем, че вашата MVVM рамка вече е попълнила DataContext на UserControl с ViewModel, тогава можете да използвате C# код, подобен на следния, за да настроите ресурса.

this.Resources.Add("vm", this.DataContext);

Ако DataContext вече е зададен в конструктора на UserControl, тогава той може да отиде там. В противен случай ще трябва да намерите кука, която се извиква по-късно в жизнения цикъл на UserControl.

Редактиране: След като разгледахте кода си. Бих предложил следните модификации.

  1. Не задавайте нито DataContext, нито "vm" StaticResource в XAML.
  2. Използвайте следния код като конструктор на класа TemplateView.

Код:

public TemplateView()
{
    var templateViewModel = new TemplateViewModel();
    this.DataContext = templateViewModel;
    this.Resources.Add("vm", templateViewModel);
    InitializeComponent();
}

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

person Scott Munro    schedule 15.08.2011
comment
Благодаря Скот. Ако разбирам правилно сте добавили ресурса (контекст на данни) в конструктора на потребителски контрол за списъка или за целия контрол? Псевдокод: this.uc.Resources[vm]; ? - person rlcrews; 16.08.2011
comment
Благодаря, Скот, опитах този подход, но клиентът не компилира, защото контекстът изглеждаше зададен два пъти. (От изгледа и в рамките на кода отзад) Качих примерен проект с кода на място, ако вие (или някой друг) иска да погледне. skydrive.live.com/ - person rlcrews; 16.08.2011
comment
Изтеглих проекта, но установих, че се компилира добре. Не намерих кода, който сте включили по-горе. Ако все още имате версията, в която сте имали проблеми с DataContext, който е зададен два пъти, тогава ще се радвам да я разгледам. - person Scott Munro; 17.08.2011
comment
Съжалявам за това Скот. Актуализирах проекта и го публикувах отново. Също така добавих коментари към файла TemplateViewModel.cs, очертаващи въпросната област. Имената на методите са различни, но концепцията е същата. Благодаря отново за отделеното време. - person rlcrews; 17.08.2011
comment
@randyc: Актуализирах отговора си с някакъв код, който използвах, за да стартирам вашето решение. - person Scott Munro; 18.08.2011
comment
Скот, благодаря много за отделеното време и обяснението относно настройката на конструктора. Това решение работи. - person rlcrews; 18.08.2011
comment
Радвам се, че мога да помогна. Обърнете внимание, че опростих кода само преди няколко минути - разбрах, че не е задължително да имате нужда от ViewModelLocator. - person Scott Munro; 18.08.2011

Аз съм разработчик на WPF и не знам със сигурност дали това ще работи в Silverlight, но обикновено променям обвързването на вашия целеви обект на нещо като

 <ei:CallMethodAction MethodName="GetDetailID" TargetObject="{Binding Path=DataContext, RelativeSource={RelativeSource AncestorType=ListBox, Mode=FindAncestor}}"/> 

В действителност, преглеждане на дървото, докато намери първия предшественик ListBox, и след това проверка на неговото свойство DataContext, което, ако прочетох въпроса ви правилно, е вашият ViewModel.

person Mark Green    schedule 16.08.2011
comment
Благодаря, Марк, напълно съм съгласен. Проблемът със Silverlight е, че той няма достъп до режима FindAncestor в Silvlerlight. Той ви позволява само да посочите себе си или шаблонен обект - person rlcrews; 16.08.2011