private static void RefreshBinding(AvaloniaObject target, AvaloniaProperty property) { if (target.GetValue(property) is IBinding binding) { target.Bind(property, binding); } }
/// <summary> /// Initializes a new binding. /// </summary> /// <param name="avaloniaObject">The <see cref="AvaloniaObject"/> to apply the new binding to.</param> /// <param name="avaloniaProperty">The <see cref="AvaloniaProperty{TValue}"/> the new binding should be applied to.</param> /// <param name="defaultValue">The default value of the <paramref name="avaloniaProperty"/> at <c>1.0</c> scaling.</param> public virtual void Initialize(AvaloniaObject avaloniaObject, AvaloniaProperty <T> avaloniaProperty, T defaultValue) { if (!isInitialized) { subscription = avaloniaObject.Bind(avaloniaProperty, source); DefaultValue = defaultValue; isInitialized = true; } }
private void AddBinding <T>(string modelFieldName, AvaloniaObject control, AvaloniaProperty <T> property, bool isTwoWayDataBinding = false) { // (ideas from here)[http://avaloniaui.net/docs/binding/binding-from-code] var bindingSource = new Subject <T>(); control.Bind <T>(property, bindingSource.AsObservable()); bool bindingIsDataContext = false; object dataContext = null; // does model contain a datacontext??? if (this.Model.HasKey(SpecialModelKeys.DataContext)) { // bind to the data context dataContext = this.Model[SpecialModelKeys.DataContext]; if (dataContext is System.ComponentModel.INotifyPropertyChanged prop) { // It's INotifyPropertyChanged so set this as handled bindingIsDataContext = true; // need to fire it's current value. Then start watching for changes var currentValue = getDataContextValue(dataContext, modelFieldName); log.Debug( $"AddBinding-Model Value Change [*Initial* Field: {modelFieldName}; New Value: {currentValue}]"); FireOnNextWithValue <T>(bindingSource, currentValue); prop.PropertyChanged += (_s, _args) => { if (string.Equals(_args.PropertyName, modelFieldName, StringComparison.OrdinalIgnoreCase)) { var newCurrentValue = getDataContextValue(dataContext, modelFieldName); log.Debug($"AddBinding-Model Value Change [Field: {modelFieldName}; New Value: {newCurrentValue}]"); FireOnNextWithValue <T>(bindingSource, newCurrentValue); } }; } else { /* * !!REMEMBER!! You can use the bindabledictionary * If you don't want to go to the trouble of implementing INotifyPropertyChanged just have your items use BindableDictionary and it's pretty easy */ throw new Exception( $"Special DataContext used in model, but DataContext is not INotifyPropertyChanged. [modelFileName: {modelFieldName}] Type given is {dataContext?.GetType().Name ?? "null"}. There is no way to read properties without INotifyPropertyChanged"); } } if (!bindingIsDataContext) { notifyOnModelChange(modelFieldName, (val) => { FireOnNext <T>(bindingSource, modelFieldName); }); } // If they say two way then we setup a watch on the property observable and apply the values back to the model if (isTwoWayDataBinding) { // monitor for Property changes on control var controlValueChangesObservable = control.GetObservable(property); controlValueChangesObservable.Subscribe(newVal => { if (newVal == null) { // there is never a situation where the UI would need to make a model property null right??? return; } log.Debug($"AddBinding-TwoWay-Control Value Change [Control Property: {property.Name}; Field: {modelFieldName}; New Value: {newVal}]"); setModelValue(modelFieldName, newVal); }); } // end of AddBinding }