Catalog/imagecatalog/ViewModelBase.cs

81 lines
2.7 KiB
C#
Raw Normal View History

using System;
2024-10-14 22:55:52 +02:00
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
2026-02-04 23:16:06 +01:00
using System.Threading;
2024-10-14 22:55:52 +02:00
using System.Threading.Tasks;
#if WINDOWS
2026-02-04 23:16:06 +01:00
using System.Windows.Forms;
#endif
2024-10-14 22:55:52 +02:00
namespace ImageCatalog_2
{
public class ViewModelBase : INotifyPropertyChanged
{
2026-02-04 23:16:06 +01:00
private readonly SynchronizationContext? _synchronizationContext;
#if WINDOWS
2026-02-04 23:16:06 +01:00
private Control? _control;
#endif
2026-02-04 23:16:06 +01:00
protected ViewModelBase()
{
// Capture the synchronization context (UI thread context)
_synchronizationContext = SynchronizationContext.Current;
}
/// <summary>
/// Set a Control to use for thread marshalling in WinForms applications.
/// This is required for proper cross-thread handling with data binding.
/// </summary>
#if WINDOWS
2026-02-04 23:16:06 +01:00
public void SetControl(Control control)
{
_control = control;
}
#endif
2026-02-04 23:16:06 +01:00
2024-10-14 22:55:52 +02:00
public event PropertyChangedEventHandler? PropertyChanged;
2026-02-04 23:16:06 +01:00
2024-10-14 22:55:52 +02:00
// This method is called by the Set accessor of each property.
// The CallerMemberName attribute that is applied to the optional propertyName
// parameter causes the property name of the caller to be substituted as an argument.
protected void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
2026-02-04 23:16:06 +01:00
if (PropertyChanged == null)
return;
#if WINDOWS
2026-02-04 23:16:06 +01:00
// If we have a Control reference (WinForms), use Control.Invoke for proper marshalling
if (_control != null)
{
if (_control.InvokeRequired)
{
_control.Invoke(() => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)));
}
else
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
// Fallback to SynchronizationContext if available
else
#endif
if (_synchronizationContext != null && SynchronizationContext.Current != _synchronizationContext)
2026-02-04 23:16:06 +01:00
{
// We're on a different thread, marshal to the UI thread
_synchronizationContext.Send(_ =>
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}, null);
}
else
2024-10-14 22:55:52 +02:00
{
2026-02-04 23:16:06 +01:00
// We're already on the UI thread or no sync context available
2024-10-14 22:55:52 +02:00
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}