0
votes

I want to implement a dynamic UI where TextBox controls will be created dynamically, and their content bound to a Dictionary on the ViewModel.

I'm trying to implement two-way data binding using ReactiveUI.

The issue I'm facing is that I only seem to be allowed to bind the TextBoxes to an entry in the Dictionary if I use a literal string as the key, but as soon as I try to use a string variable to setup the binding, I get the following error:

Index expressions are only supported with constants.

Here is a very simplified sample of what I'm trying to do. The TextBox is not dynamically instantiated in order to isolate the problem:

string PropNum = "22017";
this.Bind(ViewModel, vm => vm.ExcelData[PropNum], view => view.tbCreate.Text);

In this example, ExcelData is a Dictionary<string, object> defined on the ViewModel.

On the other hand, the following works fine:

this.Bind(ViewModel, vm => vm.ExcelData["22017"], view => view.tbCreate.Text);

I need the lookup key to be a variable. Any ways to achieve this result?

Thanks

1

1 Answers

0
votes

No you can't do what you want with Bind()

We use Expression> to determine where the binding should come from. As the error message said you have to use constants if you want to use indexes.

To give you an idea what the Expression is doing, Expression allows you to use details about a lambda a user provides.

this.Bind(this.ViewModel, vm => vm.Property1.Property2.Property3)

With Expression's you get details about each property/object along the way.

What we do is subscribe to each object along the way's PropertyChanged event (if the object is not null), and we'll also set values appropriately to the other property.

Expression have a limitation of having to be constant since it's mostly a compile time feature.

In terms of what you want to achieve you'll have to do everything after your dynamic value. So you can subscribe to the PropertyChange events once you've resolved the ExcelData index.

You can potentially use WhenAnyValue() on the resolved object,

myViewModel.ExcelData[propertyIndex].WhenAnyValue(x => x.Value).BindTo(this.ViewModel, view => view.TextBox.Text);
this.WhenAnyValue(view => view.TextBox.Text).BindTo(myViewModel.ExcelData[propertyIndex], x => x.Value);

You need the two BindTo due to it being OneWayOnly, and I've used the assumption you have a Value property on your ExcelData object.

Be aware your ExcelData object contained at the propertyIndex must also be derived off INotifyPropertyChanged