【问题标题】:RelayCommands get executed multiple timesRelayCommands 被多次执行
【发布时间】:2013-07-09 15:05:40
【问题描述】:

我在 Windows Phone 7(使用 wp8 SDK 和 VS Ultimate 2012 的 7.1)应用程序中使用 MVVM Light,该应用程序从 Web 服务应用程序异步检索数据。我在每个执行异步方法的页面上使用 RelayCommands 来获取数据,然后导航到下一页。例如,在我的一个 ViewModel 中,我声明了以下 ICommand :

public ICommand ShowTreatmentDetailsCommand { get; set; }

然后,在 VM 的构造函数中,我以这种方式分配它:

ShowTreatmentDetailsCommand = new RelayCommand(ShowTreatmentDetails);

这是该命令调用的方法:

private async void ShowTreatmentDetails()
{
    try
    {
        Treatment refreshedTreatment = await treatmentService.LoadSingle(SelectedTreatment.id, LoggedUser.logon, LoggedUser.pwHash);

        if (refreshedTreatment != null)
        {
            DrugGroup anaestGroup = null;
            DrugGroup surgGroup = null;

            IEnumerable<DrugGroup> groups = await drugGroupService.Load(
                refreshedTreatment.id,
                LoggedUser.logon,
                LoggedUser.pwHash);

            anaestGroup = groups
                .Where(g => g.type == DrugType.Anaesthetic)
                .SingleOrDefault<DrugGroup>();

            surgGroup = groups
                .Where(g => g.type == DrugType.Surgical)
                .SingleOrDefault<DrugGroup>();

            Dictionary<string, object> parameters = new Dictionary<string, object>();
            parameters.Add(Keys.AnaestDrugGroup, anaestGroup);
            parameters.Add(Keys.SurgDrugGroup, surgGroup);
            parameters.Add(Keys.SelectedTreatment, refreshedTreatment);

            Messenger.Default.Send(parameters);
        }
        else
        {
            // Display error message
        }

        RefreshData();
    }
    catch (NullReferenceException) { }
}

当使用 EventTrigger 和 EventToCommand 类从 ListBox 中选择项目时,从 View 的 xaml 代码调用此命令(但与按钮相关的命令问题仍然存在。以防万一,这是我的 ListBox 元素:

<ListBox x:Name="lbxTreatmentList"
         ItemsSource="{Binding Treatments}"
         SelectedItem="{Binding SelectedTreatment, Mode=TwoWay}">
    <int:Interaction.Triggers>
        <int:EventTrigger EventName="SelectionChanged">
            <com:EventToCommand Command="{Binding ShowTreatmentDetailsCommand}"
                                PassEventArgsToCommand="True" />
        </int:EventTrigger>
    </int:Interaction.Triggers>
    <ListBox.ItemTemplate>
        <DataTemplate>
            <custom:TreatmentListItem PatientName="{Binding patient}"
                                      OpeDescription="{Binding description}"
                                      StartedAt="{Binding startedAt}" />
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

还有一个带有按钮的例子:

<Button Grid.Row="2"
    HorizontalAlignment="Center"
    Foreground="{StaticResource BeldicoBlue}"
    BorderBrush="{StaticResource BeldicoBlue}"
    Margin="0,12,0,0"
    Padding="24,12"
    Command="{Binding ValidateCommand}">
    <TextBlock Text="Validate this treatment" FontWeight="ExtraBold" />
</Button>

问题在于,每次触发命令时,相关方法的执行次数都会增加。 IE。 :第一次通话时一次,然后两次,然后是三、四、五……次。由于该方法中有一个异步服务调用,因此很快就会占用带宽和时间。

我绝对不明白这种行为背后的原因,有人可以帮忙吗?

【问题讨论】:

  • 为什么要定义public ICommand ShowTreatmentDetailsCommand,然后是ShowTreatmentDetailsCommand = new RelayCommand。将 ICommand 替换为 RelayCommand。可能不会解决你的问题,但如果我做对了,我不会。您单击按钮,方法将被调用一次。再次点击按钮,方法会调用TWICE,对吗?
  • 您是否查看了每次执行的堆栈跟踪以找出触发执行的原因?
  • @Rudi :我将我的命令声明为 ICommands,因为 ICommand 是在 .NET 框架中构建的,而不是 RelayCommands,后者继承了 ICommand 接口但带有 MVVM Light 包。将命令声明为 RelayCommands 而不是 ICommands 没有区别,但我只是习惯性地使用 ICommand。是的,你的问题是对的。

标签: .net windows-phone-7.1 mvvm-light async-await relaycommand


【解决方案1】:

这里有几种可能的情况:

  1. 您正在创建多个附加到页面的视图模型实例,每个实例都在执行命令。

    或者,更有可能:

  2. 您没有完全理解SelectionChanged 事件的工作原理。选择更改时,可以多次触发此事件。如果已经有一个选定的项目,则在删除该项目时将触发 changed 事件,然后在添加新的选定项目时再次触发。
    如果您直接使用事件处理程序,则可以直接查询SelectionChangedEventArgs 以确定触发事件的原因。您的代码忽略了这些参数,即使您的 xaml 说您正在传递它们。

如果您更改您的操作以使其支持这些参数,您可以在此处添加检查。
例如

ShowTreatmentDetailsCommand =
     new RelayCommand<SelectionChangedEventArgs>(ShowTreatmentDetails);

private async void ShowTreatmentDetails(SelectionChangedEventArgs args)
{
    if (args.AddedItems.Count >= 1)
    {
        // your code
    }
}

【讨论】:

  • 我也想到了 Nr 1,因为这也发生在我身上,但是根据他的代码,我(我们)看不到他在何时何地调用/创建 ViewModel。很好地考虑了 SelectionChangedEvent,但他说当他点击一个按钮时也会发生这种情况,所以我认为它更有可能是数字 1。
  • 这对我来说实际上是第二个解决方案。我不知道 SelectionChanged 事件在每次选择时都会被触发多次,感谢分享提示。顺便说一句,在我的情况下,检查 args.AddedItems.Count 是否严格等于 1 而不是“更小或等于”效果更好。我曾经在一些按钮上遇到过类似的错误,但是当我重构我的 View 层时,它似乎已经得到修复,使它在每次导航时系统地调用 CleanViewModel 方法。
  • 恕我直言 SelectionChangedEventArgs in Viewmodel 将使该方法与视图耦合,因此如果不模拟 SelectionChangedEventsArgs 就无法测试它有没有更优雅的方法?
猜你喜欢
  • 2019-01-30
  • 1970-01-01
  • 1970-01-01
  • 2018-04-11
  • 2015-04-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多