Created
October 31, 2016 18:01
-
-
Save cwensley/e9eda58ca2e44858f62bfdc2f2a8e809 to your computer and use it in GitHub Desktop.
Shows how to generate an image in your view model based on user input in a background thread using async/await.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using Eto.Forms; | |
using Eto.Drawing; | |
using System.ComponentModel; | |
using System.Windows.Input; | |
using System.Threading.Tasks; | |
using System.Threading; | |
namespace TestAsyncAwait | |
{ | |
public class MyViewModel : INotifyPropertyChanged | |
{ | |
CancellationTokenSource cancelSource; | |
int count; | |
/// <summary> | |
/// Call this from your view model to update the image asynchronously | |
/// </summary> | |
async void ExecuteUpdateImage() | |
{ | |
try | |
{ | |
// cancel previous update if any | |
cancelSource?.Cancel(); | |
// tell user we're updating | |
Updating = true; | |
// create a new cancellation token | |
cancelSource = new CancellationTokenSource(); | |
var ct = cancelSource.Token; | |
// 1 second delay before doing anything | |
await Task.Delay(1000, ct); | |
// generate new image in background thread | |
MyImage = await Task.Run(() => BackgroundUpdate(ct), ct); | |
// No longer updating. Does not execute for cancelled updates | |
Updating = false; | |
cancelSource = null; | |
} | |
catch (OperationCanceledException) | |
{ | |
// task was cancelled! | |
} | |
} | |
/// <summary> | |
/// This is run in a background thread and won't block the UI | |
/// </summary> | |
Bitmap BackgroundUpdate(CancellationToken ct) | |
{ | |
Thread.Sleep(1000); // simulate delay in generating bitmap | |
ct.ThrowIfCancellationRequested(); | |
var bmp = new Bitmap(100, 100, PixelFormat.Format32bppRgba); | |
ct.ThrowIfCancellationRequested(); | |
count++; // increment counter to ensure we're only generating limited number of bitmaps | |
using (var g = new Graphics(bmp)) | |
{ | |
g.DrawLine(Colors.Blue, 0, 0, 100, 100); | |
g.DrawLine(Colors.Blue, 100, 0, 0, 100); | |
g.DrawText(new Font(SystemFont.Default, 20), Colors.Black, 0, 0, count.ToString()); | |
} | |
ct.ThrowIfCancellationRequested(); | |
return bmp; | |
} | |
Command updateCommand; | |
public Command UpdateCommand => updateCommand ?? (updateCommand = new Command((sender, e) => ExecuteUpdateImage())); | |
Image myImage; | |
public Image MyImage | |
{ | |
get { return myImage; } | |
private set | |
{ | |
if (myImage != value) | |
{ | |
myImage = value; | |
OnPropertyChanged(nameof(MyImage)); | |
} | |
} | |
} | |
bool updating; | |
public bool Updating | |
{ | |
get { return updating; } | |
private set | |
{ | |
if (updating != value) | |
{ | |
updating = value; | |
OnPropertyChanged(nameof(Updating)); | |
} | |
} | |
} | |
double numericValue; | |
public double NumericValue | |
{ | |
get { return numericValue; } | |
set | |
{ | |
if (numericValue != value) | |
{ | |
numericValue = value; | |
OnPropertyChanged(nameof(NumericValue)); | |
ExecuteUpdateImage(); | |
} | |
} | |
} | |
public event PropertyChangedEventHandler PropertyChanged; | |
protected virtual void OnPropertyChanged(string name) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name)); | |
} | |
public partial class MainForm : Form | |
{ | |
void InitializeComponent() | |
{ | |
Title = "My Eto Form"; | |
var updateImageButton = new Button { Text = "Update Image" }; | |
updateImageButton.BindDataContext(c => c.Command, (MyViewModel m) => m.UpdateCommand); | |
var imageView = new ImageView { Width = 200, Height = 200 }; | |
imageView.BindDataContext(c => c.Image, Binding.Property((MyViewModel m) => m.MyImage)); | |
var updatingLabel = new Label { Text = "Updating image..." }; | |
updatingLabel.BindDataContext(c => c.Visible, (MyViewModel m) => m.Updating); | |
var numericUpDown = new NumericUpDown(); | |
numericUpDown.ValueBinding.BindDataContext((MyViewModel m) => m.NumericValue); | |
Content = new StackLayout | |
{ | |
Padding = 10, | |
Spacing = 10, | |
Items = | |
{ | |
TableLayout.Horizontal(5, updateImageButton, numericUpDown), | |
updatingLabel, | |
new StackLayoutItem(TableLayout.AutoSized(imageView, centered: true), HorizontalAlignment.Stretch, true) | |
// Add more controls here | |
} | |
}; | |
DataContext = new MyViewModel(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment