Mvvmcross: Extend fluent binding to allow dynamic indexed property expressions

Created on 26 Dec 2013  路  10Comments  路  Source: MvvmCross/MvvmCross

When using this binding:

var index = 0;
set.Bind(view).For(s => s.DataContext).To(vm => vm.NewsFeedItems[index]);

It does not work.

But this one works OK:

set.Bind(view).For(s => s.DataContext).To("NewsFeedItems["+index+"]");

Also this one works OK:

set.Bind(view).For(s => s.DataContext).To(vm => vm.NewsFeedItems[0]);
feature up-for-grabs

All 10 comments

Just linking some information that Stuart itself pointed out in StackOverflow (similar requirement for a different project): https://stackoverflow.com/questions/13082976/extracting-the-current-value-of-an-instance-variable-while-walking-an-expression/13083397#13083397

I've done some tests on Android and it seems to be working:

On the VM I added an ObservableCollection named Test with some values
and on the view I've added 4 TextView to a list and bound them to the Test property testing the next things which worked perfectly even when changing the values of the observable collection:

1.- Index from a for variable
```c#
var sett = this.CreateBindingSet();
for(int i = 0; i < 4; i++)
sett.Bind(this.textViews[i]).For(v => v.Text).To(vm => vm.Test[i]);
sett.Apply();

2.- Index from a for local variable that performs some math previously
```c#
var sett = this.CreateBindingSet<RootView, RootViewModel>();
for (int i = 0; i < 4; i++)
{
        var index = i + 45;
        index -= 45;
        sett.Bind(this.textViews[i]).For(v => v.Text).To(vm => vm.Test[index]);
}
sett.Apply();

3.- Index from a variable outside the for
```c#
var sett = this.CreateBindingSet();
var index = -1;
for (int i = 0; i < 4; i++)
{
index++;
sett.Bind(this.textViews[i]).For(v => v.Text).To(vm => vm.Test[index]);
}
sett.Apply();

4.- Index from a property of the VM
```c#
var sett = this.CreateBindingSet<RootView, RootViewModel>();
for (int i = 0; i < 4; i++)
{
    sett.Bind(this.textViews[i]).For(v => v.Text).To(vm => vm.Test[this.ViewModel.TestIndex]);
}
sett.Apply();

Something that didn't work was using test case 4 and after applying the binding change the TestIndex property to see if the binding gets updated. This index binding only takes the value of the index at the time of applying the binding so changing the index property after that does not change the binding itself, e.g.

```c#
var sett = this.CreateBindingSet();
for (int i = 0; i < 4; i++)
{
sett.Bind(this.textViews[i]).For(v => v.Text).To(vm => vm.Test[this.ViewModel.TestIndex]);
}
sett.Apply();

this.ViewModel.TestIndex += 1;
```

I'm not sure whether there is a practical use for the latest case but if it's worth I can give it a try to see if I can add that feature

@fedemkr Awesome! Does the Fluent- unsupported scenario work in Tibet? If it doesn't work, I think we can just close this issue.

TL;DR : Yes @fedemkr please, implement indexed binding, including for dictionaries

I'm exploring how to implement the basic pattern of MobX (https://mobx.js.org/getting-started.html) for managing application state in C# for Xamarin. Anyone interested in frontend app architecture ought to read up on it. MVVMCross users will recognise the core idea as simply a central app state class with a bunch of interdependant bound properties that views can then bind to, and everything is kept in sync.
I've done similar in Ember.js, which has very powerful binding built in, and with the flexibility of javascript enables effectively macros for different kinds of binding.
The challenge for using the MobX pattern in MVVMCross right now is, largely the need for full indexed binding, as @fedemkr mentions as not yet implemented.

Here is a simple example of what I am wanting to do (using Fody.PropertyChanged) :

[AddINotifyPropertyChangedInterface]
class AppCache {
    ObservableDictionary<string,Product> AllProduct {get; set}
}

[AddINotifyPropertyChangedInterface]
class AppState {

    AppCache AppCache {get; set;}
    string MyProductId {get; set;}
    Product MyProduct {get; set;}

    public AppState(AppCache appCache) {
        var sett = this.CreateBindingSet<AppState, AppCache>();
        sett.Bind(this.MyProduct).For(v => s.MyProduct).To(c => c.AllProduct[MyProductId]);
    }
}

class ProductPageModel {
    AppState AppState {get; set;}
}

This would mean that if and when :

  1. Products are loaded from the server and inserted into AllProduct with the id as key AND
  2. MyProductId is set to the id of a loaded Product

then MyProduct would automatically change to the selected Product.

The view can then be bound something like {{Binding AppState.MyProduct.name}}

There are other scenarios needed, such as selecting multiple Products with multiple ids.

After using binding systems in Adobe Flex, Ember and Xamarin I reckon this is the way forward for managing app state on the front end.

Any comments?

@nmilcoff did you have any more input on this issue?

@buzzware does the thumbs up mean that you'd like to see work done on this?

Yes I would, for the reasons above. I say this knowing I don't have capacity myself for the foreseeable future and I don't have advanced experience in C# eg. expressions and when I tried to setup to play with it, I was told I can't on a Mac #2608

@buzzware I don't develop on Mac so can't answer whether it's possible yet or not. @martijn00 do you know whether the recent updates to VS Mac have fixed the build for mvvmcross?
@nmilcoff do you have any thoughts on this topic?

Sorry for the delayed answer, I'll look into it and see if I can add this feature 馃槃

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ssepulveda picture ssepulveda  路  5Comments

prin53 picture prin53  路  4Comments

Cheesebaron picture Cheesebaron  路  4Comments

StephenBeirlaen picture StephenBeirlaen  路  4Comments

merckxite picture merckxite  路  4Comments