【问题标题】:Action on ComboBox selection changed对组合框选择的操作已更改
【发布时间】:2017-05-25 02:18:51
【问题描述】:

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

我想在选中项发生变化时触发一些动作,我最初的做法是把逻辑放在选中项绑定的字段的setter中。

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

这些操作在时间和资源上可能非常昂贵(需要通过网络服务检索数据)并且我不希望 UI 冻结,所以最近我开始从接收到的集合中发送消息在视图的代码隐藏中并异步调用 ViewModel 命令。

我只是在浪费时间还是有任何意义?

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

附加信息

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

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

(视图模型)

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

昂贵的操作会调用一些 Web 服务并且可能需要很长时间,这种设计是好的还是有更好的方法来实现这一点?

我的第二种方法是通过消息,如下例所示:
(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);
    }

}

这种方法更好还是只是不好和无用?

【问题讨论】:

  • 你的问题太宽泛了。您是否有一些可以发布的代码以及有关该代码的具体问题?

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


【解决方案1】:

对于 MVVM,我更喜欢使用 RelayCommands 将 XAML 中的 EventTrigger 绑定到视图模型中的 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);
}

我在我的应用程序中使用 [免费] MVVMLight 工具包,该工具包是由撰写我链接到的文章的人编写的,但其中很多内容也包含在 .Net 中。使用 Expression Blend 可以让您在设计时更轻松地连接这些东西。

【讨论】:

  • 这是否也适用于 SelectionChanged 事件?
  • 没关系,@Dragosh Stoica 回答了这个问题,但你的答案是坦克。
  • 我没有为您正在做的事情准备好代码示例,但我认为这种方法可以对您的应用程序进行最小的更改。
【解决方案2】:

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

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

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

这里有一个使用交互的示例:cute link

就是这样!

【讨论】:

  • 我担心这更像是一个性能问题,但如果它只是违反原则,那没什么大不了的。谢谢你的回答。
  • 这是有效的,请注意,只要有任何更改测试(不仅仅是 UI 交互的更改),它都会运行。例如,当您加载视图模型时,此代码将在测试时立即运行设置为其初始值。这可能会产生意想不到的后果。
猜你喜欢
  • 2015-10-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-23
  • 2017-03-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多