OnPropertyChanged() 仅通过手动编辑 TextBox 触发
OnPropertyChanged() only triggered by manually editing a TextBox
我需要一个绑定到 ClassA 的文本框,显示来自 ClassB 的两个对象的变量之和。
如果我尝试手动编辑文本框,它只会更改其值。我的问题是我不知道如何在 ClassA 中实现一个方法来监听 ClassB 中的变量是否发生变化。我试图使 ClassB 成为 ClassA 的子类,但随后我得到一个 WhosebugException,所以它不起作用。
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));
}
}
}
使用 INotifyPropertyChanged
和 WPF PropertyChangedEventManager
让 ClassA
监听其每个 ClassB
对象。当其中任何一个的 Var
属性 发生变化时,ClassA
可以为其 Sum
属性 引发 PropertyChanged
事件。例如,您可以为 class A 编写一个构造函数来完成
public ClassA()
{
PropertyChangedEventManager.AddHandler(
MyClassB1,
(_,_) => OnPropertyChanged(nameof(Sum)),
nameof(ClassB.Var));
PropertyChangedEventManager.AddHandler(
MyClassB2,
(_,_) => OnPropertyChanged(nameof(Sum)),
nameof(ClassB.Var));
}
但是有一个问题:你有 public setter ClassA.Sum
。如果 Sum
应该是每两个 ClassB.Var
值的相加,这怎么可能起作用?你怎么往另一个方向走?
每次有人设置 ClassA.Sum
时,您必须以某种方式在两个 ClassB
之间划分新的总和,或者下次有人调用 getter 时,该值会改变返回。
我不知道这是怎么回事。
您可以使用 Action
.
A 类:
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));
}
B 类:
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();
}
}
}
我需要一个绑定到 ClassA 的文本框,显示来自 ClassB 的两个对象的变量之和。 如果我尝试手动编辑文本框,它只会更改其值。我的问题是我不知道如何在 ClassA 中实现一个方法来监听 ClassB 中的变量是否发生变化。我试图使 ClassB 成为 ClassA 的子类,但随后我得到一个 WhosebugException,所以它不起作用。
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));
}
}
}
使用 INotifyPropertyChanged
和 WPF PropertyChangedEventManager
让 ClassA
监听其每个 ClassB
对象。当其中任何一个的 Var
属性 发生变化时,ClassA
可以为其 Sum
属性 引发 PropertyChanged
事件。例如,您可以为 class A 编写一个构造函数来完成
public ClassA()
{
PropertyChangedEventManager.AddHandler(
MyClassB1,
(_,_) => OnPropertyChanged(nameof(Sum)),
nameof(ClassB.Var));
PropertyChangedEventManager.AddHandler(
MyClassB2,
(_,_) => OnPropertyChanged(nameof(Sum)),
nameof(ClassB.Var));
}
但是有一个问题:你有 public setter ClassA.Sum
。如果 Sum
应该是每两个 ClassB.Var
值的相加,这怎么可能起作用?你怎么往另一个方向走?
每次有人设置 ClassA.Sum
时,您必须以某种方式在两个 ClassB
之间划分新的总和,或者下次有人调用 getter 时,该值会改变返回。
我不知道这是怎么回事。
您可以使用 Action
.
A 类:
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));
}
B 类:
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();
}
}
}