如何将按钮的单击事件和列表框的selecteditemchanged绑定到Silverlight中的mvvm中的viewmodel

时间:2010-04-09 10:05:16

标签: silverlight silverlight-3.0

我刚开始使用Silverlight中的mvvm模型。 在步骤1中,我得到了一个绑定到我的viewmodel的列表框,但现在我想在按钮中传播一个单击,并将列表框的selecteditemchanged传回到viewmodel。 我想我必须以某种方式将按钮的click事件和listbox的selecteditemchanged绑定到我的viewmodel中的2个方法?

对于列表框的selecteditemchanged,我认为当viewmodel尝试将selecteditem设置为另一个值时,还必须有“返回调用”吗?

我来自asp.net(mvc)背景,但无法弄清楚如何在silverlight中做到这一点。

3 个答案:

答案 0 :(得分:2)

Roboblob为Silverlight 4提供excellent step-by-step solution。它严格遵循MVVM范例。

答案 1 :(得分:1)

我不会以任何方式将VM绑定或绑定到View中的控件事件。相反,有一个单独的事件由View引发以响应按钮单击。

[免责声明:此代码全部直接来自我的头脑,而不是复制&从VS粘贴 - 以此为例!!]

因此在伪代码中,View将如下所示:

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;

并且VM会有这样一行:

MyView.UserPressedTheGoButton += new EventHandler(myHandler);
这可能看起来有点啰嗦,为什么不直接这样做呢?主要原因是您不希望将VM绑定得太紧(如果有的话)到View的内容,否则很难更改View。像这样的一个UI不可知事件意味着按钮可以随时改变而不影响VM - 您可以将其从按钮更改为超链接,或者您雇用的kool kat设计师可能将其更改为完全奇怪和时髦的东西,它不会无所谓。

现在,我们来谈谈列表框的 SelectedItemChanged 事件。您可能希望拦截此事件,以便您可以修改绑定到视图中另一个控件的数据。如果这是一个正确的假设,那么请继续阅读 - 如果我错了,那么请停止阅读并重复使用上面的例子:)

可能的情况是,您可能无需处理该事件的处理程序。如果将列表框的 SelectedItem 绑定到VM中的属性:

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

然后在VM的 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事件,只需在VM上实现INotifyPropertyChanged接口(您应该已经完成​​)。这是基本的东西......你接下来的是VM本身的 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中获取UI事件的任何处理程序,你保持了View和ViewModel之间的抽象。

我希望这对你有所帮助。使用我的代码,我尝试让ViewModel对View一无所知,而View只知道ViewModel的最低限度(View接收ViewModel作为接口,因此它只能知道接口指定了什么)。

答案 2 :(得分:1)

关于绑定按钮点击事件我可以推荐Laurent Bugnion的MVVM Light Toolkit(http://www.galasoft.ch/mvvm/getstarted/)作为解决这个问题的方法,我将提供一个小例子,但Laurent的文档很可能是一个更好的方法。了解他的框架。

在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>

并在viewmodel中创建事件,单击该按钮时将调用该事件

public RelayCommand ViewModelEventName { get; protected set; }

...

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

这支持传递参数,检查是否允许执行等。

虽然我自己没有使用它,但我认为Prism框架也允许你做类似的事情。