对于包含DataTemplate
(替换以前使用的Popup
btw)的项目,我有一个复杂的ToolTip
。对于一个用例(appart of 3 others),DataTemplate
在ItemsControl
中使用,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
答案 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>
的原因是RotateTransform
为AllowsTransparency
。如果没有这个,Popup必须保持矩形。如果将其设置为false
,则也会应用旋转。