Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Fixing problem with exception not being pushed to OnError method.

  • Loading branch information...
commit 60982dcad9481f1d1a9585b1a429bf4cc702ecf3 1 parent b8b0d24
StanislawSwierc authored
3  CodeBinding.Rx/CodeBinding.Rx.csproj
@@ -42,6 +42,9 @@
42 42 <Reference Include="WindowsBase" />
43 43 </ItemGroup>
44 44 <ItemGroup>
  45 + <Compile Include="ObservableValueConverter.cs" />
  46 + <Compile Include="ObservableValueConverterBase.cs" />
  47 + <Compile Include="ObservableMultiValueConverter.cs" />
45 48 <Compile Include="ObservableBindingTarget.cs" />
46 49 <Compile Include="ObservableEx.cs" />
47 50 <Compile Include="Properties\AssemblyInfo.cs" />
50 CodeBinding.Rx/ObservableEx.cs
@@ -29,16 +29,56 @@ public static IObservable<TResult> Create<TResult>(Expression<Func<TResult>> exp
29 29
30 30 // Create binding
31 31 var binding = BindingEx.FromExpression(expression);
  32 + IObservable<TResult> observableConverter = null;
  33 + if (binding is Binding)
  34 + {
  35 + var single = (Binding)binding;
  36 + if (single.Converter != null)
  37 + {
  38 + // Create intercepting converter
  39 + var converter = new ObservableValueConverter<TResult>(single.Converter);
  40 + // Replace original converter
  41 + single.Converter = converter;
  42 + observableConverter = converter;
  43 + }
  44 + }
  45 + else if (binding is MultiBinding)
  46 + {
  47 + var multi = (MultiBinding)binding;
  48 + // Create intercepting converter
  49 + var converter = new ObservableMultiValueConverter<TResult>(multi.Converter);
  50 + // Replace original converter
  51 + multi.Converter = converter;
  52 + observableConverter = converter;
  53 + }
  54 + else
  55 + {
  56 + // Only Binding and MultiBinding classes are supported
  57 + throw new InvalidOperationException("Invalid binding type");
  58 + }
32 59
33 60 return Observable.Create<TResult>(observer =>
34 61 {
35 62 // Create target object
36 63 var target = new ObservableBindingTarget<TResult>();
37   - target.SetBinding(ObservableBindingTarget<TResult>.ValueProperty, binding);
38   - return new CompositeDisposable(
39   - target.Subscribe(observer),
40   - target
41   - );
  64 + if (observableConverter != null)
  65 + {
  66 + var subscription = observableConverter.Subscribe(observer);
  67 + // Binding has to be set in order to enable converter
  68 + target.SetBinding(ObservableBindingTarget<TResult>.ValueProperty, binding);
  69 + return new CompositeDisposable(
  70 + target,
  71 + subscription
  72 + );
  73 + }
  74 + else
  75 + {
  76 + target.SetBinding(ObservableBindingTarget<TResult>.ValueProperty, binding);
  77 + return new CompositeDisposable(
  78 + target.Subscribe(observer),
  79 + target
  80 + );
  81 + }
42 82 }
43 83 );
44 84 }
46 CodeBinding.Rx/ObservableMultiValueConverter.cs
... ... @@ -0,0 +1,46 @@
  1 +using System;
  2 +using System.Collections.Generic;
  3 +using System.Linq;
  4 +using System.Text;
  5 +using System.Windows.Data;
  6 +using System.Windows;
  7 +using System.Reactive.Disposables;
  8 +using System.Diagnostics.Contracts;
  9 +
  10 +namespace CodeBinding.Rx
  11 +{
  12 + internal class ObservableMultiValueConverter<T> : ObservableValueConverterBase<T>, IMultiValueConverter
  13 + {
  14 + private IMultiValueConverter m_Inner;
  15 +
  16 + public ObservableMultiValueConverter(IMultiValueConverter converter)
  17 + {
  18 + Contract.Requires(converter != null);
  19 +
  20 + m_Inner = converter;
  21 + }
  22 +
  23 + #region IMultiValueConverter Implementation
  24 +
  25 + public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
  26 + {
  27 + try
  28 + {
  29 + object result = m_Inner.Convert(values, targetType, parameter, culture);
  30 + SendNext((T)result);
  31 + }
  32 + catch (Exception ex)
  33 + {
  34 + SendError(ex);
  35 + }
  36 + return DependencyProperty.UnsetValue;
  37 + }
  38 +
  39 + public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
  40 + {
  41 + throw new InvalidOperationException();
  42 + }
  43 +
  44 + #endregion
  45 + }
  46 +}
46 CodeBinding.Rx/ObservableValueConverter.cs
... ... @@ -0,0 +1,46 @@
  1 +using System;
  2 +using System.Collections.Generic;
  3 +using System.Linq;
  4 +using System.Text;
  5 +using System.Windows.Data;
  6 +using System.Windows;
  7 +using System.Reactive.Disposables;
  8 +using System.Diagnostics.Contracts;
  9 +
  10 +namespace CodeBinding.Rx
  11 +{
  12 + internal class ObservableValueConverter<T> : ObservableValueConverterBase<T>, IValueConverter
  13 + {
  14 + private IValueConverter m_Inner;
  15 +
  16 + public ObservableValueConverter(IValueConverter converter)
  17 + {
  18 + Contract.Requires(converter != null);
  19 +
  20 + m_Inner = converter;
  21 + }
  22 +
  23 + #region IValueConverter Implementation
  24 +
  25 + public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
  26 + {
  27 + try
  28 + {
  29 + object result = m_Inner.Convert(value, targetType, parameter, culture);
  30 + SendNext((T)result);
  31 + }
  32 + catch (Exception ex)
  33 + {
  34 + SendError(ex);
  35 + }
  36 + return DependencyProperty.UnsetValue;
  37 + }
  38 +
  39 + public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
  40 + {
  41 + throw new NotImplementedException();
  42 + }
  43 +
  44 + #endregion
  45 + }
  46 +}
71 CodeBinding.Rx/ObservableValueConverterBase.cs
... ... @@ -0,0 +1,71 @@
  1 +using System;
  2 +using System.Collections.Generic;
  3 +using System.Linq;
  4 +using System.Text;
  5 +using System.Windows.Data;
  6 +using System.Windows;
  7 +using System.Reactive.Disposables;
  8 +using System.Diagnostics.Contracts;
  9 +
  10 +namespace CodeBinding.Rx
  11 +{
  12 + internal abstract class ObservableValueConverterBase<T> : IObservable<T>
  13 + {
  14 + private Action<T> m_OnNext;
  15 + private Action<Exception> m_OnError;
  16 +
  17 + protected void SendNext(T value)
  18 + {
  19 + var handler = m_OnNext;
  20 + if (handler != null)
  21 + {
  22 + handler(value);
  23 + }
  24 + }
  25 +
  26 + protected void SendError(Exception error)
  27 + {
  28 + Action<Exception> handler = null;
  29 + lock (this)
  30 + {
  31 + // Save current subscribers
  32 + handler = m_OnError;
  33 +
  34 + // Remove all subscribers
  35 + m_OnError = null;
  36 + m_OnNext = null;
  37 +
  38 + }
  39 + if (handler != null)
  40 + {
  41 + handler(error);
  42 + }
  43 + }
  44 +
  45 + public IDisposable Subscribe(IObserver<T> observer)
  46 + {
  47 + Contract.Requires(observer != null);
  48 +
  49 + // Lock to make sure m_OnNext and m_OnError are managed together
  50 + lock (this)
  51 + {
  52 + m_OnNext += observer.OnNext;
  53 + m_OnError += observer.OnError;
  54 + }
  55 +
  56 + return Disposable.Create(() =>
  57 + {
  58 + // Check if handlers have been cleared already
  59 + if (m_OnError != null)
  60 + {
  61 + lock (this)
  62 + {
  63 + m_OnNext -= observer.OnNext;
  64 + m_OnError -= observer.OnError;
  65 + }
  66 + }
  67 + }
  68 + );
  69 + }
  70 + }
  71 +}

0 comments on commit 60982dc

Please sign in to comment.
Something went wrong with that request. Please try again.