2

我有一个用户控件“A”,它有另一个用户控件“B”作为它的子控件。用例场景是,当用户单击“A”上的按钮时,它应该请求“B”处理一些信息(通常与“B”的状态有关)并获得结果,然后将其用于一些计算在一个'。

现在,我正在使用 MVVM 模式。“A”的视图模型对 A 或 B 的 UI 没有任何引用。我正在寻找这个:当用户单击“A”的 UI 上的按钮时,我需要在“B”中调用命令',通过将“A”的视图模型中的委托作为参数传递给该命令。这样,当'B'中的命令处理信息时,它可以调用从'A'传来的回调函数。

现在,委托是无参数的。一旦用户控件“B”中的命令处理了一些信息,它就会更新其状态。此状态是一个依赖属性,它将绑定到“A”的视图模型中的属性。

有没有办法实现这样的目标?

我目前有一个可行的解决方案。但我想即兴编写代码并使其变得更好。这是我目前对这个问题的临时解决方法:

当用户单击“A”中的按钮时,我在“A”(xaml.cs)中有一个事件处理程序。在事件处理程序中,因为我有'B'的引用,我正在检查'B'中的命令是否可以执行,然后调用它。然后,我检查命令(在'A'的视图模型中)是否可以执行,然后调用它。

如果我的问题描述性不够,这里有一个代码示例来支持它:

“A”的 XAML:

<bNameSpace:B x:Name="BObject" DepenPropertyInB="{Binding PropInA, Mode=OneWayToSource}"/>
....
<telerik:RadButton Content="Process" HorizontalAlignment="Right" Height="30" Width="80" Grid.Column="2" Click="ProcessButton_Click" />

A的XAML.cs:

private void ProcessButton_Click(object sender, RoutedEventArgs e)
{
    if (BObject.StateDataRequestedCommand.CanExecute(""))
        BObject.StateDataRequestedCommand.Execute("");

    if(ViewModel.ProcessInfoRequestedCommand.CanExecute(""))
        ViewModel.ProcessInfoRequestedCommand.Execute("");
}

A的视图模型:

private void OnProcessInfoRequestedCommand(string anyValue)
{
    // read the value of PropInA and do some processing
}

B的视图模型:

private void OnStateDataRequestedCommand(string anyValue)
{
    // Bases on B's state do some calc and update DepenPropertyInB
}
4

2 回答 2

2

稍后我会回来添加更多细节,但这基本上是我认为需要发生的事情。

点击应该有一个DelegateCommand类型实现,其中包含对 A 和 B 的视图模型的引用。您需要某种“导体”类来实例化视图模型,并且可以将适当的引用传递给命令对象。


因此,显然该命令属于 A 的视图模型,但是,它需要对 B 的引用。因此,请记住这一点来设置命令类:

public MyCommand : ICommand
{
    private readonly ViewModelA _a, ViewModelB _b;

    public MyCommand(ViewModelA a, ViewModelB b)
    {
        _a = a;
        _b = b;
    }

    public bool CanExecute(object arg)
    {
        // can-execute logic here
    }

    public void Execute(object arg)
    {
        _b.StateDataRequestedCommand.Execute("");
        _a.ProcessInfoRequestedCommand.Execute("");
    }
}

现在,但是将MyCommand的一个实例放入 A 的视图模型中......

public MyCommand StateRequestedCommand { get; set; }

并像往常一样绑定它...

<telerik:RadButton Command="{Binding StateRequestedCommand}" />

现在,挑战是以某种方式在 A 的视图模型中实例化这个类。我通常使用 NInject 将外部依赖项注入到类中,但是有不同的方法可以做到这一点。无论哪种方式,它都必须发生在比 ViewModelA 本身更高的级别,因为它没有对 ViewModelB 的引用。这可能在 App_Startup 逻辑中,或者在 IoC(例如,NInject)绑定中,或者在视图模型“定位器”中,如果你正在使用的话。

于 2012-09-10T01:04:52.650 回答
2

每个命令都需要 CommandParameter 并且您使用它但发送“”而不是实际参数。参数可以是任何类型,因为它被取消为对象。因此,您可以将任何对象作为参数发送给任何命令。

class CommandA : ICommand
{
  void Execute(object param)
  {
    var commandB = param as CommandB;
    if(commandB != null)
    {
      commandB.Execute((int a) => {
          // continue your code here
        });
    }
  }

  bool CanExecute(object param)
  {
    return param is CommandB;
  }
}

class CommandB : ICommand
{
  void Execute(object param)
  {
    var action = param as Action<int>;
    if(action != null)
    {
      action(10);
    }
  }
}

class MVA
{
  CommandA CommandA{get;}
  CommandB CommandB{get;}
}

XAML:

<Control x:Name="A" Command="{Binding CommandA}" CommandParameter="{Binding Command, ElementName="B"}">
  <Control x:Name="B" Command="{Binding CommandB} />
</Control>
于 2012-09-10T01:57:12.523 回答