Home > Mobile >  OnPropertyChanged() only triggered by manually editing a TextBox
OnPropertyChanged() only triggered by manually editing a TextBox

Time:03-27

I need a TextBox which is binded to ClassA showing the sum of a variable from two Objects from ClassB. It does only change its Value if i try to edit the TextBox manually. My problem is i dont know how i can implement a method in ClassA which listenes if the variables in ClassB are changed. I tried to make ClassB a SubClass from ClassA but then i get an StackOverflowException so that doesnt work.


MainWindow.xaml


<Window x:Class="INPCTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:INPCTest"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Window.DataContext>
        <local:ClassA/>
    </Window.DataContext>
    <Grid x:Name="BaseGrid" >
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="10"/>
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="10" />
        </Grid.ColumnDefinitions>

        <Grid.RowDefinitions>
            <RowDefinition Height="10"/>
            <RowDefinition Height="*"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <TextBox x:Name="TextBoxClassA" Grid.Row="1" Grid.Column="1" Text="{Binding Sum, UpdateSourceTrigger=PropertyChanged}" />
        <TextBox x:Name="TextBox1ClassB" Grid.Row="2" Grid.Column="1" Text="{Binding MyClassB1.Var, UpdateSourceTrigger=PropertyChanged}" />
        <TextBox x:Name="TextBox2ClassB" Grid.Row="2" Grid.Column="2" Text="{Binding MyClassB2.Var, UpdateSourceTrigger=PropertyChanged}" />
    </Grid>
</Window>

ClassA.cs


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace INPCTest
{
    public class ClassA : ObservableObject
    {

        private decimal _sum;



        public decimal Sum
        {
            get { _sum = MyClassB1.Var   MyClassB2.Var; return _sum; }
            set { _sum = value; OnPropertyChanged();}
        }


        public ClassB MyClassB1 { get; set; } = new ClassB(1);
        public ClassB MyClassB2 { get; set; } = new ClassB(2);

    }
}

ClassB.cs


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace INPCTest
{
    public class ClassB : ObservableObject
    {
        private decimal _var;

        public ClassB(decimal var)
        {
            _var = var;
        }

        public decimal Var
        {
            get { return _var; }
            set { _var = value; OnPropertyChanged();}
        }


    }
}

ObservableObject.cs


using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;

namespace INPCTest
{
    public class ObservableObject : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler? PropertyChanged;

        public void OnPropertyChanged([CallerMemberName] string propertyname = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyname));
        }

    }
}

CodePudding user response:

You can use from Action.

ClassA:

public class ClassA : ObservableObject
{
    private decimal _sum;

    public ClassA()
    {
        MyClassB1 = new ClassB(1) {OnVarChanged = OnVarChange};
        MyClassB2 = new ClassB(2) {OnVarChanged = OnVarChange};
    }

    public decimal Sum
    {
        get { _sum = MyClassB1.Var   MyClassB2.Var; return _sum; }
        set { _sum = value; OnPropertyChanged(); }
    }


    public ClassB MyClassB1 { get; set; }
    public ClassB MyClassB2 { get; set; }

    private void OnVarChange() => OnPropertyChanged(nameof(Sum));
}

ClassB:

public class ClassB : ObservableObject
{
    private decimal _var;

    public ClassB(decimal var)
    {
        _var = var;
    }

    public Action OnVarChanged { get; set; }

    public decimal Var
    {
        get { return _var; }
        set
        {
            _var = value;
            OnPropertyChanged();
            OnVarChanged?.Invoke();
        }
    }

}

CodePudding user response:

Make ClassA listen to each of its ClassB objects using INotifyPropertyChanged and the WPF PropertyChangedEventManager. When the Var property on either one changes, ClassA can raise a PropertyChanged event for its Sum property. For example you might write a constructor for class A to do it

public ClassA()
{
    PropertyChangedEventManager.AddHandler(
        MyClassB1,
        (_,_) => OnPropertyChanged(nameof(Sum)),
        nameof(ClassB.Var));

    PropertyChangedEventManager.AddHandler(
        MyClassB2,
        (_,_) => OnPropertyChanged(nameof(Sum)),
        nameof(ClassB.Var));
}

But there is a problem: You have a public setter for ClassA.Sum. How can that possibly work if Sum is supposed to be the addition of each two ClassB.Var values? How do you go in the other direction?

Each time someone sets ClassA.Sum You would have to divide the new Sum between the two ClassB's somehow or the next time somebody called the getter, the value would change back.

I don't know how that's going to work.

  • Related