Repository navigation
Property Change Notifications
Property-change notifications let data bindings (WPF, Avalonia, WinForms, MVVM frameworks)
react immediately when a setting value changes. Dapplo.Ini generates the boilerplate for
INotifyPropertyChanged and INotifyPropertyChanging automatically — simply extend the
relevant BCL interface(s) on your section interface.
Extend INotifyPropertyChanged and/or INotifyPropertyChanging directly on your section
interface. The source generator detects these and emits the event declarations and setter
invocations for every property in the generated class:
[IniSection]
public interface IThemeSettings : IIniSection, INotifyPropertyChanged
{
[IniValue(DefaultValue = "Light")]
string? Theme { get; set; }
[IniValue(DefaultValue = "12")]
int FontSize { get; set; }
}Both Theme and FontSize will now fire PropertyChanged whenever they change.
If you also want PropertyChanging (fired before the value changes), extend
INotifyPropertyChanging as well:
[IniSection]
public interface IThemeSettings
: IIniSection, INotifyPropertyChanged, INotifyPropertyChanging
{
// ...
}Interfaces that do not extend either BCL interface generate no event declarations (better performance, lower memory use).
var theme = config.GetSection<IThemeSettings>();
((INotifyPropertyChanged)theme).PropertyChanged += (_, e)
=> Console.WriteLine($"{e.PropertyName} changed");
((INotifyPropertyChanging)theme).PropertyChanging += (_, e)
=> Console.WriteLine($"{e.PropertyName} is about to change");Use [IniValue(SuppressPropertyChanged = true)] or
[IniValue(SuppressPropertyChanging = true)] to opt individual properties out.
This is useful for internal bookkeeping properties that must not pollute the event stream:
[IniSection]
public interface IThemeSettings : IIniSection, INotifyPropertyChanged, INotifyPropertyChanging
{
[IniValue(DefaultValue = "Light")]
string? Theme { get; set; } // fires both events
/// <summary>Internal cache flag — suppress both kinds of events.</summary>
[IniValue(SuppressPropertyChanged = true, SuppressPropertyChanging = true)]
bool IsDirty { get; set; } // fires neither event
}You can suppress only one event type while keeping the other:
// Fires PropertyChanged but NOT PropertyChanging
[IniValue(SuppressPropertyChanging = true)]
string? Theme { get; set; }When at least one event is emitted for a property, the generated setter contains an early-return equality check:
// Generated pseudo-code
set
{
if (EqualityComparer<string?>.Default.Equals(_theme, value)) return;
PropertyChanging?.Invoke(this, new PropertyChangingEventArgs(nameof(Theme)));
_theme = value;
SetRawValue("Theme", ConvertToRaw(value));
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Theme)));
}Setting a property to its current value is a no-op — no events are fired and the INI raw-value store is not updated. This prevents infinite loops in WPF/Avalonia two-way bindings.
For value types and string the check is emitted even when no event is generated, so
assigning an unchanged value never marks the section dirty. (Collections are excluded:
re-assigning the same, mutated instance is still recorded as a change.)
Reload() / ReloadAsync() (and file-change reloads) set values without going through the
setters. Sections that implement INotifyPropertyChanged get a PropertyChanged event for
every property whose value the reload changed, raised after the reload has completed on the
thread that ran it — marshal to the UI thread where needed. See Reloading.
Because the generated class implements both INotifyPropertyChanging and
INotifyPropertyChanged, it integrates naturally with WPF, Avalonia, WinForms, and
any other MVVM framework that relies on these interfaces:
<!-- WPF XAML — binds directly to the section object -->
<TextBlock Text="{Binding Theme}" />// Set the section as the DataContext
DataContext = config.GetSection<IThemeSettings>();IDataValidation<TSelf> validation runs in every property setter regardless of whether
INotifyPropertyChanged or INotifyPropertyChanging are implemented. You do not need to
extend these interfaces just to get live validation in your UI — see Validation.
-
Defining-Sections —
[IniValue]attribute reference -
Validation —
IDataValidation<TSelf>—INotifyDataErrorInfointegration