Closed ghost closed 9 years ago
As with the other issue, if it's agreed that this is a change this project wants, then I would be happy to contribute the code and do a pull request.
It's very difficult.(ReactiveProperty should inherit from ReadOnlyReactiveProperty)
But I think that this case is follows.
static class MvvmHelpersExtensions
{
public static IObservable<bool> ChangedAsObservable<T>(this ReactiveProperty<T> self, bool skipFirst = true)
{
var result = self.AsObservable();
if (skipFirst)
{
result = result.Skip(1);
}
return result.Select(_ => true);
}
}
class MountainViewModel
{
private Subject<bool> ResetIsDirtySubject { get; } = new Subject<bool>();
public ReactiveProperty<string> Name { get; } = new ReactiveProperty<string>();
public ReactiveProperty<double> HeightInMeters { get; } = new ReactiveProperty<double>();
public ReadOnlyReactiveProperty<bool> IsDirty { get; }
public MountainViewModel()
{
this.IsDirty = Observable.Merge(
this.Name.ChangedAsObservable(),
this.HeightInMeters.ChangedAsObservable(),
this.ResetIsDirtySubject)
.ToReadOnlyReactiveProperty(false);
}
public void ResetDirty()
{
this.ResetIsDirtySubject.OnNext(false);
}
}
Thank you.
How is this solution?
public interface IReadOnlyReactiveProperty
{
object Value { get; }
IObservable<IEnumerable> ObserveErrorChanged { get; }
IObservable<bool> ObserveHasErrors { get; }
}
public interface IReactiveProperty : IReadOnlyReactiveProperty
{
new object Value { get; set; }
}
public interface IReadOnlyReactiveProperty<T> : IReadOnlyReactiveProperty, IObservable<T>, IDisposable, INotifyPropertyChanged
{
new T Value { get; }
}
public interface IReactiveProperty<T> : IReactiveProperty, IReadOnlyReactiveProperty<T>, INotifyDataErrorInfo
{
new T Value { get; set; }
}
public class ReactiveProperty<T> : IReactiveProperty<T> {}
public class ReadOnlyReactiveProperty<T> : IReadOnlyReactiveProperty<T> {}
Thanks for the quick replies!
I prefer a solution that doesn't use new
to hide properties. Here's a possible alternative:
public interface IHasErrors
{
IObservable<IEnumerable> ObserveErrorChanged { get; }
IObservable<bool> ObserveHasErrors { get; }
}
public interface IReadOnlyReactiveProperty<T> : IObservable<T>, IDisposable, INotifyPropertyChanged,
INotifyDataErrorInfo, IHasErrors
{
T Value { get; }
}
public interface IReactiveProperty<T> : IObservable<T>, IDisposable, INotifyPropertyChanged, INotifyDataErrorInfo,
IHasErrors
{
T Value { get; set; }
IReadOnlyReactiveProperty<T> AsReadOnly();
}
public class ReactiveProperty<T> : IReactiveProperty<T>, IReadOnlyReactiveProperty<T>
{
public T Value { get; set; }
public IDisposable Subscribe(IObserver<T> observer)
{
throw new NotImplementedException();
}
public void Dispose()
{
throw new NotImplementedException();
}
public event PropertyChangedEventHandler PropertyChanged;
public IEnumerable GetErrors(string propertyName)
{
throw new NotImplementedException();
}
public bool HasErrors { get; }
public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;
public IObservable<IEnumerable> ObserveErrorChanged { get; }
public IObservable<bool> ObserveHasErrors { get; }
public IReadOnlyReactiveProperty<T> AsReadOnly()
{
return this;
}
}
public abstract class ReadOnlyReactiveProperty<T> : IReadOnlyReactiveProperty<T>
{
public IDisposable Subscribe(IObserver<T> observer)
{
throw new NotImplementedException();
}
public void Dispose()
{
throw new NotImplementedException();
}
public event PropertyChangedEventHandler PropertyChanged;
public IEnumerable GetErrors(string propertyName)
{
throw new NotImplementedException();
}
public bool HasErrors { get; }
public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;
public IObservable<IEnumerable> ObserveErrorChanged { get; }
public IObservable<bool> ObserveHasErrors { get; }
public T Value { get; private set; }
}
The definition of AsReadOnly
negates the need for IReadOnlyReactiveProperty
to inherit from IReactiveProperty
.
I agree to follows step.
public interface IHasErrors {}
public interface IReadOnlyReactiveProperty<T> : IHasErrors {}
public interface IReactiveProperty<T> : IHasErrors {}
But I shouldn't inherit IReactiveProperty from IReadOnlyReactiveProperty. Because this relation isn't "is a".
I understood about this inheritance!
@runceel thank you for reading my code. What do you think about ReactiveProperty
(the class, not the interface) inheriting IReadOnlyReactiveProperty
? Is that acceptable?
I think it's a valid pattern to have code like this:
public interface IReadOnlyPerson
{
string Name { get; }
}
public interface IReadWritePerson
{
string Name { get; set; }
}
public class Person : IReadWritePerson, IReadOnlyPerson
{
public string Name { get; set; }
}
That way, we can use interfaces to ensure that some code can change a person's name and other code can't. This is basically the pattern I wrote up in my previous comment.
I wrote code. Please review.
That looks perfect. Thank you so much!
I released ReactiveProperty v2.2.8. Please check.
private readonly ReactiveProperty<int> _counter = new ReactiveProperty<int>();
public IReadOnlyReactiveProperty<int> Counter => _counter;
It works perfectly! Thanks!
It would be useful if the
ReactiveProperty
class inherited from theReadOnlyReactiveProperty
class. That way, we can have a private ReactiveProperty and a public ReadOnlyReactiveProperty with the same object as their value. This effectively lets us have private setters and public getters, but with a reactive property.Example
As it currently stands, we would have to make the class slightly less readable to accomplish the same effect:
Thank you for your time!