locked
BindableProperty only updating ViewModel property with default values RRS feed

  • Question

  • User395792 posted

    Hi,

    I have a binding issue in my Xamarin.Forms project with the following setup: * One GenericPage superclass inheriting from ContentPage and containing a BindableProperty * One Page class inheriting from GenericPage with a ViewModel which is bound to the BindableProperty using a OneWayToSource binding mode * One GenericControl superclass inheriting from ContentView and containing a BindableProperty * One Control class inheriting from GenericControl with a ControlViewModel which is bound to the BindableProperty using a OneWayToSource binding mode * An instance of the Control class is embedded in the Page class using XAML and the BindableProperty of GenericControl is bound to the property of the ViewModel using a OneWay binding mode

    Visual representation of this setup:

    I can verify that the "connection" from Page to the BindableProperty of GenericControl indeed works, as the propertyChanged method is invoked in GenericControl with the correct value from the BindableProperty in GenericPage. I can also verify that the "connection" from GenericControl to ControlViewModel is working (at least in the beginning) as the property setter in ControlViewModel is called once with the default value from the BindableProperty in GenericControl.

    However, for some reason, the changes which arrive at the BindableProperty in GenericControl (either the default values from GenericPage or externally set) are not propagated to the ControlViewModel.

    I have created a Repro Project for this issue: github.com/mlxyz/Xamarin-Forms-Binding-Repro

    In the project, pressing the button will change the value of the bindable property in GenericPage. However, the property of the ControlViewModel is not updated for some reason (the top label).

    Why is this the case and how can I fix it?

    Thanks!

    Note: I have also posted this question to stackoverflow: stackoverflow.com/q/62913492/10289094

    Thursday, July 16, 2020 4:11 PM

Answers

  • User382871 posted

    However, the property of the ControlViewModel is not updated for some reason (the top label). I've tested the code and reproduced the issue. The issue is caused by the binding for the custom control page.

    The value of Test property is obtained from the page and set binding for the custom control. <controls:Control Test="{Binding Source={x:Reference Root}, Path=BindingContext.Test, Mode=OneWay}" /> But the following code will set the view's BindingContext to the viewModel class, it's not the same as the page's binding. This is why the top label is always the default when clicking the button. Try to remove the code from the view page. <controls:GenericControl ...> <controls:GenericControl.BindingContext> <viewModels:ControlViewModel /> </controls:GenericControl.BindingContext> <ContentView.Content> ... </ContentView.Content> </controls:GenericControl>

    !

    • Marked as answer by Anonymous Thursday, June 3, 2021 12:00 AM
    Friday, July 17, 2020 6:26 AM
  • User382871 posted

    I would like to have a separate view model for my Control class however, as I have to do some calculations there based on the properties that are passed in from the Page. If you want to set separate viewModel for the control, just set data binding as usual. To update the UI of the contentView in the page, you could use MessagingCenter.

    • Marked as answer by Anonymous Thursday, June 3, 2021 12:00 AM
    Friday, July 17, 2020 10:03 AM

All replies

  • User382871 posted

    However, the property of the ControlViewModel is not updated for some reason (the top label). I've tested the code and reproduced the issue. The issue is caused by the binding for the custom control page.

    The value of Test property is obtained from the page and set binding for the custom control. <controls:Control Test="{Binding Source={x:Reference Root}, Path=BindingContext.Test, Mode=OneWay}" /> But the following code will set the view's BindingContext to the viewModel class, it's not the same as the page's binding. This is why the top label is always the default when clicking the button. Try to remove the code from the view page. <controls:GenericControl ...> <controls:GenericControl.BindingContext> <viewModels:ControlViewModel /> </controls:GenericControl.BindingContext> <ContentView.Content> ... </ContentView.Content> </controls:GenericControl>

    !

    • Marked as answer by Anonymous Thursday, June 3, 2021 12:00 AM
    Friday, July 17, 2020 6:26 AM
  • User395792 posted

    @YelinZh Thank you for your answer! I can indeed confirm, that the text is updated correctly, when I remove the ControlViewModel from the Control.xaml page.

    I would like to have a separate view model for my Control class however, as I have to do some calculations there based on the properties that are passed in from the Page.

    Is that possible?

    Note: I can make it work with the separate view model by adding the following line in the propertyChanged handler in GenericControl: (control.BindingContext as ControlViewModel).ControlViewModelTest = (Vector3)newvalue; But I had thought that this would be automatically done by the binding in Control.

    Friday, July 17, 2020 8:40 AM
  • User382871 posted

    I would like to have a separate view model for my Control class however, as I have to do some calculations there based on the properties that are passed in from the Page. If you want to set separate viewModel for the control, just set data binding as usual. To update the UI of the contentView in the page, you could use MessagingCenter.

    • Marked as answer by Anonymous Thursday, June 3, 2021 12:00 AM
    Friday, July 17, 2020 10:03 AM
  • User395792 posted

    @YelinZh Sorry for the late reply. I did some more research and the problem in my original question appears to be caused by the fact that one bindable property can not be bound to two viewmodel properties at the same time. This means that I cant use bindable properties in the control to relay data from the viewmodel of the page to the viewmodel of the control. I don't really want to use the MessagingCenter for this use case as there arise a couple of other problems (e.g. threading problems as messages are sent from a separate thread initiated by ArKit and potential performance issues as there potentially will be 10s of messages sent per second), but I guess I have not other choice here.

    I will accept your post as the answer but I'm still searching for a better way to solve my issue.

    Monday, July 27, 2020 11:29 AM