我是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;
});
}
}
答案 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;
}
}
}
}