Forum Xamarin.Forms

Announcement:

The Xamarin Forums have officially moved to the new Microsoft Q&A experience. Microsoft Q&A is the home for technical questions and answers at across all products at Microsoft now including Xamarin!

To create new threads and ask questions head over to Microsoft Q&A for .NET and get involved today.

How to do math dynamically with databinding in Xamarin.forms and MVVM

mndevelopmentsmndevelopments Member ✭✭
edited October 2020 in Xamarin.Forms

Hello

I'm dynamically changing the value of a textbox depending on a switch value. I'm doing it with setters, but my issue is that one of the values that i want to dynamically change to is a calculation that needs to be done first.

I've tried doing the calculation in my item model with (see the CalculatedValue

    public class Item
    {
        public string Id { get; set; }
        public string Name { get; set; }
        public double UValue { get; set; }
        public string Description { get; set; }
        public bool IsInhomogent { get; set; }
        public double mValue1 { get; set; }
        public double mLampda1 { get; set; }
        public double mValue2 { get; set; }
        public double mLampda2 { get; set; }

        public string NameAndValue
        {
            get { return Name + " λ = " + UValue; }
        }

        public double CalulatedValue
        {
            get { return ((mValue1 * mLampda1) + (mValue2 * mLampda2)) / (mValue1 + mValue2); }
        }
    }

However, this only updates the calculation when I load the table, and I can't do that because it hasn't been saved yet.

How would I do this calculation live, every time mValue1, mLampda1, mValue2 or mLampda2 property is changed?

I tried doing it in my code behind, while loading from the viewmodel with this:

    public ItemDetailViewModel viewModel;

        void WhenTextPropertyChanges(System.Object sender, Xamarin.Forms.TextChangedEventArgs e)
        {
            if (mBredde1.Text == null | mLampda1.Text == null | mBredde2.Text == null | mLampda2.Text == null |
                mBredde1.Text == "" | mLampda1.Text == "" | mBredde2.Text == "" | mLampda2.Text == "")
            {
                return;
            }
            else
            {
                viewModel.UValue = ((double.Parse(mBredde1.Text) * double.Parse(mLampda1.Text))
                    + (double.Parse(mBredde2.Text) * double.Parse(mLampda2.Text)))
                    / (double.Parse(mBredde1.Text) + double.Parse(mBredde2.Text));
            }

        }

But this gives me an error "Exception has been thrown by the target of an invocation." on the line where I navigate to the page where I want this function to be

        await Shell.Current.GoToAsync($"{nameof(ItemDetailPage)}?{nameof(ItemDetailViewModel.ItemId)}={item.Id}");

For now my XAML uses the following setter to determine which value to show in the entry:

<Entry x:Name="UValueEntry" Keyboard="Numeric" Grid.Column="1" Grid.Row="1">
                        <Entry.Triggers>
                            <DataTrigger TargetType="Entry" Binding="{Binding IsInhomogent}" Value="True">
                                <Setter Property="Text" Value="{Binding CalculatedValue, Mode=OneWay}" />
                            </DataTrigger>
                            <DataTrigger TargetType="Entry" Binding="{Binding IsInhomogent}" Value="False">
                                <Setter Property="Text" Value="{Binding UValue}" />
                            </DataTrigger>
                        </Entry.Triggers>
                    </Entry>

I'm struggling with how I could achieve what I want in my MVVM, which is why I've tried in the code behind. I got something that almost worked with the TextChanged eventhandlers, but I can't seem to read og write to the viewmodel containing UValue or CalculatedValue.

Tagged:

Best Answer

Answers

  • YelinzhYelinzh Member, Xamarin Team Xamurai

    However, this only updates the calculation when I load the table, and I can't do that because it hasn't been saved yet.

    This is related to updating the UI at runtime, try using the MVVM mode to set up data binding. Please make the model class to implement the INotifyPropertyChanged interface.Implementing this interface in a view model or model class allows the class to provide change notifications to any data-bound controls in the view when the underlying property value changes.

    Then update the value of 'CalulatedValue' property when each of the four properties is changed.

    Check the code:

    public class CustomModel : INotifyPropertyChanged
    {
        private double mLampda1;
        public double MLampda1
        {
            get
            {
                return mLampda1;
            }
            set
            {
                if (mLampda1 != value)
                {
                    mLampda1 = value;
                    CalulatedValue = ((mValue1 * mLampda1) + (mValue2 * mLampda2)) / (mValue1 + mValue2);
                    NotifyPropertyChanged();
                }
            }
        }
    
        private double calulatedValue;
        public double CalulatedValue
        {
            get
            {
                return calulatedValue;
            }
            set
            {
                if (calulatedValue != value)
                {
                    calulatedValue = value;
                    NotifyPropertyChanged();
                }
            }
        }
    
        protected virtual void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
        public event PropertyChangedEventHandler PropertyChanged;
    }
    
  • mndevelopmentsmndevelopments Member ✭✭
    edited October 2020

    @Jarvan Thank you for your suggestion.

    I'm not getting the wanted behaviour from your code example above though.

    I'm implementing INotifyPropertyChanged in my BaseViewModel, and I tried doing your code in both the model and in my "DetailViewModel", but I'm still not seeing any changes until I save the table, and reload it.

    My item model now looks like this:

       public class Item : INotifyPropertyChanged
        {
            public string Id { get; set; }
            public string Name { get; set; }
            public double UValue { get; set; }
            public string Description { get; set; }
            public bool IsInhomogent { get; set; }
            public string NameAndValue
            {
                get { return Name + " λ = " + UValue; }
            }
    
            public double mValue1;
            public double MValue1
            {
                get
                {
                    return mValue1;
                }
    
                set
                {
                    if (mValue1 != value)
                    {
                        mValue1 = value;
                        CalulatedValue = ((mValue1 * mLampda1) + (mValue2 * mLampda2)) / (mValue1 + mValue2);
                        NotifyPropertyChanged();
                    }
                }
            }
    
            public double mValue2;
            public double MValue2
            {
                get
                {
                    return mValue2;
                }
    
                set
                {
                    if (mValue2 != value)
                    {
                        mValue2 = value;
                        CalulatedValue = ((mValue1 * mLampda1) + (mValue2 * mLampda2)) / (mValue1 + mValue2);
                        NotifyPropertyChanged();
                    }
                }
            }
    
            public double mLampda1;
            public double MLampda1
            {
                get
                {
                    return mLampda1;
                }
    
                set
                {
                    if (mLampda1 != value)
                    {
                        mLampda1 = value;
                        CalulatedValue = ((mValue1 * mLampda1) + (mValue2 * mLampda2)) / (mValue1 + mValue2);
                        NotifyPropertyChanged();
                    }
                }
            }
    
            public double mLampda2;
            public double MLampda2
            {
                get
                {
                    return mLampda2;
                }
    
                set
                {
                    if (mLampda2 != value)
                    {
                        mLampda2 = value;
                        CalulatedValue = ((mValue1 * mLampda1) + (mValue2 * mLampda2)) / (mValue1 + mValue2);
                        NotifyPropertyChanged();
                    }
                }
            }
            public double calculatedValue;
            public double CalulatedValue
            {
                get { return ((mValue1 * mLampda1) + (mValue2 * mLampda2)) / (mValue1 + mValue2); }
                set
                {
                    if (calculatedValue != value)
                    {
                        calculatedValue = value;
                        NotifyPropertyChanged();
                    }
                }
            }
    
            protected virtual void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
            {
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
            }
    
            public event PropertyChangedEventHandler PropertyChanged;
        }
    
  • Weird. I'll look at it again, but for now I'm using a more dirty method in my codebehind where I use the TextChanged event to se the value og UValue, and since I'm not unittesting it's a fine solution for me at the moment.

Sign In or Register to comment.