对ComboBox选择的操作已更改

时间:2017-01-10 14:40:07

标签: c# wpf mvvm visual-studio-2015 combobox

我使用MVVM将ComboBox绑定到ViewModel,我对重度操作和选择更改几乎没有疑问。

我希望在更改所选项目时触发某些操作,我的初始方法是将逻辑放在所选项目绑定到的字段的setter中。

所以我的第一个问题是,这是一种好的做法还是有更好的方法?

这些行为的时间和资源可能非常昂贵(需要通过网络服务检索数据)而且我不希望用户界面冻结,所以最近我开始发送消息设置在视图的代码隐藏中接收并以异步方式调用ViewModel命令。

我只是在浪费时间或者这有什么意义吗?

问题在于,当我调试UI时,无论如何都会冻结(在发布时它没有发生)。在这里和那里阅读我已经知道它可能与调试器有关,任何人都可以在VS 2015上确认这种行为吗?

其他信息

根据要求,我提供了一些例子。这是我的第一个方法:

(XAML)
<ComboBox SelectedItem="{Binding SelectedField}"/>

(ViewModel)

public class ViewModel  
{
    private MyObject _selectedField = null;
    public MyObject SelectedField
    {
        get
        {
            return _selectedField;
        }
        set
        {
            if(_selectedField != value)
            {
                // Expensive action
                _selectedField = value;
                RaisePropertyChanged(() => SelectedField);
            }
        }
    }
}

昂贵的行动会引起一些网络服务电话并且可能需要很长时间,这种设计是好还是有更好的方法来实现这一目标?

我的第二种方法是通过消息,如下例所示:
(ViewModel)

public class ViewModel  
{
    private MyObject _selectedField = null;
    public MyObject SelectedField
    {
        get
        {
            return _selectedField;
        }
        set
        {
            if(_selectedField != value)
            {
                Messenger.Default.Send(new DoStuffMessage());
                _selectedField = value;
                RaisePropertyChanged(() => SelectedField);
            }
        }
    }    
    private RelayCommand _doStuffCommand = null;
    public ICommand DoStuffCommand
    {
        get
        {
            if (_doStuffCommand == null)
                _doStuffCommand = new RelayCommand(async () => await DoStuff());
            return _doStuffCommand;
        }
    }

    private async Task DoStuff()
    {
        // Expensive action
    }
}

(适用代码隐藏)

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();

        Messenger.Default.Register<DoStuffMessage>(this, DoStuffMessage_Handler);
    }

    private void DoStuffMessage_Handler(DoStuffMessage msg)
    {
        (DataContext as ViewModel).DoStuffCommand.Execute(null);
    }

}

这种方法更好还是坏而无用?

2 个答案:

答案 0 :(得分:2)

对于MVVM,我更喜欢使用RelayCommands将XAML中的EventTrigger绑定到viewmodel中的ICommand。我认为这创造了最佳的代码分离,并且比在我的安装人员中添加大量逻辑更清晰,在故障排除期间可能会忽略它。以下是该过程的概述:https://msdn.microsoft.com/en-us/magazine/dn237302.aspx

这是连接一个按钮并传入一个参数,所以很明显你需要根据你的用例修改它,但它会显示基本技术。在XAML中:

<Button Content="Click Me">
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="Click">
            <Custom:EventToCommand Command="{Binding MyCommand}" CommandParameter="foo"/>
        </i:EventTrigger>
    </i:Interaction.Triggers>
</Button>

在你的虚拟机中:

public static ICommand MyCommand { get; set; } // declare an ICommand - bind to this!

public MainViewModel(IDataService dataService)
{
    // associate your ICommand with a method.  If you don't use a parameter, you don't need the lambda expression here.
    MyCommand = new RelayCommand<string>((paramater) => MyCommandMethod(parameter));
}

public void MyCommandMethod(string parameter)
{
    Debug.WriteLine("This is the code I want to run in my VM. The parameter is " + parameter);
}

我将[free] MVVMLight工具包用于我的应用程序,这是由编写我链接的文章的人编写的,但是很多内容也被编入.Net中。使用Expression Blend可以在设计时更容易地连接这些东西。

答案 1 :(得分:1)

只要它是异步的,你就可以在setter中做任何你喜欢的事。

private string _test;
    public string Test
    {
        get { return _test; }
        set
        {
           Task.Run(() =>
           {
               //do stuff
           });
            _test = value;
        }
    }

如果您不想在setter中放置逻辑,因为例如违反了单一责任原则,您应该使用交互来捕获SelectionChange事件并在VM中调用应该调用异步方法的命令。

此处您有一个使用互动的示例:cute link

就是这样!