WPF - 数据绑定和渲染变换

3
我希望将一个比例转换绑定到一个转换器,传递ActualWidthActualHeight参数。
这是我想要做的事情:
<Canvas x:Name="Canevas">
   <Canvas.RenderTransform>
      <TransformGroup>
         <ScaleTransform 
              ScaleX="{Binding RelativeSource={RelativeSource FindAncestor, 
                               AncestorType={x:Type UIElement}}, 
                               Path=ActualWidth, Mode=OneWay, 
                               Converter={StaticResource ScaleConverter}, 
                               ConverterParameter={Binding Path=ActualWidth}"

              ScaleY="{Binding RelativeSource={RelativeSource FindAncestor,
                               AncestorType={x:Type UIElement}}, 
                               Path=ActualHeight, Mode=OneWay, 
                               Converter={StaticResource ScaleConverter},  
                               ConverterParameter={Binding Path=ActualHeight}}"
         />
      </TransformGroup>
   </Canvas.RenderTransform>

   <Ellipse Canvas.Left="47" Canvas.Top="48" Height="155" 
            Name="ellipse1" Stroke="Black" Width="174" Fill="#FF00C6C3" />

这个问题是这段代码无法编译:

ConverterParameter={Binding Path=ActualHeight}

我希望知道如何将这些属性作为参数移动到我的转换器中?是否可以完全在 Xaml 中解决?

非常感谢您的帮助!

转换器源代码:

public class ScaleConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter,
                                        System.Globalization.CultureInfo culture)
    {
        double v = (double)value;
        var actualSize = (double)parameter; //ActualWidth, ActualHeight

        var vScale = v * (1 + (v / actualSize));

        return vScale;
    }

    public object ConvertBack(object value, Type targetType, object parameter, 
                                        System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

1
你能展示一下你的转换器代码吗?为什么需要ConverterParameter?也许你应该使用IMultiValueConverter和MultiBinding代替... - Thomas Levesque
我添加了转换器源代码。 - Florian
我不确定我理解你想做什么...转换器应该返回一个比例因子,但根据你的公式它将返回一个宽度(或高度)。你到底想实现什么? - Thomas Levesque
3个回答

4
我认为你可以想出一种方法使其工作,通过让ScaleConverter从DependencyObject继承,给它一个ActualSize依赖属性,在你的资源中放置两个实例而不是一个,并进行单向到源绑定,将一个实例的ActualSize绑定到canvas的ActualWidth,另一个实例的ActualHeight(因此实例的ActualSize始终与canvas的宽度/高度保持同步,随着canvas的调整大小)。 然而,看起来你可能真正想要的是一些简单的东西:将画布拉伸以填充其父级。如果是这样的话,请查看Viewbox
<Viewbox Stretch="Fill">
    <Canvas Width="221" Height="203">
        <Ellipse Canvas.Left="47" Canvas.Top="48" Height="155"
                 Stroke="Black" Width="174" Fill="#FF00C6C3" />
    </Canvas>
</Viewbox>

我在Stretch="Fill"中包含了X和Y的拉伸,而不保留宽高比,因为这看起来是您想要的。您还需要为Canvas分配宽度和高度,以使其正常工作,因为Canvas默认没有自然大小。上面的代码片段设置了一个宽度和高度,将您的椭圆放在拉伸的Viewbox的右下角;您可能需要与此不同的内容。
使用Viewbox的一个可能的缺点是描边粗细也会被缩放,因此如果您将窗口变得短而宽,水平线条将变得细,而垂直线条将变得粗。如果这是个问题,您可能需要坚持使用数据绑定。

3

编辑:我的回答只是重构了你的代码,使其能够编译。如果你的解决方案不起作用,那么这个也不会起作用。

不要使用IValueConverter,而是使用IMultiValueConverterMultiBinding。不要将额外的值作为ConverterParameter传递,而是作为额外的绑定传递。

    <Canvas x:Name="Canvas">
        <Canvas.RenderTransform>
            <TransformGroup>
                <!--<ScaleTransform ScaleX="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UIElement}}, Path=ActualWidth, Mode=OneWay, Converter={StaticResource ScaleConverter}, ConverterParameter={Binding Path=ActualWidth}"
                           ScaleY="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UIElement}}, Path=ActualHeight, Mode=OneWay, Converter={StaticResource ScaleConverter}, ConverterParameter={Binding Path=ActualHeight}}" />-->
                <ScaleTransform>
                    <ScaleTransform.ScaleX>
                        <MultiBinding Converter="{StaticResource ScaleConverter}">
                            <Binding RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType={x:Type UIElement}}" Path="ActualWidth" Mode="OneWay"/>
                            <Binding Path="ActualWidth"/>
                        </MultiBinding>
                    </ScaleTransform.ScaleX>
                    <ScaleTransform.ScaleY>
                        <MultiBinding Converter="{StaticResource ScaleConverter}">
                            <Binding RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType={x:Type UIElement}}" Path="ActualHeight" Mode="OneWay"/>
                            <Binding Path="ActualHeight"/>
                        </MultiBinding>
                    </ScaleTransform.ScaleY>
                </ScaleTransform>
            </TransformGroup>
        </Canvas.RenderTransform>
        <Ellipse Canvas.Left="47" Canvas.Top="48" Height="155" Name="ellipse1" Stroke="Black" Width="174" Fill="#FF00C6C3" />
    </Canvas>

还有你的转换器:

public class ScaleConverter : IMultiValueConverter
{

    public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        double v = (double)values[0];
        var actualSize = (double)values[1]; //ActualWidth, ActualHeight

        var vScale = v * (1 + (v / actualSize));

        return vScale;
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

0

非常抱歉,我认为这是不可能的。因为Binding.ConverterParameter不是一个DependencyProperty,所以你无法使用绑定来填充它的值。我之前也尝试过这样做(使用ConverterParameter的绑定),但遇到了你面临的同样问题。


我相信你可以使用反向绑定(例如使用OneWayToSource) - Mark A. Donohoe

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接