How can I implement delay using Caliburn.Micro using convention

Sometimes I need to postpone the binding (think of the search field that calls the server, you want it to be executed only if the user paused for a second of a second, and not for every keystroke).

WPF binding delay is not a problem - you simply specify a delay with the binding: <TextBlock Text="{Binding Name, Delay=500}"/>.

Whenever I need to delay execution in a situation where I use Caliburn.Micro Message.Attach, I usually implement it this way (the message attaches to the event TextChangedwith an action DoSomething):

private int doingSomething;

public async void DoSomething()
{
    int current = ++doingSomething;
    await Task.Delay(500);
    if (current != doingSomething) //method was reentered
        return;

    await DoWorkCallServerEtc();
}

This works well, but it does not scale well and violates the DRY principle (I need to write this again where I need the delay).

: - , Caliburn.Micro?
, , , ?

+4
1

System.Windows.Interactivity .

,

<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), , Caliburn Bootstrapper:

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)]" />

, .

+4

Source: https://habr.com/ru/post/1629768/


All Articles