Skip to content

Commit

Permalink
change ReadOnlyBindableReactiveProperty dependancy property to 'Curre…
Browse files Browse the repository at this point in the history
…ntValue' from 'Value'
  • Loading branch information
Funkest committed Feb 29, 2024
1 parent 1e7f4d4 commit a54ece2
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 27 deletions.
20 changes: 12 additions & 8 deletions sandbox/WpfApp1/MainWindow.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,21 @@
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.DataContext>
<!--<local:BasicUsagesViewModel />-->
<!--<local:ValidationViewModel />-->
<local:CommandViewModel />
<local:BasicUsagesViewModel />
<!--<local:ValidationViewModel />
<local:CommandViewModel />-->
</Window.DataContext>
<!--<StackPanel>
<StackPanel>
<TextBlock Text="Basic usages" FontSize="24" />
<Label Content="Input" />
<TextBox Text="{Binding Input.Value, UpdateSourceTrigger=PropertyChanged}" />
<Label Content="Output" />
<Label Content="BindableReactiveProperty.Value" />
<TextBlock Text="{Binding Output.Value}" />
</StackPanel>-->
<Label Content="ReadOnlyBindableReactiveProperty.CurrentValue" />
<TextBlock Text="{Binding OutputRO.CurrentValue}" />
<TextBlock Text="{Binding OutputRO2.CurrentValue}" />
<Button Content="add" Command="{Binding AddCommand}" />
</StackPanel>

<!--<StackPanel Margin="10">
<Label Content="Validation" />
Expand All @@ -28,9 +32,9 @@
</StackPanel>-->


<StackPanel Margin="10">
<!--<StackPanel Margin="10">
<Label Content="Command" />
<CheckBox IsChecked="{Binding OnCheck.Value}" />
<Button Content="Btn" Command="{Binding ShowMessageBox}" />
</StackPanel>
</StackPanel>-->
</Window>
15 changes: 15 additions & 0 deletions sandbox/WpfApp1/MainWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,11 +59,26 @@ public class BasicUsagesViewModel : IDisposable
{
public BindableReactiveProperty<string> Input { get; }
public BindableReactiveProperty<string> Output { get; }
public ReadOnlyBindableReactiveProperty<string> OutputRO { get; }
public ReadOnlyBindableReactiveProperty<string> OutputRO2 { get; }
public ReactiveCommand<Unit> AddCommand { get; } = new();

public BasicUsagesViewModel()
{
Input = new BindableReactiveProperty<string>("");
Output = Input.Select(x => x.ToUpper()).ToBindableReactiveProperty("");
var rrp = Input.ToReadOnlyReactiveProperty("");
OutputRO = Input.ToReadOnlyBindableReactiveProperty("");
OutputRO2 = rrp.ToReadOnlyBindableReactiveProperty("");
AddCommand.SubscribeAwait(async (_, _) =>
{
var i = 0;
while (i++ < 10)
{
Input.Value += "@";
await Task.Delay(500);
}
});
}

public void Dispose()
Expand Down
32 changes: 25 additions & 7 deletions src/R3/BindableReactiveProperty.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ public ReadOnlyBindableReactiveProperty(T value, IEqualityComparer<T>? equalityC
public class BindableReactiveProperty<T> : ReadOnlyBindableReactiveProperty<T>, INotifyPropertyChanged, INotifyDataErrorInfo, IBindableReactiveProperty
{
IDisposable? subscription;
bool isReadOnly = false;

public T Value
{
Expand Down Expand Up @@ -82,14 +83,26 @@ public BindableReactiveProperty(T value, IEqualityComparer<T>? equalityComparer)
{
}

// ToBindableReactiveProperty
public BindableReactiveProperty(T value, IEqualityComparer<T>? equalityComparer, bool isReadOnly)
: base(value, equalityComparer)
{
this.isReadOnly = isReadOnly;
}

internal BindableReactiveProperty(Observable<T> source, T initialValue, IEqualityComparer<T>? equalityComparer)
: base(initialValue, equalityComparer)
{
this.subscription = source.Subscribe(new Observer(this));
}

// ToBindableReactiveProperty

public ReadOnlyBindableReactiveProperty<T> ToReadOnlyBindableReactiveProperty(T initialValue = default!)
{
isReadOnly = true;
return this;
}

protected override void DisposeCore()
{
subscription?.Dispose();
Expand Down Expand Up @@ -131,7 +144,7 @@ protected override void OnValueChanged(T value)

if (!validationContext.TryValidateValue(value, errors))
{
ErrorsChanged?.Invoke(this, ValueChangedEventArgs.DataErrorsChanged);
ErrorsChanged?.Invoke(this, ValueChangedEventArgs.GetDataErrorsChangedEventArgs(isReadOnly));

// set is completed(validation does not call before set) so continue call PropertyChanged
}
Expand All @@ -150,12 +163,12 @@ protected override void OnValueChanged(T value)
if (errors != null && errors.Count != 0)
{
errors.Clear();
ErrorsChanged?.Invoke(this, ValueChangedEventArgs.DataErrorsChanged);
ErrorsChanged?.Invoke(this, ValueChangedEventArgs.GetDataErrorsChangedEventArgs(isReadOnly));
}
}
}

PropertyChanged?.Invoke(this, ValueChangedEventArgs.PropertyChanged);
PropertyChanged?.Invoke(this, ValueChangedEventArgs.GetPropertyChangedEventArgs(isReadOnly));
}

// for INotifyDataErrorInfo
Expand Down Expand Up @@ -213,7 +226,7 @@ protected override void OnReceiveError(Exception exception)
errors.Add(new ValidationResult(exception.Message));
}

ErrorsChanged?.Invoke(this, ValueChangedEventArgs.DataErrorsChanged);
ErrorsChanged?.Invoke(this, ValueChangedEventArgs.GetDataErrorsChangedEventArgs(isReadOnly));
}

public BindableReactiveProperty<T> EnableValidation()
Expand Down Expand Up @@ -302,6 +315,11 @@ public bool TryValidateValue(object? value, ICollection<ValidationResult> valida

internal static class ValueChangedEventArgs
{
internal static readonly PropertyChangedEventArgs PropertyChanged = new PropertyChangedEventArgs("Value");
internal static readonly DataErrorsChangedEventArgs DataErrorsChanged = new DataErrorsChangedEventArgs("Value");
static readonly PropertyChangedEventArgs propertyChanged = new PropertyChangedEventArgs("Value");
static readonly PropertyChangedEventArgs propertyChangedReadOnly = new PropertyChangedEventArgs("CurrentValue");
static readonly DataErrorsChangedEventArgs dataErrorsChanged = new DataErrorsChangedEventArgs("Value");
static readonly DataErrorsChangedEventArgs dataErrorsChangedReadOnly = new DataErrorsChangedEventArgs("CurrentValue");

internal static PropertyChangedEventArgs GetPropertyChangedEventArgs(bool isReadOnly) => isReadOnly ? propertyChangedReadOnly : propertyChanged;
internal static DataErrorsChangedEventArgs GetDataErrorsChangedEventArgs(bool isReadOnly) => isReadOnly ? dataErrorsChangedReadOnly : dataErrorsChanged;
}
16 changes: 4 additions & 12 deletions src/R3/ReactivePropertyExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,21 +32,13 @@ public static BindableReactiveProperty<T> ToBindableReactiveProperty<T>(this Obs

public static ReadOnlyBindableReactiveProperty<T> ToReadOnlyBindableReactiveProperty<T>(this Observable<T> source, T initialValue = default!)
{
if (source is ReadOnlyBindableReactiveProperty<T> rrp)
{
return rrp;
}
return source.ToReadOnlyBindableReactiveProperty(EqualityComparer<T>.Default, initialValue);
}

public static ReadOnlyBindableReactiveProperty<T> ToReadOnlyBindableReactiveProperty<T>(this Observable<T> source, IEqualityComparer<T>? equalityComparer, T initialValue = default!)
{
if (source is ReadOnlyBindableReactiveProperty<T> rrp)
{
return rrp;
}
// allow to cast ReactiveProperty<T>
return new ConnectedBindableReactiveProperty<T>(source, initialValue, equalityComparer);
// allow to cast BindableReactiveProperty<T>
return new ConnectedBindableReactiveProperty<T>(source, initialValue, equalityComparer, isReadOnly: true);
}
}

Expand Down Expand Up @@ -88,8 +80,8 @@ internal sealed class ConnectedBindableReactiveProperty<T> : BindableReactivePro
{
readonly IDisposable sourceSubscription;

public ConnectedBindableReactiveProperty(Observable<T> source, T initialValue, IEqualityComparer<T>? equalityComparer)
: base(initialValue, equalityComparer)
public ConnectedBindableReactiveProperty(Observable<T> source, T initialValue, IEqualityComparer<T>? equalityComparer, bool isReadOnly = false)
: base(initialValue, equalityComparer, isReadOnly)
{
this.sourceSubscription = source.Subscribe(new Observer(this));
}
Expand Down

0 comments on commit a54ece2

Please sign in to comment.