移除或设置 XAML 元素的绝对变换

Removing or setting an absolute transform of XAML Element

我需要一个 XAML 对象总是被缩放 1:1,或者至少是 imagebrush 内容,即使它的父对象在视图框中并且内容在 X 方向被压缩.

一个例子:Viewbox包含Label & ImageBrush。我希望标签文本可以缩放,但只有 ImageBrush 大小 - 缩小时它只会显示内容的顶角。

对象的视图模型无法访问比例因子。我一直在寻找一种方法来删除或重置视图框转换,但一直找不到。是否有一个或我必须将当前比例因子从父视图模型传播到最终视图模型?除非绝对必要,否则我宁愿不在那里混合表示逻辑。

这是目前的 XAML 目前我得到的:

           <ImageBrush ImageSource="{Binding Paint, Mode=OneWay, Converter={StaticResource BitmapToImageSourceConverter}}">
                <ImageBrush.RelativeTransform>
                    <MatrixTransform>
                        <MatrixTransform.Matrix>
                            <MultiBinding Converter="{StaticResource TimelineMatrixConverter}">
                                <Binding />
                                <Binding RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type MatrixTransform}}" Path="Matrix" />
                            </MultiBinding>
                        </MatrixTransform.Matrix>
                    </MatrixTransform>
                </ImageBrush.RelativeTransform>
            </ImageBrush>

这是您可以执行的操作的一个基本示例。首先扩展 Viewbox class:

public class ViewboxEx : Viewbox
{

    private FrameworkElement _child;

    #region InvertScaleH

    /// <summary>
    /// InvertScaleH Read-Only Dependency Property
    /// </summary>
    private static readonly DependencyPropertyKey InvertScaleHPropertyKey
        = DependencyProperty.RegisterReadOnly("InvertScaleH", typeof(double), typeof(ViewboxEx),
            new FrameworkPropertyMetadata((double)1));

    public static readonly DependencyProperty InvertScaleHProperty
        = InvertScaleHPropertyKey.DependencyProperty;

    /// <summary>
    /// Gets the InvertScaleH property. This dependency property 
    /// indicates invert scale factor to compensate for horizontal scale fo the Viewbox.
    /// </summary>
    public double InvertScaleH
    {
        get { return (double)GetValue(InvertScaleHProperty); }
    }

    /// <summary>
    /// Provides a secure method for setting the InvertScaleH property.  
    /// This dependency property indicates invert scale factor to compensate for horizontal scale fo the Viewbox.
    /// </summary>
    /// <param name="value">The new value for the property.</param>
    protected void SetInvertScaleH(double value)
    {
        SetValue(InvertScaleHPropertyKey, value);
    }

    #endregion

    #region InvertScaleV

    /// <summary>
    /// InvertScaleV Read-Only Dependency Property
    /// </summary>
    private static readonly DependencyPropertyKey InvertScaleVPropertyKey
        = DependencyProperty.RegisterReadOnly("InvertScaleV", typeof(double), typeof(ViewboxEx),
            new FrameworkPropertyMetadata((double)1));

    public static readonly DependencyProperty InvertScaleVProperty
        = InvertScaleVPropertyKey.DependencyProperty;

    /// <summary>
    /// Gets the InvertScaleV property. This dependency property 
    /// indicates invert scale factor to compensate for vertical scale fo the Viewbox.
    /// </summary>
    public double InvertScaleV
    {
        get { return (double)GetValue(InvertScaleVProperty); }
    }

    /// <summary>
    /// Provides a secure method for setting the InvertScaleV property.  
    /// This dependency property indicates invert scale factor to compensate for vertical scale fo the Viewbox.
    /// </summary>
    /// <param name="value">The new value for the property.</param>
    protected void SetInvertScaleV(double value)
    {
        SetValue(InvertScaleVPropertyKey, value);
    }

    #endregion

    public ViewboxEx()
    {
        Loaded += OnLoaded;
        SizeChanged += (_,__) => UpdateScale();
    }

    private void OnLoaded(object sender, RoutedEventArgs e)
    {
        UpdateChild();
    }

    protected override void OnVisualChildrenChanged(DependencyObject visualAdded, DependencyObject visualRemoved)
    {
        base.OnVisualChildrenChanged(visualAdded, visualRemoved);

        UpdateChild();
    }

    private void UpdateChild()
    {
        if (_child != null)
        {
            _child.SizeChanged -= OnChild_SizeChanged;
        }
        _child = Child as FrameworkElement;
        if (_child != null)
        {
            _child.SizeChanged += OnChild_SizeChanged;
        }

        UpdateScale();
    }

    private void OnChild_SizeChanged(object sender, SizeChangedEventArgs e)
    {
        UpdateScale();
    }

    private void UpdateScale()
    {
        if (_child == null)
            return;
        SetInvertScaleH(_child.ActualWidth / ActualWidth);
        SetInvertScaleV(_child.ActualHeight / ActualHeight);
    }

}

基本上它所做的就是监听Viewbox的大小和内容的变化,然后计算反转比例因子。现在使用这个比例因子:

<Window x:Class="YourNamespace.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:YourNamespace"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <local:ViewboxEx>
            <Grid Width="100" Height="100">
                <Ellipse Fill="Green"/>
                <TextBlock Text="123" Margin="10,10,0,0">
                    <TextBlock.RenderTransform>
                        <ScaleTransform 
                            ScaleX="{Binding InvertScaleH, RelativeSource={RelativeSource AncestorType={x:Type local:ViewboxEx}}}"
                            ScaleY="{Binding InvertScaleV, RelativeSource={RelativeSource AncestorType={x:Type local:ViewboxEx}}}"/>
                    </TextBlock.RenderTransform>
                </TextBlock>
            </Grid>
        </local:ViewboxEx>
    </Grid>
</Window>

在此示例中,椭圆像往常一样跟随视框大小变化,但文本保持其大小。

这是一个基本的实现,可能并非在所有情况下都有效。