Cursor rule
.cursor/rules/async-threading-patterns.mdcAsync/await and threading patterns for WPF UI updates
Cursor rules
Quality
65/100
Scores the file, not the repository.Length
750 words
26 headings · 15 code blocksRepository
103
— · pushed 17 days agoLast changed
3 days ago
First indexed 3 days ago.1234567# Async/Await and Threading Patterns89## UI Thread Updates1011### Dispatcher Pattern12**CRITICAL**: All UI updates must happen on the UI thread. Use `Dispatcher.Invoke()` or `Dispatcher.InvokeAsync()` when updating UI from background threads.1314```csharp15// From background thread - update UI16Application.Current.Dispatcher.Invoke(() =>17{18 StatusText.Text = "Processing...";19 StatusText.Foreground = Brushes.Blue;20});2122// Async version (non-blocking)23await Application.Current.Dispatcher.InvokeAsync(() =>24{25 StatusText.Text = "Complete";26});27```2829### Dispatcher Priority30- Use `DispatcherPriority.Background` for non-urgent updates31- Use `DispatcherPriority.Normal` (default) for standard updates32- Use `DispatcherPriority.Send` only when absolutely necessary3334```csharp35Dispatcher.Invoke(() =>36{37 // Update UI38}, DispatcherPriority.Background);39```4041## Async Service Methods4243### Translation Services44All translation services implement async methods:4546```csharp47public interface ITranslationService48{49 Task<TranslationResult?> TranslateAsync(50 string sourceText,51 string targetLanguage,52 string context);53}54```5556### Implementation Pattern57```csharp58public async Task<TranslationResult?> TranslateAsync(string text, string lang, string context)59{60 try61 {62 using var httpClient = new HttpClient();63 var response = await httpClient.PostAsync(url, content);6465 if (response.IsSuccessStatusCode)66 {67 var result = await response.Content.ReadAsStringAsync();68 return ParseResult(result);69 }7071 return null;72 }73 catch (Exception ex)74 {75 Console.WriteLine($"Translation error: {ex.Message}");76 return null;77 }78}79```8081## Background Operations8283### Screen Capture84Screen capture runs on background thread/timer:8586```csharp87private void Timer_Tick(object sender, EventArgs e)88{89 // Capture runs on timer thread90 var bitmap = CaptureScreen(x, y, width, height);9192 // Process on background thread93 Task.Run(async () =>94 {95 var result = await ProcessImageAsync(bitmap);9697 // Update UI on UI thread98 Application.Current.Dispatcher.Invoke(() =>99 {100 UpdateDisplay(result);101 });102 });103}104```105106### OCR Processing107OCR operations should be async and non-blocking:108109```csharp110private async Task<List<TextObject>> ProcessOCRAsync(Bitmap bitmap)111{112 // Run OCR on background thread113 return await Task.Run(() =>114 {115 // OCR processing116 return ocrService.Process(bitmap);117 });118}119```120121## HttpClient Usage122123### Best Practices124- **DO NOT** create new HttpClient instances for each request125- Create HttpClient once and reuse (or use HttpClientFactory)126- Dispose properly with `using` statement127128```csharp129// Good: Reuse HttpClient130private static readonly HttpClient _httpClient = new HttpClient();131132public async Task<string> GetDataAsync()133{134 var response = await _httpClient.GetAsync(url);135 return await response.Content.ReadAsStringAsync();136}137138// Or use using for one-off requests139public async Task<string> GetDataAsync()140{141 using var client = new HttpClient();142 var response = await client.GetAsync(url);143 return await response.Content.ReadAsStringAsync();144}145```146147## Task Cancellation148149### Cancellation Tokens150Use `CancellationToken` for long-running operations:151152```csharp153public async Task ProcessAsync(CancellationToken cancellationToken)154{155 while (!cancellationToken.IsCancellationRequested)156 {157 await DoWorkAsync();158 await Task.Delay(1000, cancellationToken);159 }160}161```162163## Thread Safety164165### Singleton Thread Safety166Simple null-check pattern is sufficient for this application:167168```csharp169private static ConfigManager? _instance;170private static readonly object _lock = new object();171172public static ConfigManager Instance173{174 get175 {176 if (_instance == null)177 {178 lock (_lock)179 {180 if (_instance == null)181 {182 _instance = new ConfigManager();183 }184 }185 }186 return _instance;187 }188}189```190191### Dictionary Access192- Use `TryGetValue` for safe dictionary access193- Check for null before using values194195```csharp196if (_configValues.TryGetValue(key, out var value))197{198 return value;199}200return defaultValue;201```202203## Blocking vs Non-Blocking204205### Avoid Blocking UI Thread206- **NEVER** use `.Result` or `.Wait()` on async methods in UI code207- Always use `await` for async operations208- Use `Task.Run()` to move CPU-intensive work off UI thread209210```csharp211// BAD: Blocks UI thread212var result = httpClient.GetAsync(url).Result;213214// GOOD: Non-blocking215var result = await httpClient.GetAsync(url);216217// GOOD: Move work off UI thread218var result = await Task.Run(() => ExpensiveOperation());219```220221## Exception Handling in Async222223### Async Exception Handling224Exceptions in async methods should be caught and logged:225226```csharp227public async Task<Result?> ProcessAsync()228{229 try230 {231 var result = await DoWorkAsync();232 return result;233 }234 catch (Exception ex)235 {236 Console.WriteLine($"Error: {ex.Message}");237 LogManager.Instance.LogError("Process failed", ex);238 return null;239 }240}241```242243## Timer Usage244245### WPF DispatcherTimer246Use `DispatcherTimer` for UI-related timers:247248```csharp249private DispatcherTimer _timer;250251private void InitializeTimer()252{253 _timer = new DispatcherTimer();254 _timer.Interval = TimeSpan.FromMilliseconds(100);255 _timer.Tick += Timer_Tick;256 _timer.Start();257}258259private void Timer_Tick(object sender, EventArgs e)260{261 // Runs on UI thread262 UpdateUI();263}264```265266### System.Timers.Timer267Use `System.Timers.Timer` for background operations:268269```csharp270private System.Timers.Timer _backgroundTimer;271272private void InitializeBackgroundTimer()273{274 _backgroundTimer = new System.Timers.Timer(1000);275 _backgroundTimer.Elapsed += BackgroundTimer_Elapsed;276 _backgroundTimer.AutoReset = true;277 _backgroundTimer.Start();278}279280private void BackgroundTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)281{282 // Runs on background thread - use Dispatcher for UI updates283 Task.Run(async () => await ProcessBackgroundWorkAsync());284}285```286287## Progress Reporting288289### Progress Updates290Report progress from background threads:291292```csharp293private async Task ProcessWithProgressAsync(IProgress<int> progress)294{295 for (int i = 0; i < 100; i++)296 {297 await DoWorkAsync();298 progress.Report(i);299 }300}301302// Usage303var progress = new Progress<int>(percent =>304{305 Application.Current.Dispatcher.Invoke(() =>306 {307 ProgressBar.Value = percent;308 });309});310311await ProcessWithProgressAsync(progress);312```313
Also in SethRobinson/UGTLive
Diff this repo’s formatsOne repository carrying more than one format is the comparison this product exists for: does anyone actually write different content in each file, or is one a copy of the other?
| Repository | Format | Stack | Covers | Score | Changed |
|---|---|---|---|---|---|
| SethRobinson/UGTLive.cursor/rules/ui-ux-patterns.mdc · 103 | Cursor rules | stylearchtypesui+1 | 62/100 | 3 days ago | |
| SethRobinson/UGTLive.cursor/rules/architecture-patterns.mdc · 103 | Cursor rules | buildtestlint-formatstyle+6 | 77/100 | 3 days ago | |
| SethRobinson/UGTLive.cursor/rules/code-style-conventions.mdc · 103 | Cursor rules | stylearchtypesdocs | 62/100 | 3 days ago | |
| SethRobinson/UGTLive.cursor/rules/configuration-management.mdc · 103 | Cursor rules | archsecuritydatabaseapi+1 | 65/100 | 3 days ago | |
| SethRobinson/UGTLive.cursor/rules/debugging-testing.mdc · 103 | Cursor rules | buildteststylearch+3 | 69/100 | 3 days ago | |
| SethRobinson/UGTLive.cursor/rules/locale-invariant-formatting.mdc · 103 | Cursor rules | lint-formatuido-not | 61/100 | 3 days ago | |
| SethRobinson/UGTLive.cursor/rules/service-integration-patterns.mdc · 103 | Cursor rules | buildteststylearch | 69/100 | 3 days ago | |
| SethRobinson/UGTLive.cursor/rules/translation-workflow.mdc · 103 | Cursor rules | testlint-formatarchapi+3 | 66/100 | 3 days ago | |
| SethRobinson/UGTLive.cursor/rules/ugtlive-project-guide.mdc · 103 | Cursor rules | stylearchuideployment+1 | 69/100 | 3 days ago | |
| SethRobinson/UGTLive.cursor/rules/versioning-workflow.mdc · 103 | Cursor rules | stylegitdeploymentagent-behaviour+1 | 62/100 | 3 days ago | |
| SethRobinson/UGTLive.cursor/rules/wpf-ui-patterns.mdc · 103 | Cursor rules | setuplint-formatstylearch+1 | 66/100 | 3 days ago | |
| SethRobinson/UGTLiveAGENTS.md · 103 | AGENTS.md | testgitsecurityperformance+1 | 74/100 | 3 days ago |
Diff against .cursor/rules/ui-ux-patterns.mdc Diff against .cursor/rules/architecture-patterns.mdc Diff against .cursor/rules/code-style-conventions.mdc Diff against .cursor/rules/configuration-management.mdc Diff against .cursor/rules/debugging-testing.mdc Diff against .cursor/rules/locale-invariant-formatting.mdc Diff against .cursor/rules/service-integration-patterns.mdc Diff against .cursor/rules/translation-workflow.mdc Diff against .cursor/rules/ugtlive-project-guide.mdc Diff against .cursor/rules/versioning-workflow.mdc Diff against .cursor/rules/wpf-ui-patterns.mdc Diff against AGENTS.md
Similar configs
Same format, overlapping stack, ranked by quality.
| Repository | Format | Stack | Covers | Score | Changed |
|---|---|---|---|---|---|
| ThanhTrunggDEV/DontBeLazy.cursor/rules/rust-testing.mdc · 6 | Cursor rules | teststyletesting-strategy | 90/100 | 3 days ago | |
| ThanhTrunggDEV/DontBeLazy.cursor/rules/dart-testing.mdc · 6 | Cursor rules | teststyletypestesting-strategy | 85/100 | 3 days ago | |
| ThanhTrunggDEV/DontBeLazy.cursor/rules/dart-coding-style.mdc · 6 | Cursor rules | lint-formatstyletypesdo-not | 84/100 | 3 days ago | |
| ThanhTrunggDEV/DontBeLazy.cursor/rules/rust-security.mdc · 6 | Cursor rules | stylesecuritydatabasedo-not | 80/100 | 3 days ago | |
| imazen/imageflow.cursor/rules/ci.mdc · 4.4k | Cursor rules | setupbuildtestarch+3 | 79/100 | 3 days ago | |
| ThanhTrunggDEV/DontBeLazy.cursor/rules/rust-coding-style.mdc · 6 | Cursor rules | lint-formatstyle | 78/100 | 3 days ago | |
| ThanhTrunggDEV/DontBeLazy.cursor/rules/dart-hooks.mdc · 6 | Cursor rules | lint-formatarchtesting-strategygit+1 | 78/100 | 3 days ago | |
| SethRobinson/UGTLive.cursor/rules/architecture-patterns.mdc · 103 | Cursor rules | buildtestlint-formatstyle+6 | 77/100 | 3 days ago |
