更改Xamarin表单按钮颜色

时间:2017-09-02 09:39:16

标签: c# xamarin mvvm xamarin.forms

我是xamarin的新手,我想在完成一个过程后返回默认颜色后更改按钮的颜色,请参阅下面的代码如何在运行时重新渲染按钮。正在执行,所以我已经在click中处理了它。这个功能应该适用于Android和iOS。

public class RippleButton : Button
{
    private readonly Color _defaultBackgroundColor = Color.FromRgb(255, 87, 34);
    private readonly Color _clickedBackgroundColor = Color.FromRgb(76, 175, 80);

    public ICommand ClickCommand
    {
        get { return (ICommand)GetValue(ClickCommandProperty); }
        set
        {
            SetValue(ClickCommandProperty, value);
        }
    }


    public static readonly BindableProperty ClickCommandProperty = BindableProperty.Create(
                                                   propertyName: nameof(ClickCommand),
                                                   returnType: typeof(ICommand),
                                                   declaringType: typeof(RippleButton),
                                                   defaultValue: null,
                                                   defaultBindingMode: BindingMode.TwoWay,
                                                   propertyChanged: OnClickCommandChanged);

    private static void OnClickCommandChanged(BindableObject bindable, object oldvalue, object newvalue)
    {
    }

    public RippleButton()
    {
        const int animationTime = 10;


        TextColor = Color.FromRgb(255, 255, 255);
        BackgroundColor = _defaultBackgroundColor;

        Clicked += async (sender, e) =>
        {
            var btn = (RippleButton)sender;

            BackgroundColor = Color.FromRgb(76, 175, 80);

            ClickCommand?.Execute(btn.CommandParameter);

            await btn.ScaleTo(1.2, animationTime);
            await btn.ScaleTo(1, animationTime);

            BackgroundColor = _defaultBackgroundColor;
        };
    }

    private void ChangeColorOfButton()
    {
        BackgroundColor = _clickedBackgroundColor;
        Device.StartTimer(TimeSpan.FromSeconds(0.25), () =>
        {
            BackgroundColor = _defaultBackgroundColor;
            return false;
        });
    }
}

1 个答案:

答案 0 :(得分:6)

为了等待命令执行 - 其中一种方法是定义异步命令。 Stephen Cleary分享了一些awesome patterns on how to implement asynchronous commands

您可以将async命令定义为:

public interface IAsyncCommand : ICommand
{
    Task ExecuteAsync(object parameter);
}

public abstract class AsyncCommandBase : IAsyncCommand
{
    public abstract bool CanExecute(object parameter);
    public abstract Task ExecuteAsync(object parameter);

    public async void Execute(object parameter)
    {
        await ExecuteAsync(parameter);
    }

    public event EventHandler CanExecuteChanged;

    protected void RaiseCanExecuteChanged()
    {
        CanExecuteChanged?.Invoke(this, EventArgs.Empty);
    }
}

public class AsyncCommand<TResult> : AsyncCommandBase, INotifyPropertyChanged
{
    private readonly Func<Task<TResult>> _command;
    private NotifyTaskCompletion<TResult> _execution;

    public AsyncCommand(Func<Task<TResult>> command)
    {
        _command = command;
    }

    public override bool CanExecute(object parameter)
    {
        return Execution == null || Execution.IsCompleted;
    }

    public override async Task ExecuteAsync(object parameter)
    {
        Execution = new NotifyTaskCompletion<TResult>(_command());
        RaiseCanExecuteChanged();
        await Execution.TaskCompletion;
        RaiseCanExecuteChanged();
    }

    public NotifyTaskCompletion<TResult> Execution
    {
        get { return _execution; }
        private set
        {
            _execution = value;
            OnPropertyChanged();
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
    }
}

您现在可以将控件重构为:

public class RippleButton : Button
{
    public static readonly BindableProperty ClickedBackgroundColorProperty =
        BindableProperty.Create(
            "ClickedBackgroundColor", typeof(Color), typeof(RippleButton),
            defaultValue: Color.FromRgb(76, 175, 80));

    public Color ClickedBackgroundColor
    {
        get { return (Color)GetValue(ClickedBackgroundColorProperty); }
        set { SetValue(ClickedBackgroundColorProperty, value); }
    }

    public static readonly BindableProperty AsyncCommandProperty =
        BindableProperty.Create(
            "AsyncCommand", typeof(IAsyncCommand), typeof(RippleButton),
            defaultValue: default(IAsyncCommand));

    public IAsyncCommand AsyncCommand
    {
        get { return (IAsyncCommand)GetValue(AsyncCommandProperty); }
        set { SetValue(AsyncCommandProperty, value); }
    }

    public RippleButton()
    {
        const int animationTime = 150;

        TextColor = Color.FromRgb(255, 255, 255);
        BackgroundColor = Color.FromRgb(255, 87, 34);

        Clicked += async (sender, e) =>
        {
            //execute command only if button is enabled.
            if (!IsEnabled)
                return;

            //continue only if command is executable, and not allow multiple click(s)
            if (AsyncCommand == null || !AsyncCommand.CanExecute(CommandParameter))
                return;

            var defaultColor = BackgroundColor;
            BackgroundColor = ClickedBackgroundColor;
            IsEnabled = false;

            await AsyncCommand.ExecuteAsync(CommandParameter);

            await this.ScaleTo(1.2, animationTime);
            await this.ScaleTo(1, animationTime);

            IsEnabled = true;
            BackgroundColor = defaultColor;
        };
    }
}

样本使用:

XAML

<local:RippleButton Text="Download" 
                    AsyncCommand="{Binding SimulateDownloadCommand}" />

查看模型

public class YourViewModel : BaseViewModel
{
    public YourViewModel()
    {
        SimulateDownloadCommand = new AsyncCommand<bool>(() => SimulateDownloadAsync());
    }

    private IAsyncCommand _downloadCommand;
    public IAsyncCommand SimulateDownloadCommand
    {
        get { return _downloadCommand; }
        private set
        {
            if (_downloadCommand != value)
            {
                _downloadCommand = value;
                OnPropertyChanged("SimulateDownloadCommand");
            }
        }
    }

    async Task<bool> SimulateDownloadAsync()
    {
        await Task.Run(() => SimulateDownload());
        return true;
    }

    void SimulateDownload()
    {
        // Simulate a 1.5 second pause
        var endTime = DateTime.Now.AddSeconds(1.5);
        while (true)
        {
            if (DateTime.Now >= endTime)
            {
                break;
            }
        }
    }
}

enter image description here enter image description here