绑定OnwayToSource无法按预期工作 - 有哪些替代方案?

时间:2011-10-26 14:39:44

标签: wpf binding mvvm

我有一个业务对象 - 使用DataTemplate将其称为Fish(不是从任何东西派生,即不是DependancyObject)。否则在代码中我需要通过对Fish的引用来了解Fish DataTemplate的TextBlock部分的渲染宽度。没问题,我想。我在Fish类中添加了width和height属性,在我的数据模板中,我使用Mode = OnwayToSource将TextBlock的宽度/高度绑定到这些属性。 问题:设置Fish.width / heigh属性时,Width / Height总是NaN。我试过这个解决方法:
OneWayToSource Binding seems broken in .NET 4.0
但它也不起作用(值总是NaN) 我无法绑定到ActualWidth / ActualHeight,因为它们是只读的(为什么我不能在readonly属性上绑定OnwayToSource !!)
我有哪些替代方案?我是否必须从DependancyObject派生Fish并将我的属性设为DP? XAML:

<DataTemplate DataType="{x:Type p:Fish}">
<Border BorderBrush="Black" BorderThickness="2" >
<TextBlock FontSize="14" TextAlignment="Center" VerticalAlignment="Center"
           Width="{Binding Path=width, Mode=OneWayToSource}"
           Height="{Binding Path=height, Mode=OneWayToSource}" ...

代码:

class Fish {
    public double width { get; set; } // From DataTemplate TextBlock.Width.
    public double height { get; set; } // From DataTemplate TextBlock.Height
}

...
double rendered_width = my_fish.width; // Use the rendered width!

3 个答案:

答案 0 :(得分:3)

我终于意识到你要做的事情,你说得对,它是正确的。但是,WPF不同意。我发现它是problem others had before,但显然是设计上的。即使您只想绑定OneWayToSource,也无法在只读属性上设置绑定。

这是一个同样问题的问题:OneWayToSource binding from readonly property in XAML他们的解决方法是在xaml元素周围放置一个容器(具有读/写宽度/高度),并在该容器上设置绑定。这可能适合你。

在Microsoft Connect上有一个与此相关的未解决的问题,声称它是按设计行为:http://connect.microsoft.com/VisualStudio/feedback/details/540833/onewaytosource-binding-from-a-readonly-dependency-property。有人声称使用转换器的related thread中有一种解决方法。您可以尝试一下,但我不确定它是否适用于您的情况,因为它们的绑定是自定义控件,而不是内置框架元素。

更好

This Solution中,Boogaart提出了一个定义新附加属性的实现(类似于DockPanel.Dock =“Top”),它允许任何元素提供其宽度和高度以供观察:

<TextBlock ...
     SizeObserver.Observe="True"
     SizeObserver.ObservedWidth="{Binding Width, Mode=OneWayToSource}"
     SizeObserver.ObservedHeight="{Binding Height, Mode=OneWayToSource}"

尝试一下,看看它是否合适。

答案 1 :(得分:1)

如果在某种操作后使用这些属性,即按下按钮或单击超链接,则可以通过命令的CommandParameter传入ActualWidth和Height。否则我建议使用触发器,例如这里提供的触发器:

http://expressionblend.codeplex.com/wikipage?title=Behaviors%20and%20Effects&referringTitle=Documentation

我同意OneWayToSource绑定对只读依赖项属性不起作用似乎是违反直觉的。

答案 2 :(得分:1)

尝试绑定OneWay。我认为OneWayToSource意味着要写入源代码。

http://msdn.microsoft.com/en-us/library/system.windows.data.bindingmode.aspx

我做了一个测试,确定Width = NaN,直到宽度为Assigned(set)。我明白这不是你想要的行为。试试这个。在指定宽度的情况下,报告(作为200)。如果未指定宽度,则报告为NaN。但ActualWidth是正确的。 ActualWidth就在那里,但显然你试图让它无法工作。

    <StackPanel Orientation="Vertical">
            <Border BorderThickness="1" BorderBrush="Red">
                <TextBlock Name="tbwidthA" Text="{Binding Path=Howdy}" HorizontalAlignment="Left" Width="200"/>
            </Border>
            <TextBlock Name="tbwidthAw" Text="{Binding ElementName=tbwidthA, Path=Width}"  HorizontalAlignment="Left"/>
            <TextBlock Name="tbwidthAaw" Text="{Binding ElementName=tbwidthA, Path=ActualWidth}" HorizontalAlignment="Left" />
            <Border BorderThickness="1" BorderBrush="Red">
                <TextBlock Name="tbwidthB" Text="{Binding Path=Howdy}" HorizontalAlignment="Left" />
            </Border>
            <TextBlock Name="tbwidthBw" Text="{Binding ElementName=tbwidthB, Path=Width}" HorizontalAlignment="Left" />
            <TextBlock Name="tbwidthAbw" Text="{Binding ElementName=tbwidthB, Path=ActualWidth}" HorizontalAlignment="Left" />
            <Button Content="TBwidth" Click="Button_Click_1" Width="60" HorizontalAlignment="Left" />
        </StackPanel>

有趣的是Button确实报告了正确的ActualWidth但宽度是NaN。

        Debug.WriteLine(tbwidthB.Width.ToString());
        Debug.WriteLine(tbwidthB.ActualWidth.ToString());