Caliburn.Micro - 更新 BindableCollection 中的项目字段时调用方法保护
Caliburn.Micro - Calling method guard when updating field of item in BindableCollection
我有一个 属性 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 方法,因为现在守卫方法将 return false 一旦猫被拍了?
虽然对于属性,存在特定且复杂的 UI 感知机制(我说的是 Binding),但对于方法,情况则完全不同。
在我看来,在这种情况下使用事件是不合适的,所以我想到了一个基于扩展 Caliburn Micro 框架的解决方案。
首先,我们需要创建一个特定的 ActionMessage,用于在调用后重新执行 guard 方法。我叫它 RefreshableActionMessage
.
public class RefreshableActionMessage : ActionMessage
{
private bool refreshAfterInvoke = true;
public bool RefreshAfterInvoke
{
get { return refreshAfterInvoke; }
set { refreshAfterInvoke = value; }
}
}
现在我们必须在 "guarded" 按钮中使用它(是的,我们需要使用冗长的语法):
<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方法的代码,但是我们可以在Bootstrapper
class:[=20中的Configure
方法中添加它=]
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
方法执行。
希望这个解决方案能帮到你。
我最终为每只 Cat 创建了一个单独的 ViewModel,即 CatViewModel 和相应的 CatView。然后我能够通知可绑定集合已更改,并且一切正常。
请注意,我错误地将 ViewModel 逻辑放入了我的 Cat 模型中。这些是在我的模型上发生变化的属性。我将它们移到了 CatViewModel 中。
我有一个 属性 BindableCollection<Cat> { get; private set; }
,其中有许多 Cat
个对象绑定到我的 WPF XAML.
然后我将以下代码附加到此 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 方法,因为现在守卫方法将 return false 一旦猫被拍了?
虽然对于属性,存在特定且复杂的 UI 感知机制(我说的是 Binding),但对于方法,情况则完全不同。 在我看来,在这种情况下使用事件是不合适的,所以我想到了一个基于扩展 Caliburn Micro 框架的解决方案。
首先,我们需要创建一个特定的 ActionMessage,用于在调用后重新执行 guard 方法。我叫它 RefreshableActionMessage
.
public class RefreshableActionMessage : ActionMessage
{
private bool refreshAfterInvoke = true;
public bool RefreshAfterInvoke
{
get { return refreshAfterInvoke; }
set { refreshAfterInvoke = value; }
}
}
现在我们必须在 "guarded" 按钮中使用它(是的,我们需要使用冗长的语法):
<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方法的代码,但是我们可以在Bootstrapper
class:[=20中的Configure
方法中添加它=]
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
方法执行。
希望这个解决方案能帮到你。
我最终为每只 Cat 创建了一个单独的 ViewModel,即 CatViewModel 和相应的 CatView。然后我能够通知可绑定集合已更改,并且一切正常。
请注意,我错误地将 ViewModel 逻辑放入了我的 Cat 模型中。这些是在我的模型上发生变化的属性。我将它们移到了 CatViewModel 中。