Caliburn.Micro - 在BindableCollection中更新项目字段时调用方法保护

时间:2017-07-05 02:52:32

标签: c# wpf xaml caliburn.micro

我有一个属性BindableCollection<Cat> { get; private set; },其中有许多Cat个对象绑定到我的WPF XAML中的ItemsControl。

然后我将以下代码附加到此ItemsControl中的按钮。

XAML代码段

<Button Content="Pat Cat" cal:Message.Attach="PatCat($dataContext)" />

在ViewModel中......

BindableCollection<Cat> { get; private set; }

public bool CanPatCat(Cat cat)
{
   return cat.Pattable && cat.Alive;
}

public void PatCat(Cat cat)
{
    // pat the cat
    cat.Alive = false;
}

鉴于这是一个方法保护而不是属性,如何通知UI以便为BindableCollection中的每个Cat评估CanPat方法,因为一旦Cat被拍了,保护方法现在将返回false?

2 个答案:

答案 0 :(得分:1)

虽然对于属性存在特定且复杂的UI感知机制(我在谈论Binding),但对于方法,情况完全不同。 在我的拙见中使用这种情况下的事件是不合适的,所以我想到了一个基于扩展Caliburn Micro框架的解决方案。

首先,我们需要创建一个特定的ActionMessage,用于在调用后重新执行guard方法。我称之为RefreshableActionMessage

public class RefreshableActionMessage : ActionMessage
{
    private bool refreshAfterInvoke = true;

    public bool RefreshAfterInvoke
    {
        get { return refreshAfterInvoke; }
        set { refreshAfterInvoke = value; }
    }
}

现在我们必须在我们的“看守”按钮中使用它(是的,我们需要使用详细的语法):

<Button Content="Pat Cat">
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="Click">
            <local:RefreshableActionMessage MethodName="PatCat">
                <cal:Parameter Value="{Binding}" />
            </local:RefreshableActionMessage>
        </i:EventTrigger>
    </i:Interaction.Triggers>
</Button>

缺少负责重新执行guard方法的代码,但我们可以在Configure类的Bootstrapper方法中添加它:

protected override void Configure()
{
    ActionMessage.InvokeAction = delegate(ActionExecutionContext context)
    {
        RefreshableActionMessage refreshableActionMessage;

        object[] parameters = MessageBinder.DetermineParameters(context, context.Method.GetParameters());
        object obj = context.Method.Invoke(context.Target, parameters);
        Task task = obj as Task;
        if (task != null)
        {
            obj = task.AsResult();
        }
        IResult result = obj as IResult;
        if (result != null)
        {
            obj = new IResult[]
            {
                result
            };
        }
        IEnumerable<IResult> enumerable = obj as IEnumerable<IResult>;
        if (enumerable != null)
        {
            obj = enumerable.GetEnumerator();
        }
        IEnumerator<IResult> enumerator = obj as IEnumerator<IResult>;
        if (enumerator != null)
        {
            Coroutine.BeginExecute(enumerator, new CoroutineExecutionContext
            {
                Source = context.Source,
                View = context.View,
                Target = context.Target
            }, null);
        }

        refreshableActionMessage = context.Message as RefreshableActionMessage;
        if (refreshableActionMessage != null && refreshableActionMessage.RefreshAfterInvoke)
        {
            refreshableActionMessage.UpdateAvailability();
        }
    };
}

如您所见,如果自定义ActionMessage需要刷新,则可以通过调用UpdateAvailability方法执行。

我希望这个解决方案可以帮到你。

答案 1 :(得分:0)

我最终为每只Cat创建了一个单独的ViewModel,因此CatViewModel具有相应的CatView。然后,我能够通知可绑定集合已经更改,并且事情按预期工作。

注意,我错误地将ViewModel逻辑放入我的Cat模型中。这些是我的模型正在改变的属性。我把它们移到了CatViewModel。