0

我的目标是让一个 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 对象,但充其量是一个双精度对象,最坏情况是一个字符串。我有一个转换器可以将字符串转换为双精度,但这似乎不是诀窍。我的感觉是多重绑定产生了我的解决方案,但是,我看到的所有示例都是将两个字符串组合到第三个控件中。我对制作带有附加值的控件不感兴趣,而是更新我的“复杂”属性的组件。

我知道我可以创建两个“子”属性,一个高度和宽度,然后一次更新一个维度属性,但似乎应该存在一个更优雅的解决方案。

为什么我的文本框没有正确绑定到 Dimension 属性的单个组件并相应地更新维度?

构造一个实现 INotifyPropertyChanged 的​​包装类似乎有些过分。

public class MySizeClass : Size, INotifyPropertyChanged
4

2 回答 2

3

如果Size您在这里使用的类型是 WPF 提供的类型,即System.Windows.Size,那么问题在于它不是一个类。它是一个值类型(即 a struct)。尽管它确实为其Widthand提供了设置器Height,但它可能不应该这样做,因为它们没有按照您的预期进行。

C# 也不允许您修改Dimensions.Width- 如果您编写以下内容:

src.Dimensions.Width = 123;

wheresrc是包含您在“组件绑定解决方案”中显示的那些属性定义的类型的实例,您将收到此错误:

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的。这就是为什么您不能单独修改Widthor的原因Height

尝试使用转换器解决此问题是行不通的,因为问题不在于您尝试写入目标的值。问题是您想要写入一个不可访问的目标,即值类型的特定属性。如果绑定是对象的属性,而不是值,则绑定只能写入目标属性。

(原则上,微软可以让 WPF 检测到这一点,让它读取Dimensions属性,修改它获取的值的副本,然后将修改后的值写回Dimensions. 虽然在这种情况下这很方便,但它也可以数据绑定通常如何处理属性更新的重大变化。我认为他们不尝试可能会更好,因为它很容易掩盖其他问题。)

在 C# 中,当您有一个包含Size值的局部变量或字段时,您当然可以写入单个属性,因为变量或字段表示该值的特定实例。字段、局部变量refout参数以及数组元素是特殊的,因为实际上可以使用它们就地保存的值。但是在浏览属性时你不能这样做。同样的原因是,如果你定义了 aList<Size>你就不能写myList[0].Width = 123;,即使这对数组来说也很好。

无论如何,可变值类型由于各种原因而存在问题,而不仅仅是这个。他们通常不受欢迎,不幸的是 WPF 发布了一些。

如果 WPF 能够绑定到字段,您就可以做您想做的事。但事实并非如此,所以你不能。

于 2013-08-01T17:35:22.140 回答
1

这是组件绑定解决方案,它可以很好地工作。

    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 支持的。

于 2013-08-01T13:53:11.750 回答