1+ using System ;
2+ using System . Collections . Generic ;
3+ using System . Text ;
4+
5+ namespace MonkeyLoader . Configuration
6+ {
7+ /// <summary>
8+ /// Represents the functionality for an <see cref="IDefiningConfigKey{T}"/>,
9+ /// which propagate any changes in value in both directions
10+ /// between the two associated config items.
11+ /// </summary>
12+ /// <inheritdoc cref="IConfigKeyBidirectionalBinding{T}"/>
13+ public sealed class ConfigKeyBidirectionalBinding < T > : IConfigKeyBidirectionalBinding < T >
14+ {
15+ /// <inheritdoc/>
16+ public IDefiningConfigKey < T > Owner { get ; private set ; } = null ! ;
17+
18+ IDefiningConfigKey IConfigKeyBidirectionalBinding . Owner => Owner ;
19+
20+ /// <inheritdoc/>
21+ public IDefiningConfigKey < T > Target { get ; }
22+
23+ IDefiningConfigKey IConfigKeyBidirectionalBinding . Target => Target ;
24+
25+ /// <summary>
26+ /// Creates a new bidirectional binding targeting the given config item.
27+ /// </summary>
28+ /// <param name="target">The other config item to propagate changes to and from.</param>
29+ public ConfigKeyBidirectionalBinding ( IDefiningConfigKey < T > target )
30+ {
31+ Target = target ;
32+ }
33+
34+ /// <remarks>
35+ /// Adds the <see cref="IDefiningConfigKey{T}.Changed">Changed</see> event
36+ /// listeners to propagate changes between the linked config items.
37+ /// </remarks>
38+ /// <exception cref="InvalidOperationException">When the binding has already been initialized or is targeted at itself.</exception>
39+ /// <inheritdoc/>
40+ public void Initialize ( IDefiningConfigKey < T > entity )
41+ {
42+ if ( Owner is not null )
43+ throw new InvalidOperationException ( $ "This binding targetting [{ Target } ] is already owned by [{ Owner } ]!") ;
44+
45+ if ( ReferenceEquals ( Target , entity ) )
46+ throw new InvalidOperationException ( $ "Can't bind [{ Target } ] to itself!") ;
47+
48+ Owner = entity ;
49+
50+ // Shouldn't need circular check because Changed event is only fired for actual changes
51+ Owner . Changed += ( _ , args ) => Target . SetValue ( args . NewValue ! , args . GetPropagatedEventLabel ( ConfigKeyBindings . SetFromBidirectionalOwnerEventLabel ) ) ;
52+ Target . Changed += ( _ , args ) => Owner . SetValue ( args . NewValue ! , args . GetPropagatedEventLabel ( ConfigKeyBindings . SetFromBidirectionalTargetEventLabel ) ) ;
53+ }
54+ }
55+
56+ /// <typeparam name="T">The type of the config item's value.</typeparam>
57+ /// <inheritdoc cref="IConfigKeyBidirectionalBinding"/>
58+ public interface IConfigKeyBidirectionalBinding < T > : IConfigKeyComponent < IDefiningConfigKey < T > > , IConfigKeyBidirectionalBinding
59+ {
60+ /// <inheritdoc cref="IConfigKeyBidirectionalBinding.Owner"/>
61+ public new IDefiningConfigKey < T > Owner { get ; }
62+
63+ /// <inheritdoc cref="IConfigKeyBidirectionalBinding.Target"/>
64+ public new IDefiningConfigKey < T > Target { get ; }
65+ }
66+
67+ /// <summary>
68+ /// Defines the interface for config key components,
69+ /// which propagate any changes in value in both directions
70+ /// between the two associated config items.
71+ /// </summary>
72+ public interface IConfigKeyBidirectionalBinding
73+ {
74+ /// <summary>
75+ /// Gets the config item that this component was initialized to.
76+ /// </summary>
77+ public IDefiningConfigKey Owner { get ; }
78+
79+ /// <summary>
80+ /// Gets the config item that this binding targets.
81+ /// </summary>
82+ public IDefiningConfigKey Target { get ; }
83+ }
84+ }
0 commit comments