What to do when type conversion in bindings fail?

38 views
Skip to first unread message

James Nugent

unread,
Feb 17, 2014, 5:19:23 AM2/17/14
to reacti...@googlegroups.com
Putting together one of the few data entry screens I have in my app, I noticed the following seems to be a lot harder than it probably should be - am I missing something or if not is there some nice way of making this better in future? The scenario:

ViewModel has an int property and a command which is enabled or disabled based on the value of that property:

public class SomeViewModel : ReactiveObject
{
private int _requiredQuantity;
public int RequiredQuantity
{
get { return _requiredQuantity; }
set { this.RaiseAndSetIfChanged(ref _requiredQuantity, value); }
}

public ReactiveCommand DoStuff { get; private set; }

public SomeViewModel()
{
var canDoStuff = this.WhenAnyValue(vm => vm.RequiredQuantity)
.Select(v => v > 0);

DoStuff = new ReactiveCommand(canDoStuff);
...
}
}

The view has a textbox bound to RequiredQuantity via a reactive binding:

public class SomeView : IViewFor<SomeViewModel>
{
public SomeView()
{
...
this.WhenActivated(d => {
...
d(this.Bind(ViewModel, vm => vm.RequiredQuantity, v => v.RequiredQuantity.Text));
...
});
...
}
}

What I'm trying to sort out the following scenario:

1. User enters valid (numeric) value into the textbox - 12 for example
2. Binding updates, canDoStuff becomes true
3. User enters invalid (textual) value into the textbox - "test" for example
4. RequiredQuantity is still 12, so canDoStuff is still true

The ideal would be for two things to happen:

1. Set a validation error on the control (with a specified error message) if the type conversion fails
2. Allow a "fallback" value for the binding (e.g. set to 0 if type conversion fails so that canDoStuff becomes false)

Is there a better way of doing this than adding a string property to the viewmodel which is bound to the textbox, and hooking up the int version with a subscription to changes in the string property?

Cheers,


James

Richard Banks

unread,
Jun 11, 2015, 12:42:55 AM6/11/15
to reacti...@googlegroups.com
Bump.

I'm trying to do something similar.

In my case I've got a WinForms app (yeah, I know) and I'm only changing the viewmodel properties on Leave

var s = Observable.FromEventPattern(txtValue1, "Leave");

this.Bind(ViewModel, vm => vm.Value2, f => f.txtValue1.Text, s);


Being a text box, I can enter anything. I could restrict key press events so that only digits, period and +/- are enterable but that doesn't stop a user entering an invalid integer format such as 1+-2.


Ideally, if there's a binding conversion failure I want to reset the textbox's text property to either the previous value or a fallback value.


Given conversion failures are silently swallowed by the framework I'm not sure what the best way to expose them is. The converters themselves don't have the context about how they were called so there's nothing obvious I can send back to the view to tell it to refresh/reset the display.


Maybe a BindError object , like UserError, could work and we call BindError.Throw from within the PropertyBinderImplementation class whenever a TryConvert method fails. But even then I'm not really sure how to get the textbox to refresh consistently.


For example, I tried adding a button to the UI (just as a test) that set the ViewModel value to 0. Unsurprisingly the text box refreshed to 0 as expected when the VM.Value1 property was non-zero. If it was already 0 nothing happens as the Value1 property value hasn't actually changed and no observable change occurs.


Any thoughts?

Reply all
Reply to author
Forward
0 new messages