在使用带有数据绑定概念的WPF开发的MVVM应用程序中,我想从一个视图中获取TextBox.Text值以进行一些更改(计算)并将其显示在位于其他视图中的TextBox中?是否可以直接沟通,或者我必须通过List<>输入?
谢谢!
答案 0 :(得分:0)
问题:我们有一个带有两个子视图模型的主视图模型,我们希望子视图模型各自相互更新一些与另一个相似的属性。我们说每个人都有一个名为Value
的属性,我们希望ChildA.Value
与ChildB.Value
保持同步。为了增加皱纹,我们不希望价值相同;我们希望每个人都与另一个人保持任意关系。也许一个是摄氏温度,另一个很难拼写。诸如此类的事情。
值得庆幸的是,这是一个以视图模型为中心的设计,因此现有的代码不会与我们作斗争。
如果这些是正确设计的视图模型,它们将从实现INotifyPropertyChanged
的公共基类派生,并且当它们的属性值发生变化时,它们会引发PropertyChanged
。我正在调用基类ViewModelBase
,但它可以是任何东西。我也假设它是用C#6编写的,所以OnPropertyChanged()
方法(引发PropertyChanged
)可以用不带参数调用的方式编写。
我们要做的是让主视图模型负责管理孩子之间的关系。孩子们不知道这种关系存在,因为这样的横向依赖通常以泪水结束。让每个班级都担心自己的属性及其子级属性。因此,MainViewModel
是唯一负责担心ChildA
和ChildB
之间关系的班级。
由于ChildA
和ChildB
都实现INotifyPropertyChanged
,我们可以使用它来管理关系。
public class MainViewModel : ViewModelBase
{
public MainViewModel()
{
ChildA.PropertyChanged += ChildA_PropertyChanged;
ChildB.PropertyChanged += ChildB_PropertyChanged;
}
public static readonly double ConversionFactor = 2000.0 / 4.5;
private void ChildA_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == nameof(ChildA.Value))
{
ChildB.Value = ChildA.Value * ConversionFactor;
}
}
private void ChildB_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == nameof(ChildB.Value))
{
ChildA.Value = ChildB.Value / ConversionFactor;
}
}
public ChildAViewModel ChildA { get; } = new ChildAViewModel();
public ChildBViewModel ChildB { get; } = new ChildBViewModel();
}
public class ChildAViewModel : ViewModelBase
{
private double _value = 0.0;
public double Value
{
get { return _value; }
set
{
// This "if" is important: If the value is not changing, we must
// not raise PropertyChanged, because that will put us in an
// infinite recursive loop.
if (value != _value)
{
_value = value;
OnPropertyChanged();
}
}
}
}
public class ChildBViewModel : ViewModelBase
{
private double _value = 0.0;
public double Value
{
get { return _value; }
set
{
if (value != _value)
{
_value = value;
OnPropertyChanged();
}
}
}
}
这是另一种方法:我们可以为每个子视图模型类提供一个ValueChanged
事件。这是比上述更多的初步工作,但是一旦完成初步工作,有些人会发现它更清洁,更方便,当然更自我记录。
在将C#6 nameof
运算符添加到该语言之前,上述PropertyChanged
版本受到"魔法字符串危险"更改属性名称与引用属性名称的字符串文字不同步。许多商店仍在使用C#5进行生产。在我工作的地方,我们已经付出了很多努力来减轻这种风险;人们仍然沉默地嘀咕着关于2014年的Ed's Magic String Jihad"。
public class MainViewModel : ViewModelBase
{
public MainViewModel()
{
ChildA.ValueChanged += (s, e) => ChildB.Value = e.NewValue * ConversionFactor;
ChildB.ValueChanged += (s, e) => ChildA.Value = e.NewValue / ConversionFactor;
}
public static readonly double ConversionFactor = 2000.0 / 4.5;
public ChildAViewModel ChildA { get; } = new ChildAViewModel();
public ChildBViewModel ChildB { get; } = new ChildBViewModel();
}
public class ValueChangedEventArgs<T> : EventArgs {
public ValueChangedEventArgs(T oldValue, T newValue)
{
OldValue = oldValue;
NewValue = newValue;
}
public T OldValue;
public T NewValue;
}
public class ChildAViewModel : ViewModelBase
{
public event EventHandler<ValueChangedEventArgs<double>> ValueChanged;
private double _value = 0.0;
public double Value
{
get { return _value; }
set
{
// This "if" is important: If the value is not changing, we must
// not raise PropertyChanged, because that will put us in an
// infinite recursive loop.
if (value != _value)
{
var args = new ValueChangedEventArgs<double>(_value, value);
_value = value;
ValueChanged?.Invoke(this, args);
OnPropertyChanged();
}
}
}
}
public class ChildBViewModel : ViewModelBase
{
public event EventHandler<ValueChangedEventArgs<double>> ValueChanged;
private double _value = 0.0;
public double Value
{
get { return _value; }
set
{
if (value != _value)
{
var args = new ValueChangedEventArgs<double>(_value, value);
_value = value;
ValueChanged?.Invoke(this, args);
OnPropertyChanged();
}
}
}
}
答案 1 :(得分:0)
我不确定它是否是最好的方法,但通常我使用Application.Properties。
有关详情,请参阅this answer。