Ecng.ComponentModel
MVVM infrastructure, property change notifications, validation attributes, and UI component helpers.
Property Change Notifications
NotifiableObject
Base class implementing INotifyPropertyChanged and INotifyPropertyChanging.
using Ecng.ComponentModel;
public class Person : NotifiableObject
{
private string _name;
public string Name
{
get => _name;
set
{
if (_name == value) return;
NotifyChanging();
_name = value;
NotifyChanged();
}
}
}
var person = new Person();
person.PropertyChanged += (s, e) =>
{
Console.WriteLine($"{e.PropertyName} changed");
};
ViewModelBase
Extended base class for ViewModels with dispatcher support.
public class MainViewModel : ViewModelBase
{
private bool _isLoading;
public bool IsLoading
{
get => _isLoading;
set
{
_isLoading = value;
NotifyChanged();
}
}
}
DispatcherNotifiableObject
Notifiable object that marshals property changes to the UI thread.
public class ThreadSafeModel : DispatcherNotifiableObject
{
}
Observable Collections
ObservableCollectionEx
Extended ObservableCollection<T> with additional features.
var collection = new ObservableCollectionEx<Item>();
collection.AddRange(items);
collection.RemoveRange(itemsToRemove);
collection.Reset(newItems);
DispatcherObservableCollection
Thread-safe observable collection with UI dispatcher support.
var collection = new DispatcherObservableCollection<Item>();
Task.Run(() =>
{
collection.Add(new Item());
});
ConvertibleObservableCollection
Observable collection that transforms source items.
var models = new ObservableCollection<PersonModel>();
var viewModels = new ConvertibleObservableCollection<PersonModel, PersonViewModel>(
models,
model => new PersonViewModel(model));
models.Add(new PersonModel());
Range Types
Range
Generic range with min/max bounds.
var range = new Range<int>(1, 100);
bool contains = range.Contains(50);
bool outside = range.Contains(150);
int min = range.Min;
int max = range.Max;
int length = range.Length;
var other = new Range<int>(50, 150);
var intersection = range.Intersect(other);
var subRange = range.SubRange(20, 80);
NumericRange
Specialized numeric range with additional operations.
var range = new NumericRange<decimal>(0, 100);
Validation Attributes
Numeric Validation
public class Settings
{
[IntValidation(Min = 1, Max = 100)]
public int Count { get; set; }
[DoubleValidation(Min = 0.0, Max = 1.0)]
public double Factor { get; set; }
[DecimalValidation(Min = 0)]
public decimal Price { get; set; }
[LongValidation(Min = 0, Max = 1000000)]
public long Volume { get; set; }
}
TimeSpan Validation
[TimeSpanValidation(Min = "00:00:01", Max = "24:00:00")]
public TimeSpan Timeout { get; set; }
Price Validation
[PriceValidation(Min = 0)]
public Price StockPrice { get; set; }
Price Type
Financial price with type information.
var price = new Price(100.50m, PriceTypes.Limit);
PriceTypes.Limit
PriceTypes.Market
PriceTypes.Percent
Attributes
Step Attribute
Define increment step for numeric properties.
[Step(0.01)]
public decimal Price { get; set; }
[Step(1)]
public int Quantity { get; set; }
Icon Attributes
[Icon("path/to/icon.png")]
public class MyCommand { }
[VectorIcon("fas fa-home")]
public class HomeCommand { }
Doc Attribute
Link to documentation.
[Doc("https://docs.example.com/my-feature")]
public class MyFeature { }
BasicSetting Attribute
Mark property as a basic (commonly used) setting.
[BasicSetting]
public string ApiKey { get; set; }
Server Credentials
Manage server connection credentials securely.
var credentials = new ServerCredentials
{
Email = "user@example.com",
Password = "secret".Secure(),
Token = "api-token".Secure()
};
bool isConfigured = credentials.IsConfigured;
Process Singleton
Ensure only one instance of an application runs.
using var singleton = new ProcessSingleton("MyApp");
if (!singleton.TryAcquire())
{
Console.WriteLine("Another instance is already running");
return;
}
Dispatcher
Abstract UI thread dispatcher.
public interface IDispatcher
{
void Invoke(Action action);
Task InvokeAsync(Action action);
void BeginInvoke(Action action);
}
if (!dispatcher.CheckAccess())
{
dispatcher.Invoke(() => UpdateUI());
}
Channel Executor
Process items from a channel with controlled concurrency.
var executor = new ChannelExecutor<WorkItem>(
processItem: async item =>
{
await ProcessAsync(item);
},
maxConcurrency: 4);
executor.Enqueue(new WorkItem());
await executor.StopAsync();
Statistics
Track simple statistics.
var stat = new Stat("ProcessedItems");
stat.Increment();
stat.Add(5);
Console.WriteLine($"Total: {stat.Value}");
Periodic Action Planner
Schedule recurring actions.
var planner = new PeriodicActionPlanner();
planner.Schedule(
TimeSpan.FromMinutes(5),
async () => await RefreshDataAsync());
planner.Cancel();
NuGet
Install-Package Ecng.ComponentModel