Laden...

(WPF) DelegatedTaskedCommand

Erstellt von LaTino vor 8 Jahren Letzter Beitrag vor 8 Jahren 7.855 Views
LaTino Themenstarter:in
3.003 Beiträge seit 2006
vor 8 Jahren
(WPF) DelegatedTaskedCommand

Beschreibung:
Ein typisiertes Command, das einen beliebigen übergeben Delegaten im Hintergrund ausführt.
(Ich habe eine Pre-4.0-Klasse, die dasselbe mit dem Backgroundworker machte, durch diese ersetzt und finde das Konzept ganz praktisch. Lässt sich sicher noch entschlacken. Und ja, man kann damit sein MVVM kaputtmachen. MVVM Toolkit ist bekannt, aber unerwünscht.)


//Abstrakte Basisklasse für Hintergrund-Commands
public abstract class TaskedCommandBase : ICommand
{
    private bool _isExecuting;
    public bool IsExecuting
    {
        get
        {
            return _isExecuting;
        }
        set
        {
            if (value.Equals(_isExecuting)) return;
            _isExecuting = value;
            OnCanExecuteChanged();
        }
    }

    protected void OnCanExecuteChanged()
    {
        var handler = CanExecuteChanged;
        if (handler != null) 
            handler(this, EventArgs.Empty);
    }

    public bool CanExecute(object parameter)
    {
        return !IsExecuting;
    }

    public async void Execute(object parameter)
    {
        OnBeforeWork(this, parameter);
        await Task.Run(() =>
        {
            IsExecuting = true;
            OnExecute(this, parameter);
            IsExecuting = false;
        });
        OnAfterWork(this, parameter);
    }

    public abstract void OnBeforeWork(object sender, object parameter);
    public abstract void OnExecute(object sender, object parameter);
    public abstract void OnAfterWork(object sender, object parameter);

    public event EventHandler CanExecuteChanged;
}


//Implementierung mit Delegaten (Action<>)
public class DelegatedTaskedCommand<T> : TaskedCommandBase
{
    private readonly Action<object, T> _beforeWorkAction;
    private readonly Action<object, T> _afterWorkAction;
    private readonly Action<object, T> _executeAction;

    public DelegatedTaskedCommand(Action<object, T> executeAction, Action<object, T> afterWorkAction = null, Action<object, T> beforeWorkAction = null)
    {
        _beforeWorkAction = beforeWorkAction;
        _afterWorkAction = afterWorkAction;
        _executeAction = executeAction;
    }

    public override void OnBeforeWork(object sender, object parameter)
    {
        ExecuteAction(sender, parameter, _beforeWorkAction);
    }

    public override void OnExecute(object sender, object parameter)
    {
        ExecuteAction(sender, parameter, _executeAction);
    }

    public override void OnAfterWork(object sender, object parameter)
    {
        ExecuteAction(sender, parameter, _afterWorkAction);
    }

    private void ExecuteAction(object sender, object parameter, Action<object, T> action)
    {
        if (!(parameter is T)) return;
        if (action != null) action(sender, (T)parameter);
    }
}


//Anwendung für einen View mit einem ProgressBar, der an die VM-Eigenschaft "OperationProgress" gebunden ist, mit einem string als Parameter
//ViewModel
public ICommand TestCommand
{
    get
    {
        IProgress<int> progressHandler = new Progress<int>(value => OperationProgress = value);
        return new DelegatedTaskedCommand<string>((sender, param) =>
        {
            var stringBuilder = new StringBuilder(param);
            for (var i = 0; i < 100; i++)
            {
                progressHandler.Report(i+1);
                Thread.Sleep(100);
                stringBuilder.Append(i.ToString());
            }
            _stringMember = stringBuilder.ToString();
        }); 
    }
}

WPF, ICommand, Task

"Furlow, is it always about money?"
"Is there anything else? I mean, how much sex can you have?"
"Don't know. I haven't maxed out yet."
(Furlow & Crichton, Farscape)