将单个属性的各个组件绑定到WPF中的两个独立控件
本文关键字:两个 控件 独立 属性 单个 组件 绑定 WPF | 更新日期: 2023-09-27 18:25:45
我的目标是用两个不同的文本框更新单个Size属性。具体来说,每个组件都连接到一个文本框,该文本框在下面的XAML中突出显示。特别是一行:{Binding Path=Dimensions.Width,……}
private Size _dimension;
public Size Dimensions
{
get { return _dimension; }
set
{
_dimension = value;
OnPropertyChanged("Dimensions");
}
}
我的XAML如下:
<StackPanel HorizontalAlignment="Left" Orientation="Horizontal">
<Label Content="Width" />
<TextBox Width="50" Text="{Binding Path=Dimensions.Width,
Converter={StaticResource myStringToDoubleConverter},
UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"/>
<Label Content="Height" />
<TextBox Width="50" Text="{Binding Path=Dimensions.Height,
Converter={StaticResource myStringToDoubleConverter},
UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"/>
</StackPanel>
我遇到的问题是,当我更改文本框中的文本时,set函数不会被调用。我想原因是我没有提供Size对象,但最多提供一个double,最坏提供一个字符串。我有一个转换器,可以将字符串转换为双精度,但这似乎不是诀窍。我的感觉是多绑定产生了我的解决方案,然而,我看到的所有例子都是将两个字符串组合成第三个控件。我对制作带有附加值的控件不感兴趣,而是更新"复杂"属性的组件。
我知道我可以制作两个"子"属性,一个Height和Width,然后一次更新一个Dimension属性,但似乎应该有一个更优雅的解决方案。
为什么我的文本框不能正确地绑定到Dimension属性的单个组件并相应地更新维度?
构造一个实现INotifyPropertyChanged的包装类似乎太过分了。
public class MySizeClass : Size, INotifyPropertyChanged
如果您在这里使用的Size
类型是WPF提供的类型,即System.Windows.Size
,那么问题是它不是一个类。它是一种值类型(即struct
)。尽管它确实为Width
和Height
提供了setter,但它可能不应该这样做,因为它们没有达到您的预期。
C#也不允许您修改Dimensions.Width
——如果您编写以下内容:
src.Dimensions.Width = 123;
其中src
是包含您在"组件绑定解决方案"中显示的属性定义的类型的实例,您将得到以下错误:
Cannot modify the return value of 'WpfApplication1.Source.Dimensions' because it is not a variable
C#在这里拒绝是因为同样的基本问题阻止了它在WPF中的工作:这是因为Size
是一个值类型。任何检索Dimensions
属性的尝试都将返回该值的全新副本。
当然,C#代码实际上是的缩写
Size dimensions = src.Dimensions;
dimensions.Width = 123;
C#实际上会让你写这个,但如果你尝试一下,你会发现它为什么会阻止你写较短的版本:src.Dimensions.Width
仍然会返回旧值。(此代码所做的是获取src.Dimensions
的副本,将该副本存储在名为dimensions
的局部变量中,然后修改该局部变量,使原始变量保持不变。)
基本上,没有办法获得对Size
实例的引用,即Dimensions
属性返回的引用——您只能获得该值的副本。更新它的唯一方法是在它的位置写一个全新的Size
。这就是为什么不能单独修改Width
或Height
的原因。
试图用转换器解决这个问题是行不通的,因为问题不在于你试图写入目标的值。问题是,您想要写入不可访问的目标,即值类型的特定属性。只有当目标属性是对象的属性而不是值时,绑定才能写入目标属性。
(原则上,微软本可以让WPF检测到这一点,让它读取Dimensions
属性,修改它获得的值的副本,然后将修改后的值写回Dimensions
。尽管在这种情况下这很方便,但与数据绑定通常处理属性更新的方式相比,这也将是一个重大变化。我认为他们最好不要尝试,因为它可以很容易地掩盖其他问题。)
在C#中,当您有一个包含Size
值的局部变量或字段时,您可以写入单个属性,因为该变量或字段表示该值的特定实例。字段、局部变量、ref
或out
自变量和数组元素是特殊的,因为实际上可以使用它们原位保存的值。但在浏览属性时不能这样做。同样的原因是,如果定义了List<Size>
,就不能编写myList[0].Width = 123;
,即使这对数组来说很好。
在任何情况下,可变值类型都是有问题的,原因有很多,而不仅仅是这些。他们通常不受欢迎,不幸的是,WPF只运送了一些。
如果WPF能够绑定到字段,那么您就可以随心所欲了。但事实并非如此,所以你不能。
这是组件绑定解决方案,它确实非常好用。
private Double m_Width;
public Double Width
{
get { return (Dimensions.Width); }
set
{
m_Width = value;
Dimensions= new Size(m_Width, m_Height);
}
}
private Double m_Height;
public Double Height
{
get { return (Dimensions.Height); }
set
{
m_Height = value;
Dimensions= new Size(m_Width, m_Height);
}
}
private Size _dimension;
public Size Dimensions
{
get { return _dimension; }
set
{
_dimension = value;
OnPropertyChanged("Dimensions");
}
}
似乎直接绑定到Dimensions.Width是WPF支持的东西。