Trouble using WhenAnyValue with WhenAnyObservable - wpf

I'm trying to avoid an update to a property if another property is changing. So I've come up with the following (in my ViewModel):
this.WhenAnyObservable(
x => x.WhenAnyValue( y => y.Asset.CurrentValuation ),
x => x.Changing,
(currentValuation, changing) => changing.PropertyName != "CurrentValuationCalculated"
)
However, ReactiveUI throws the following error inside ExpressionRewriter.VisitMethodCall:
throw new NotSupportedException("Index expressions are only supported with constants.")
If I remove the WhenAnyValue line, it works. So I'm assuming it's something to do with the expression inside WhenAnyValue?
Without delving into what the ExpressionRewriter code actually does, what is it complaining about? Have I made some sort of simple error?
Update
So I've entered this instead:
this.WhenAnyObservable(
x => x.Asset.CurrentValuation,
x => x.Changing,
( currentValuation, changing ) => changing.PropertyName != "CurrentValuationCalculated"
)
However, the compiler complains about x.Asset.CurrentValuation and says:
Cannot implicitly convert type 'decimal?' to 'System.IObservable<ReactiveUI.IReactivePropertyChangedEventArgs<ReactiveUI.IReactiveObject>>'

Short answer is yes.
The longer answer is WhenAnyObservable will provide you the change notification, so you don't really need the WhenAnyValue. You would generally use WhenAnyValue on a ViewModel property to force a subscription to the change notification. The observable sequence is inherently providing change notification via OnNext
Edit
Notice below I am observing an IObservable in the WhenAnyObservable and a view model property in WhenAnyValue. You don't need to unwrap the value in the call to WhenAnyObservable to get the value out.
public class MainViewModel : ReactiveObject
{
private string _property;
public IObservable<bool> MyObservabe { get; }
public string MyProperty { get => _property; set => this.RaiseAndSetIfChanged(ref _property, value); }
public MainViewModel()
{
MyObservabe = Observable.Interval(TimeSpan.FromSeconds(1)).Select(x => x > 5);
this.WhenAnyObservable(x => x.MyObservabe);
this.WhenAnyValue(x => x.MyProperty);
}
}

Related

Is it possible to create a new instance of a command when needed using get in property?

I used next code
private String _Value = "hello";
//Set - just copy from value in _Value with PropertyChanged?.Invoke.
public String Value {get => _Value; set => Set(ref _Value, value);}
public ICommand DoSomeCommand{get => new SomeCommand(value);}
SomeCommand - the class that creates the command object, and saving value data.
get=>new SomeCommand(vale);
Initialize only ones at start of program, and keeps the value as "hello", even if i changed Value.
So i need to create new instance anytime my program calls the given command. As I understand it, all commands are stored in a buffer. But is it possible to have the command create a new instance with a new value when accessed?
For example, when i click on some button(which has this command) any time, new instance DoSomeCommand created and command with new value executed.
Bindings are automatically updated only when the view is initialized or when the source property changes.
So if you want to keep your command implemented this way, you have to manually notify PropertyChanged event for your command when your Value property changes.
Possible implementation (assuming your Set() method returns true if the value changed):
private String _Value = "hello";
public String Value
{
get => _Value;
set =>
{
if (Set(ref _Value, value))
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(DoSomeCommand)));
}
}
}
public ICommand DoSomeCommand
{
get => new SomeCommand(value);
}

Autofixture test for invalid constructor parameter

I have the following class and test. I want to test passing a null value as a parameter to the constructor and are expecting an ArgumentNullException. But since I use the Autofixture's CreateAnonymous method I get a TargetInvocationException instead.
What is the correct way to write those kinds of tests?
public sealed class CreateObject : Command {
// Properties
public ObjectId[] Ids { get; private set; }
public ObjectTypeId ObjectType { get; private set; }
public UserId CreatedBy { get; private set; }
// Constructor
public CreateObject(ObjectId[] ids, ObjectTypeId objectType, UserId createdBy) {
Guard.NotNull(ids, "ids");
Guard.NotNull(objectType, "objectType");
Guard.NotNull(createdBy, "createdBy");
Ids = ids;
ObjectType = objectType;
CreatedBy = createdBy;
}
}
[TestMethod]
[ExpectedException(typeof(ArgumentNullException))]
public void constructor_with_null_ids_throw() {
fixture.Register<ObjectId[]>(() => null);
fixture.CreateAnonymous<CreateObject>();
}
IMO, Ruben Bartelink's comment is the best answer.
With AutoFixture.Idioms, you can do this instead:
var fixture = new Fixture();
var assertion = new GuardClauseAssertion(fixture);
assertion.Verify(typeof(CreateObject).GetConstructors());
The Verify method will provide you with a quite detailed exception message if any constructor argument in any constructor is lacking a Guard Clause.
FWIW, AutoFixture extensively uses Reflection, so I don't consider it a bug that it throws a TargetInvocationException. While it could unwrap all TargetInvocationException instances and rethrow their InnerException properties, that would also mean disposing of (potentially) valuable information (such as the AutoFixture stack trace). I've considered this, but don't want to take AutoFixture in that direction, for exactly that reason. A client can always filter out information, but if information is removed prematurely, no client can get it back.
If you prefer the other approach, it's not too hard to write a helper method that unwraps the exception - perhaps something like this:
public Exception Unwrap(this Exception e)
{
var tie = e as TargetInvocationException;
if (tie != null)
return tie.InnerException;
return e;
}
I came across this while I was searching for something similar. I would like to add that, combined with automoqcustomization and xunit, below code also works and its much cleaner.
[Theory, AutoMoqData]
public void Constructor_GuardClausesArePresent(GuardClauseAssertion assertion)
{
assertion.Verify(typeof(foo).GetConstructors());
}
You just need to create the AutoMoqData attribute as follows.
public class AutoMoqDataAttribute : AutoDataAttribute
{
public AutoMoqDataAttribute() : base(() => new Fixture().Customize(new AutoMoqCustomization()))
{
}
}

One-way updates of columns using EntityFramework

EntityFramework 4.3.1.
What is the best way to have calculated properties which should be stored in db, but are not intended to be retrieved from db?
E.g.
[Column("SOME_COLUMN")]
public ulong SomeColumn
{
get { return /*calculate here*/; }
}
I want the value to be persisted when I'm saving to db. But of course - not getting updated when I load from db. I can have an empty setter alongside... But it doesn't seem to work when the column is Key.
Can I have such a Key-column?
Now I'm getting this error:
EntityFramework error: The value of a property that is part of an object's key does not match the corresponding property value stored in the ObjectContext. This can occur if properties that are part of the key return inconsistent or incorrect values or if DetectChanges is not called after changes are made to a property that is part of the key.
Firstly, make the setter private:
[Column("SOME_COLUMN")]
public ulong SomeColumn { get; private set; }
Secondly, add a calculation method in the object (so it can access the private setter):
public void CaculateSomeColumn(){
this.SomeColumn = /* some calculation */;
}
Thirdly, add a SavingChanges callback to the Repository context object (MyEntities). This callback can be defined in the context constructor, and it should set the calculated field for items of your type (MyPoco) that were added or modified:
public MyEntities(){
this.SavingChanges += (sender, eventArgs) => {
ObjectContext context = sender as ObjectContext;
if (context != null)
{
foreach (ObjectStateEntry entry in
context.ObjectStateManager.GetObjectStateEntries(
EntityState.Added | EntityState.Modified))
{
if (!entry.IsRelationship && (entry.Entity.GetType() == typeof(MyPoco)))
{
var myObject = entry.Entity as MyPoco;
myObject.CalculateSomeColumn();
}
}
}
};
}

Setting the Text property of a DropDownList ComboBox to an invalid value doesn't raise exception?

I'm looking at ways to resolve an issue with a Winforms application, which uses a ComboBox control. Specifically, the ComboBox (Style=DropDownList) is bound to a datasource and, as the user navigates through some other data, the "Text" property of the ComboBox property is set - and the user can select some other value.
The trouble starts when the value I set the "Text" property to is not in the list of available items. It seems that nothing happens. Take the following simple example:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
myComboBox1.DropDownStyle = ComboBoxStyle.DropDownList;
//myComboBox1.Items.AddRange(new[] { "One", "Two", "Three" });
List<KeyValuePair<Int32, String>> values = new List<KeyValuePair<Int32, String>>();
values.Add(new KeyValuePair<Int32, String>(1, "One"));
values.Add(new KeyValuePair<Int32, String>(2, "Two"));
values.Add(new KeyValuePair<Int32, String>(3, "Three"));
myComboBox1.DataSource = values;
myComboBox1.ValueMember = "Key";
myComboBox1.DisplayMember = "Value";
button1.Click += (s, e) => { myComboBox1.Text = "Four"; };
button2.Click += (s, e) => { myComboBox1.SelectedIndex -= 1; };
}
}
public class MyComboBox : System.Windows.Forms.ComboBox
{
public override string Text
{
get { return base.Text; }
set { MessageBox.Show(value); base.Text = value; }
}
}
This technique is used throughout a large application, so when it was noticed that (in the example above) setting the "Text" to "Four" does nothing, I thought that maybe I could trap this and throw an exception. In reality, the application is peppered with code like this:
if (myDataRow.IsBlahNull())
myComboBox1.Text = "";
else
myComboBox1.Text = myDataRow.Blah;
Now, while I appreciate that setting "SelectedIndex = -1" would be better for the "IsNull" case, the fact remains that myDataRow.Blah may not be a valid value. Also, the application is written (and live) so the fewer changes the better.
So, my immediate thought was "let's override the Text property setter and check that the value is in the list". That, it turns out, is nothing like as simple as it would seem. The problem being that the "Text" property is set to all kinds of things, in all kinds of scenarios. For example, it's set when the DataSource property is assigned, or when the SelectedIndex is set to -1. Also, it's set to the string representation of the selected item - so if you happen to have a ComboBox control that's bound to a List of KeyValue pairs, you get the "Text" property set to something like "[Key,Value]". If it's bound to a DataTable/DataView, you get the string representation of the DataRow, and that gets even harder to detect.
It's at this point I thought that there might be another way to achieve the desired result (which is to detect the setting of the Text property to some invalid value - which does nothing).
Any ideas ?
Upon reflection, is this a reasonable work-around ?
/// <summary>
/// Gets or sets the text associated with this control.
/// </summary>
public override string Text
{
get { return base.Text; }
set
{
base.Text = value;
if ((value != null) && (base.Text != value))
if (value == "")
this.SelectedIndex = -1;
else
throw new ArgumentException(String.Format("Cannot set Text property of {0} to \"{1}\".", this.Name, value));
}
}

How to achieve INotifyPropertyChanged functionality for the values in a bool[]?

I have a bool array of size 4 and I want to bind each cell to a different control.
This bool array represents 4 statuses (false = failure, true = success).
This bool array is a propery with a class:
class foo : INotifyPropertyChanged {
...
private bool[] _Statuses;
public bool[] Statuses
{
get {return Statuses;}
set {
Statuses = value;
OnPropertyChanged("Statuses");
}
}
In XAML there are 4 controls, each one bound to one cell of the array:
... Text="{Binding Path=Statuses[0]}" ...
... Text="{Binding Path=Statuses[1]}" ...
... Text="{Binding Path=Statuses[2]}" ...
... Text="{Binding Path=Statuses[3]}" ...
The problem is that the notify event is raised only when I change the array itself and isn't raised when I change one value within the array, i.e, next code line raises the event:
Statuses = new bool[4];
but next line does not raises the event:
Statuses [0] = true;
How can I raise the event each time one cell is changed?
You need to expose your statuses as an indexer, then raise a property change event that indicates that the indexer has changed.
private bool[] _Statuses;
public bool this[int index]
{
get { return _Statuses[index]; }
set
{
_Statuses[index] = value;
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(Binding.IndexerName));
}
}
See this blog post:
http://10rem.net/blog/2010/03/08/wpf---silverlight-quick-tip-inotifypropertychanged-for-indexer
It doesn't raise the event becuase Array itself doesn't implement INotifyPropertyChanged. You can either use a different container than the primitive array (anything that implements INotifyCollectionChanged liked ObservableCollection<T> should do) OR you have to call RaisePropertyChanged("Statuses") each time you update the Statuses array OR, as metioned in another answer, use one class that implement INotifyPropertyChanged that contains 4 properties.
You cannot do it while using an Array. Changing a value at any index on an Array does not raise change notification required by the UI.
Can you use a class with four properties that implements INotifyPropertyChanged interface instead?

Resources