这份原稿.如何将操作绑定到嵌套的ViewModel方法



我有一个WPF应用程序,由Caliburn提供支持。微观的,视图模型优先的方法。有一个命令栏类型的控件,它的CommandBarView。xaml和bound CommandBarViewModel。命令栏虚拟机拥有许多嵌套的虚拟机,每个按钮控件一个,所有显示一个共同的界面和具有共同的行为。命令栏VM公开它们,以便可以从视图绑定它们:

public interface IWarningButtonViewModel
{
    bool IsVisible { get; }
    bool CanShowWarning { get; }
    void ShowWarning();
}
public class CommandBarViewModel : PropertyChangedBase
{
    public IWarningButtonViewModel UserNotFoundWarning { get; private set; }
    public IWarningButtonViewModel NetworkProblemWarning { get; private set; }
    // ... initialization omitted for simplicity
}

这是一个试探性的XAML的一点CommandBarView:

<Button x:Name="UserNotFoundWarning_ShowWarning"
        IsEnabled="{Binding UserNotFoundWarning.CanShowWarning}">
  ... 
  <DataTrigger Binding="{Binding UserNotFoundWarning.IsVisible}" Value="True">
  ...
</Button>

通过这种方式,我能够成功地绑定两个属性(CanShowWarningIsVisible),但是我不能将按钮命令/动作绑定到ShowWarning方法。

我尝试了深度属性绑定,它再次适用于属性,但不适用于动作。
我还尝试了cal:Model.Bindcal:Message.Attach的混合:

<Button cal:Model.Bind="{Binding UserNotFoundWarning}" 
        cal:Message.Attach="[Event Click] = [Action ShowWarning]"
        IsEnabled="{Binding CanShowWarning}">
  ... 
  <DataTrigger Binding="{Binding IsVisible}" Value="True">
  ...
</Button>

这似乎在运行时工作,但调用:Model。Bind使VS设计器完全无法使用,UI控件无法显示。

我已经搜索了很多,但我找不到一个真正的解决方案,让我也与设计师工作。我觉得很奇怪,我只能找到深度绑定属性的例子,而不是操作。

你知道怎么解决这个问题吗?

这是我的解决方案:

private static void EnableNestedViewModelActionBinding()
{
    var baseGetTargetMethod = ActionMessage.GetTargetMethod;
    ActionMessage.GetTargetMethod = (message, target) =>
    {
        var methodName = GetRealMethodName(message.MethodName, ref target);
        if (methodName == null)
            return null;
        var fakeMessage = new ActionMessage { MethodName = methodName };
        foreach (var p in message.Parameters)
            fakeMessage.Parameters.Add(p);
        return baseGetTargetMethod(fakeMessage, target);
    };
    var baseSetMethodBinding = ActionMessage.SetMethodBinding;
    ActionMessage.SetMethodBinding = context =>
    {
        baseSetMethodBinding(context);
        var target = context.Target;
        if (target != null)
        {
            GetRealMethodName(context.Message.MethodName, ref target);
            context.Target = target;
        }
    };
}
private static string GetRealMethodName(string methodName, ref object target)
{
    var parts = methodName.Split('.');
    var model = target;
    foreach (var propName in parts.Take(parts.Length - 1))
    {
        if (model == null)
            return null;
        var prop = model.GetType().GetPropertyCaseInsensitive(propName);
        if (prop == null || !prop.CanRead)
            return null;
        model = prop.GetValue(model);
    }
    target = model;
    return parts.Last();
}

调用EnableNestedViewModelActionBinding()一次从你的引导程序,它将允许你绑定动作嵌套模型的方法使用通常的点符号。例如

cal:Message.Attach="[Event Click] = [Action UserNotFoundWarning.ShowWarning]"

Edit:请注意,如果您在运行时更改嵌套的ViewModel实例,这将不起作用。例如,如果你在绑定发生后将UserNotFoundWarning分配给新的东西- Caliburn仍然会调用先前实例的操作。

最新更新