как связать событие нажатия кнопки и выбранного элемента, измененного в списке, с моделью представления в mvvm в Silverlight - PullRequest
0 голосов
/ 09 апреля 2010

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

Для выбранного элемента, измененного из списка, я думаю, что также должен быть возможен «обратный вызов», когда модель представления пытается установить для выбранного элемента другое значение?

Я родом из asp.net (mvc), но не могу понять, как это сделать в silverlight.

Ответы [ 3 ]

2 голосов
/ 28 мая 2010

Roboblob предоставляет превосходное пошаговое решение для Silverlight 4. Он строго следует парадигме MVVM.

1 голос
/ 09 апреля 2010

Что касается привязки события нажатия кнопки, я могу порекомендовать MVVM Light Toolkit Лорана Буньона (http://www.galasoft.ch/mvvm/getstarted/)), я приведу небольшой пример, но документация Лорана, скорее всего, лучший способ понимание его структуры.

Ссылка на пару сборок на вашей странице xaml

xmlns:command="clr-namespace:GalaSoft.MvvmLight.Command;assembly=GalaSoft.MvvmLight.Extras"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"

добавить поведение смешивания к кнопке

<Button Content="Press Me">
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="Click">
            <command:EventToCommand Command="{Binding ViewModelEventName}"/>
        </i:EventTrigger>
    </i:Interaction.Triggers>
</Button>

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

public RelayCommand ViewModelEventName { get; protected set; }

...

public PageViewModel()
{
    ViewModelEventName = new RelayCommand(
        () => DoWork()
    );
}

Это поддерживает передачу параметров, проверку того, разрешено ли выполнение и т. Д.

Хотя я не использовал его сам, я думаю, что среда Prism также позволяет вам делать что-то подобное.

1 голос
/ 09 апреля 2010

Я бы никоим образом не связывал или не связывал ВМ с событиями элементов управления в представлении. Вместо этого имейте отдельное событие, которое вызывается представлением в ответ на нажатие кнопки.

[заявление об отказе: этот код сделан прямо из моей головы, а не копируется и вставляется из VS - рассматривайте это как пример !!]

Итак, в псевдокоде вид будет выглядеть так:

private void MyView_Loaded(...) 
{
    MyButton.Click += new EventHandler(MyButton_Click);
}

private void MyButton_Click(...)
{
    //Raise my event:
    OnUserPressedGo();
}

private void OnUserPressedGo()
{
    if (UserPressedTheGoButton != null)
        this.UserPressedTheGoButton(this, EventArgs.Empty);
}

public EventHandler UserPressedTheGoButton;

и виртуальная машина будет иметь такую ​​строку:

MyView.UserPressedTheGoButton += new EventHandler(myHandler);

это может показаться немного скучным, почему бы не сделать это более прямо? Основная причина этого заключается в том, что вы не хотите слишком тесно (если вообще) привязывать свою ВМ к содержимому представления, в противном случае изменение представления становится затруднительным. Наличие такого события, не связанного с пользовательским интерфейсом, как это, означает, что кнопка может меняться в любое время, не затрагивая ВМ - вы можете изменить ее с кнопки на гиперссылку, или тот дизайнер kool kat, которого вы нанимаете, может изменить его на нечто совершенно странное и прикольное, это не не имеет значения.

Теперь поговорим о событии SelectedItemChanged списка. Скорее всего, вы хотите перехватить событие для этого, чтобы вы могли изменить данные, связанные с другим элементом управления в представлении. Если это правильное предположение, тогда продолжайте читать - если я ошибаюсь, прекратите чтение и повторно используйте пример сверху:

Скорее всего, вы сможете избежать необходимости в обработчике для этого события. Если вы привяжете SelectedItem списка к свойству в ВМ:

<ListBox ItemSource={Binding SomeList} SelectedItem={Binding MyListSelectedItem} />

и затем в свойстве MyListSelectedItem виртуальной машины:

public object MyListSelectedItem 
{
    get { return _myListSelectedItem; }
    set 
    {
        bool changed = _myListSelectedItem != value;
        if (changed) 
        {
            _myListSelectedItem = value;
            OnPropertyChanged("MyListSelectedItem");
        }
    }
}

private void OnPropertyChanged(string propertyName) 
{
    if (this.NotifyPropertyChanged != null)
        this.NotifyPropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}

Чтобы получить это NotifyPropertyChanged событие, просто внедрите интерфейс INotifyPropertyChanged на своей виртуальной машине (что вы уже должны были сделать). Это основные вещи в пути ... затем вы обрабатываете обработчик событий NotifyPropertyChanged на самой виртуальной машине:

private void ViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e) 
{
    switch (e.PropertyName)
    {
        case "MyListSelectedItem":
            //at this point i know the value of MyListSelectedItem has changed, so 
            //i can now retrieve its value and use it to modify a secondary 
            //piece of data:
            MySecondaryList = AllAvailableItemsForSecondaryList.Select(p => p.Id == MyListSelectedItem.Id);
            break;
    }
}

Все, что вам сейчас нужно, это чтобы MySecondaryList также уведомил об изменении его значения:

public List<someObject> MySecondaryList 
{
    get { return _mySecondaryList; }
    set 
    {
        bool changed = .......;
        if (changed)
        {
            ... etc ...
            OnNotifyPropertyChanged("MySecondaryList");
        }
    }
}

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

Надеюсь, это имело для вас смысл. С моим кодом я пытаюсь, чтобы ViewModel знал абсолютно нулевой вид, а View только знал минимум о ViewModel (View получает ViewModel как интерфейс, поэтому он может знать только то, что определил интерфейс).

...