/// <summary> /// Deletes a binding between a dependency property and a network table entry /// </summary> /// <param name="source">The object the binding is on</param> /// <param name="property">The property to unbind</param> public static void Delete(DependencyObject source, DependencyProperty property) { if (!IsRunning) { throw new InvalidOperationException("Can only delete bindings while the network table is running"); } DependencyNotifyListener listener = new DependencyNotifyListener(source); if (propertyLookup.ContainsKey(listener)) { if (propertyLookup[listener].TryRemoveByFirst(property.Name)) { //permanent delete rather than temporary unbind listener.DeleteBinding(property); } } }
/// <summary> /// Creates a binding between a dependency property and a network table entry /// </summary> /// <typeparam name="TLocal">The type of the entry in the dashboard</typeparam> /// <typeparam name="TNetwork">The type of the entry in the network table</typeparam> /// <param name="source">The object to bind to</param> /// <param name="property">The property to bind. Attached properties will throw an exception</param> /// <param name="networkPath">The full path of the entry in the network table</param> /// <param name="converter">The conversion mapping between the network values and local values</param> /// <param name="localOverride">Whether the local dashboard values should take precedence when the binding occurs</param> public static void Create <TLocal, TNetwork>(DependencyObject source, DependencyProperty property, string networkPath, NTConverter <TLocal, TNetwork> converter, bool localOverride = false) { if (!IsRunning) { throw new InvalidOperationException("Can only create bindings while the network table is running"); } Tuple <ITable, string> networkSource = NormalizeKey(networkPath); networkPath = networkSource.Item2; //because of additional work that needs to be done to bind the value, simpler to reimplement DependencyNotifyListener listener = new DependencyNotifyListener(source); if (!propertyLookup.ContainsKey(listener)) { propertyLookup[listener] = new OneToOneConversionMap <string, string>(); //this is a new item being bound, have it notify us of updates listener.PropertyChanged += OnLocalValueChange; } if (propertyLookup[listener].TryAdd(property.Name, networkPath)) { customTables[listener] = networkSource.Item1; //this means there were no binding conflicts //bind the dependency property to be notified of changes to it listener.BindProperty(property); //map a conversion if needed; null is valid propertyLookup[listener].MapConversionByFirst(property.Name, converter); //make the values consistent by forcing an update. //first check if the dashboard has a value at all Value data = networkSource.Item1.GetValue(networkPath, null); if (data == null || localOverride) { //send the local value to the network by "updating" the local value PropertyChangedEventArgs e = new PropertyChangedEventArgs(property.Name); OnLocalValueChange(listener, e); } else { //pull the dashboard from the local value by "updating" the network value OnNetworkTableChange(networkSource.Item1, networkPath, data, NotifyFlags.NotifyUpdate); } } }