如何中和继承的变换?

时间:2016-05-10 11:56:27

标签: .net wpf

对于包含DataTemplate(替换以前使用的Popup btw)的项目,我有一个复杂的ToolTip。对于一个用例(appart of 3 others),DataTemplateItemsControl中使用,ScaleTransform本身可以通过使用PopUp从25%缩放到400%。 现在(新)ToolTip也被缩放(但<StackPanel> <Grid> <Grid.LayoutTransform> <ScaleTransform ScaleX="2" ScaleY="4"/> </Grid.LayoutTransform> <ToggleButton Name="btn1" Content="btn1" ToolTip="hello1" Padding="5"/> <Popup IsOpen="{Binding IsChecked, ElementName=btn1}" StaysOpen="True"> <TextBlock Background="Lime" Padding="10" Text="pop1!"/> </Popup> </Grid> <Grid> <Grid.LayoutTransform> <RotateTransform Angle="25"/> </Grid.LayoutTransform> <ToggleButton Name="btn2" Content="btn2" ToolTip="hello2" Padding="5"/> <Popup IsOpen="{Binding IsChecked, ElementName=btn2}" StaysOpen="True"> <TextBlock Background="Lime" Padding="10" Text="pop2!"/> </Popup> </Grid> <Grid> <Grid.LayoutTransform> <TransformGroup> <RotateTransform Angle="25"/> <ScaleTransform ScaleX="2" ScaleY="4"/> </TransformGroup> </Grid.LayoutTransform> <ToggleButton Name="btn3" Content="btn3" ToolTip="hello3" Padding="5"/> <Popup IsOpen="{Binding IsChecked, ElementName=btn3}" StaysOpen="True"> <TextBlock Background="Lime" Padding="10" Text="pop3!"/> </Popup> </Grid> </StackPanel> 不是),我不希望这种情况发生。

由于某种原因,似乎只传播了比例变换,旋转变换不是:

#ifndef BACKBUFFER_H
#define BACKBUFFER_H

#include <Windows.h>


class BackBuffer
{
public:
    BackBuffer(HWND hWnd, int width, int height);
    ~BackBuffer();

    HDC getDC();

    int width();
    int height();

    void present();

private:
    // Make copy constructor and assignment operator private
    // so client cannot copy BackBuffers.  We do this because
    // this class is not designed to be copied because it
    // is not efficient--copying bitmaps is slow (lots of memory).
    // In addition, most applications will probably only need one
    // BackBuffer anyway.  
    BackBuffer(const BackBuffer& rhs);
    BackBuffer& operator=(const BackBuffer& rhs);
private:
    HWND    mhWnd;
    HDC     mhDC;
    HBITMAP mhSurface;
    HBITMAP mhOldObject;
    int     mWidth;
    int     mHeight;
};


#endif //BACKBUFFER_H

1 个答案:

答案 0 :(得分:2)

选项1:将Popup置于LayoutTransform的影响范围之外

您可以在转换的网格之外定义Popup并直接引用PlacementTarget,如下所示:

<Grid>
    <Grid.LayoutTransform>
        <TransformGroup>
            <RotateTransform Angle="25"/>
            <ScaleTransform ScaleX="2" ScaleY="4"/>
        </TransformGroup>
    </Grid.LayoutTransform>
    <ToggleButton Name="btn3" Content="btn3" ToolTip="hello3" Padding="5"/>
</Grid>
<Popup IsOpen="{Binding IsChecked, ElementName=btn3}" StaysOpen="True" 
    PlacementTarget="{Binding ElementName=btn3}">
    <TextBlock Background="Lime" Padding="10" Text="pop3!"/>
</Popup>

选项2:手动反转LayoutTransform

或者,如果你想保持当前的布局,你可以应用&#34;反向&#34; Transformation的{​​{1}}:

Popup

但在这种情况下,更好的选择是编写一个BindingConverter,为你做到这一点。

选项3:自动反转LayoutTransform

<Popup.LayoutTransform>
    <ScaleTransform ScaleX="0.5" ScaleY="0.25"/>
</Popup.LayoutTransform>
public class TransformInverter : IValueConverter
{
    public object Convert(object value, Type targetType, 
        object parameter, CultureInfo culture)
    {
        Transform transform = value as Transform;
        if (transform == null) 
            return Transform.Identity;
        return transform.Inverse;
    }

    public object ConvertBack(object value, Type targetType, 
        object parameter, CultureInfo culture)
    {
        return DependencyProperty.UnsetValue;
    }
}

选项4:遍历VisualTree并撤消所有转换

现在这个在大多数情况下都可能有点过分,但也许它正是你想要的:将转换器绑定到Popup本身,遍历VisualTree,存储所有LayoutTransforms并使用逆转换取消它们。然而,这种方式有一个很大的缺陷:如果转换能够随着时间的推移而改变,那么它将无法工作。长话短说:

<Grid>
    <Grid.LayoutTransform>
        <TransformGroup>
            <RotateTransform Angle="25"/>
            <ScaleTransform ScaleX="2" ScaleY="4"/>
        </TransformGroup>
    </Grid.LayoutTransform>
    <ToggleButton Name="btn3" Content="btn3" ToolTip="hello3" Padding="5"/>
    <Popup IsOpen="{Binding IsChecked, ElementName=btn3}" StaysOpen="True"
           LayoutTransform="{Binding 
           RelativeSource={RelativeSource AncestorType=Grid}, 
           Path=LayoutTransform, 
           Converter={StaticResource TransformInverter}}">
        <TextBlock Background="Lime" Padding="10" Text="pop3!"/>
    </Popup>
</Grid>

并像这样使用它:

public class TransformResetter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        FrameworkElement transformedElement = value as FrameworkElement;
        if(transformedElement == null)
            return DependencyProperty.UnsetValue;

        Stack<Transform> transformations = new Stack<Transform>();

        FrameworkElement currentElement = transformedElement;
        while (currentElement != null)
        {
            currentElement = VisualTreeHelper.GetParent(currentElement) as FrameworkElement;
            if (currentElement != null)
            {
                if (currentElement.LayoutTransform != null)
                    transformations.Push(currentElement.LayoutTransform);
            }
        }

        TransformGroup group = new TransformGroup();
        while (transformations.Count > 0)
        {
            group.Children.Add(transformations.Pop());
        }

        return group.Inverse;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return DependencyProperty.UnsetValue;
    }
}

选项5:附加在已打开时重置LayoutTransform的属性

基本上与每次弹出窗口打开时执行的选项4相同:

<Popup IsOpen="{Binding IsChecked, ElementName=btn3}" StaysOpen="True"
    LayoutTransform="{Binding 
        RelativeSource={RelativeSource Self}, 
        Converter={StaticResource TransformResetter}}">
    <TextBlock Background="Lime" Padding="10" Text="pop3!"/>
</Popup>

用法:

public class PopupOptions
{
    public static readonly DependencyProperty CancelTransformationsProperty = DependencyProperty.RegisterAttached(
        "CancelTransformations", typeof(bool), typeof(PopupOptions), new PropertyMetadata(default(bool), OnCancelTransformationsPropertyChanged));

    private static void OnCancelTransformationsPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        Popup element = (Popup)d;
        if ((bool)e.NewValue)
        {
            element.Opened += PopupChanged;
            RefreshTransform(element);
        }
        else
        {
            element.Opened -= PopupChanged;
        }
    }

    private static void PopupChanged(object sender, EventArgs eventArgs)
    {
        RefreshTransform(sender as FrameworkElement);
    }

    private static void RefreshTransform(FrameworkElement transformedElement)
    {
        if (transformedElement == null)
            return;

        Stack<Transform> transformations = new Stack<Transform>();

        FrameworkElement currentElement = transformedElement;
        while (currentElement != null)
        {
            currentElement = VisualTreeHelper.GetParent(currentElement) as FrameworkElement;
            if (currentElement == null) continue;

            if (currentElement.LayoutTransform != null)
                if (!currentElement.LayoutTransform.Value.IsIdentity)
                    transformations.Push(currentElement.LayoutTransform);
        }

        TransformGroup transformGroup = new TransformGroup();
        while (transformations.Count > 0)
        {
            transformGroup.Children.Add(transformations.Pop());
        }

        Debug.WriteLine(transformGroup.Children[0].Value);

        transformedElement.LayoutTransform = (Transform)transformGroup.Inverse;
    }

    public static void SetCancelTransformations(DependencyObject element, bool value)
    {
        if (!(element is Popup))
            throw new Exception("Nope!");

        element.SetValue(CancelTransformationsProperty, value);
    }

    public static bool GetCancelTransformations(DependencyObject element)
    {
        return (bool) element.GetValue(CancelTransformationsProperty);
    }
}

背景资讯

未应用<Popup IsOpen="{Binding IsChecked, ElementName=btn3}" StaysOpen="True" yourNameSpace:PopupOptions.CancelTransformations="True"> <TextBlock Background="Lime" Padding="10" Text="pop3!"/> </Popup> 的原因是RotateTransformAllowsTransparency。如果没有这个,Popup必须保持矩形。如果将其设置为false,则也会应用旋转。