我有时需要延迟绑定(bind)执行(想想一个调用服务器的搜索框,你希望它只在用户暂停一秒钟而不是每次击键时执行)。
延迟 WPF 绑定(bind)没有问题 - 您只需指定绑定(bind)的延迟:
<TextBlock Text="{Binding Name, Delay=500}"/>
.
每当我需要在使用 Caliburn.Micro 的 Message.Attach
的情况下延迟执行时,我通常以这种方式实现它(消息附加到带有 TextChanged
操作的 DoSomething
事件):
private int doingSomething;
public async void DoSomething()
{
int current = ++doingSomething;
await Task.Delay(500);
if (current != doingSomething) //method was reentered
return;
await DoWorkCallServerEtc();
}
这很好用,但它不能很好地扩展并且违反了 DRY 原则(我需要在需要延迟的地方重新写一遍)。
我的问题是,我可以使用 Caliburn.Micro 以某种方式为此编写约定吗?
或者可能是一种不同的、更具可扩展性的方法?
最佳答案
正如您在 documentation page 中所读到的那样
Actions feature leverages System.Windows.Interactivity for it's trigger mechanism.
意思是
<TextBox Name="textBox" Margin="5"
cal:Message.Attach="[Event TextChanged] = [Action DoAction(textBox.Text)]" />
相当于:
<TextBox Margin="5" Name="textBox">
<i:Interaction.Triggers>
<i:EventTrigger EventName="TextChanged">
<cal:ActionMessage MethodName="DoAction">
<cal:Parameter Value="{Binding ElementName=textBox, Path=Text}" />
</cal:ActionMessage>
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBox>
负责执行 DoAction
方法的对象是 EventTrigger . EventTrigger
立即触发,没有延迟。所以我们需要创建自己的DelayedEventTrigger
;类似的东西:
public class DelayedEventTrigger : System.Windows.Interactivity.EventTrigger
{
private EventArgs args;
private DispatcherTimer dispatcherTimer;
public static readonly DependencyProperty DelayProperty =
DependencyProperty.Register("Delay", typeof(int), typeof(DelayedEventTrigger), new PropertyMetadata(1000));
public int Delay
{
get { return (int)base.GetValue(DelayProperty); }
set { base.SetValue(DelayProperty, value); }
}
protected override void OnEvent(EventArgs eventArgs)
{
if (dispatcherTimer != null)
{
dispatcherTimer.Stop();
}
args = eventArgs;
dispatcherTimer = new DispatcherTimer();
dispatcherTimer.Interval = TimeSpan.FromMilliseconds(Delay);
dispatcherTimer.Tick += new EventHandler(OnDispatcherTimerTick);
dispatcherTimer.Start();
}
protected override void OnDetaching()
{
if (dispatcherTimer != null)
{
dispatcherTimer.Stop();
dispatcherTimer = null;
}
base.OnDetaching();
}
private void OnDispatcherTimerTick(object sender, EventArgs e)
{
dispatcherTimer.Stop();
InvokeActions(args);
}
}
它的默认延迟是 1 秒(1000 毫秒)。所以现在我们可以在我们的 XAML 中使用它:
<TextBox Margin="5" Name="textBox">
<i:Interaction.Triggers>
<local:DelayedEventTrigger Delay="800" EventName="TextChanged">
<cal:ActionMessage MethodName="DoDelayAction">
<cal:Parameter Value="{Binding ElementName=textBox, Path=Text}" />
</cal:ActionMessage>
</local:DelayedEventTrigger>
</i:Interaction.Triggers>
</TextBox>
在我看来,没有必要使用约定(您可以明确地使用 DelayedEventTrigger
),但是如果您愿意,可以在您的 Bootstrapper
类中配置 Caliburn 解析器:
protected override void Configure()
{
base.Configure();
Parser.CreateTrigger = delegate(DependencyObject target, string triggerText)
{
System.Windows.Interactivity.EventTrigger eventTrigger;
if (triggerText == null)
{
ElementConvention elementConvention = ConventionManager.GetElementConvention(target.GetType());
return elementConvention.CreateTrigger();
}
string eventName = triggerText.Replace("[", String.Empty).Replace("]", String.Empty);
if (eventName.StartsWith("Delayed", StringComparison.OrdinalIgnoreCase))
{
eventName = eventName.Replace("DelayedEvent", String.Empty).Trim();
eventTrigger = new DelayedEventTrigger();
}
else
{
eventName = eventName.Replace("Event", String.Empty).Trim();
eventTrigger = new System.Windows.Interactivity.EventTrigger();
}
eventTrigger.EventName = eventName;
return eventTrigger;
};
}
通过添加此代码,您可以使用此约定:
<TextBox Name="textBox" Margin="5"
cal:Message.Attach="[DelayedEvent TextChanged] = [Action DoDelayAction(textBox.Text)]" />
希望对您有所帮助。
关于c# - 我如何使用约定实现 Caliburn.Micro 操作的延迟,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35535702/