RenderTransform в WPF вызывает неожиданные изменения макета - PullRequest
1 голос
/ 15 марта 2012

Я пытаюсь анимировать несколько фигур в пределах визуальной кисти, но когда я выполняю вращение, «импульс» формы.Я предполагаю, что при вращении фигур ограничивающие рамки заставляют проход макета.Однако, поскольку я использую RenderTransform, я не ожидал, что это вызовет изменения макета.

Этот код иллюстрирует проблему:

<Window x:Class="WpfApplication1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Height="200" Width="200">
<StackPanel>
    <Border BorderBrush="Red" BorderThickness="1"
            Height="100" Width="100">
        <Border.Triggers>
            <EventTrigger RoutedEvent="FrameworkElement.Loaded">
                <BeginStoryboard>
                    <Storyboard RepeatBehavior="Forever" >
                        <DoubleAnimationUsingKeyFrames Storyboard.TargetName="inner_Ellipse"
                            Storyboard.TargetProperty="(UIElement.RenderTransform).(RotateTransform.Angle)">
                            <LinearDoubleKeyFrame KeyTime="0:0:3" Value="-360"/>
                        </DoubleAnimationUsingKeyFrames>
                    </Storyboard>
                </BeginStoryboard>
                <BeginStoryboard>
                    <Storyboard  RepeatBehavior="Forever" >
                        <DoubleAnimationUsingKeyFrames Storyboard.TargetName="outer_Ellipse"
                            Storyboard.TargetProperty="(UIElement.RenderTransform).(RotateTransform.Angle)">                                             
                            <LinearDoubleKeyFrame KeyTime="0:0:3" Value="360"/>
                        </DoubleAnimationUsingKeyFrames>
                    </Storyboard>
                </BeginStoryboard>
            </EventTrigger>
        </Border.Triggers>
        <Border.Background>
            <VisualBrush Stretch="Uniform">
                <VisualBrush.Visual>                      
                    <Canvas Width="20" Height="20">
                        <Ellipse x:Name="outer_Ellipse" 
                                 Stroke="Blue" StrokeThickness="1"   
                                 Width="20" Height="20" 
                                 RenderTransformOrigin="0.5,0.5">
                            <Ellipse.RenderTransform>
                                    <RotateTransform/>
                            </Ellipse.RenderTransform>
                        </Ellipse>
                        <Ellipse  x:Name="inner_Ellipse" 
                                  Stroke="Red" StrokeThickness="1"
                                  Width="18" Height="18" 
                                  Margin="1,1,0,0"
                                  RenderTransformOrigin="0.5,0.5">
                            <Ellipse.RenderTransform>
                                    <RotateTransform/>
                            </Ellipse.RenderTransform>
                        </Ellipse>
                    </Canvas>
                </VisualBrush.Visual>
            </VisualBrush>
        </Border.Background>
    </Border>
</StackPanel>

Это простой примергораздо более сложного приложения, в котором я использую визуальные кисти для декорирования двумерных плоскостей, которыми манипулируют в 3d.Все работает хорошо, пока я не попробую анимировать кисти.Я пробовал несколько разных подходов, но всегда сталкивался с этой проблемой макета.

Любые предложения приветствуются.

Спасибо

Роб

Ответы [ 2 ]

2 голосов
/ 16 марта 2012

Мне удалось отследить причину вашей проблемы. Это связано с настройкой Stretch="Uniform" Property на вашем VisualBrush. Похоже, что фреймворк вычисляет ограничивающий прямоугольник на вашем VisuaBrush.Visual, а затем растягивает его до размера Border.Background. Следующий код должен иллюстрировать поведение. Я вынул ваш inner_Ellipse и добавил external_Rectangle, который должен имитировать растяжение ограничивающего прямоугольника:

<Window x:Class="WpfApplication1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Height="200" Width="200">
    <StackPanel>
        <Border BorderBrush="Red" BorderThickness="1"
            Height="100" Width="100">
            <Border.Triggers>
                <EventTrigger RoutedEvent="FrameworkElement.Loaded">                
                    <BeginStoryboard>
                        <Storyboard  RepeatBehavior="Forever" >
                            <DoubleAnimationUsingKeyFrames Storyboard.TargetName="outer_Rectangle"
                            Storyboard.TargetProperty="(UIElement.RenderTransform).(RotateTransform.Angle)">
                                <LinearDoubleKeyFrame KeyTime="0:0:6" Value="360"/>
                            </DoubleAnimationUsingKeyFrames>
                        </Storyboard>
                    </BeginStoryboard>
                    <BeginStoryboard>
                        <Storyboard  RepeatBehavior="Forever" >
                            <DoubleAnimationUsingKeyFrames Storyboard.TargetName="outer_Ellipse"
                            Storyboard.TargetProperty="(UIElement.RenderTransform).(RotateTransform.Angle)">
                                <LinearDoubleKeyFrame KeyTime="0:0:6" Value="360"/>
                            </DoubleAnimationUsingKeyFrames>
                        </Storyboard>
                    </BeginStoryboard>
                </EventTrigger>
            </Border.Triggers>
            <Border.Background>
                <VisualBrush Stretch="Uniform">
                    <VisualBrush.Visual>
                        <Canvas Width="20" Height="20">
                            <Ellipse x:Name="outer_Ellipse" 
                                 Stroke="Blue" StrokeThickness="1"   
                                 Width="20" Height="20" 
                                 RenderTransformOrigin="0.5,0.5">
                                <Ellipse.RenderTransform>
                                    <RotateTransform/>
                                </Ellipse.RenderTransform>
                            </Ellipse>
                            <Rectangle x:Name="outer_Rectangle" 
                                 Stroke="Blue" StrokeThickness="1"   
                                 Width="20" Height="20" 
                                 RenderTransformOrigin="0.5,0.5">
                                <Rectangle.RenderTransform>
                                    <RotateTransform/>
                                </Rectangle.RenderTransform>
                            </Rectangle>
                        </Canvas>
                    </VisualBrush.Visual>
                </VisualBrush>
            </Border.Background>
        </Border>
    </StackPanel>
</Window>

Что касается решения проблемы, я не уверен. Одним из способов было бы использовать Stretch="None" на вашем VisualBrush, но это не кажется идеальным, потому что тогда вам приходится иметь дело с размером вашего содержимого VisualBrush.Visual.

0 голосов
/ 17 марта 2012

Ну, после долгих проб и ошибок у меня есть рабочее решение. Содержимое VisualBrush корректно масштабируется и не вызывает проблему ограничивающего прямоугольника:

<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    SizeToContent="WidthAndHeight" >
<StackPanel>
    <Border BorderBrush="Black" BorderThickness="1"
        Height="400" Width="400">
        <Border.Triggers>
            <EventTrigger RoutedEvent="FrameworkElement.Loaded">
                <BeginStoryboard>
                    <Storyboard RepeatBehavior="Forever" >
                        <DoubleAnimationUsingKeyFrames Storyboard.TargetName="inner_Ellipse"
                        Storyboard.TargetProperty="(UIElement.RenderTransform).(RotateTransform.Angle)">
                            <LinearDoubleKeyFrame KeyTime="0:0:3" Value="-360"/>
                        </DoubleAnimationUsingKeyFrames>
                    </Storyboard>
                </BeginStoryboard>
                <BeginStoryboard>
                    <Storyboard  RepeatBehavior="Forever" >
                        <DoubleAnimationUsingKeyFrames Storyboard.TargetName="outer_Ellipse"
                        Storyboard.TargetProperty="(UIElement.RenderTransform).(RotateTransform.Angle)">
                            <LinearDoubleKeyFrame KeyTime="0:0:3" Value="360"/>
                        </DoubleAnimationUsingKeyFrames>
                    </Storyboard>
                </BeginStoryboard>
            </EventTrigger>
        </Border.Triggers>

        <Border.Background>
            <VisualBrush Stretch="UniformToFill">
                <VisualBrush.Visual>
                    <Border BorderBrush="Transparent" BorderThickness="1"
                            Width="200" Height="200">
                        <StackPanel Width="200" Height="200">
                            <Canvas>
                                <Rectangle x:Name="outer_Ellipse" 
                                        Stroke="Blue" StrokeThickness="1"   
                                        Width="20" Height="200" 
                                           Canvas.Left="40"
                                        RenderTransformOrigin="0.5,0.5">
                                    <Rectangle.RenderTransform>
                                        <RotateTransform/>
                                    </Rectangle.RenderTransform>
                                </Rectangle>
                                <Ellipse x:Name="inner_Ellipse" 
                                         Stroke="Red" StrokeThickness="1"
                                         StrokeDashArray="2"
                                         Canvas.Top="30"
                                         Canvas.Left="20"
                                        Width="200" Height="200" 
                                        RenderTransformOrigin="0.5,0.5">
                                    <Ellipse.RenderTransform>
                                        <RotateTransform/>
                                    </Ellipse.RenderTransform>
                                </Ellipse>
                            </Canvas>
                        </StackPanel>
                    </Border>
                </VisualBrush.Visual>
            </VisualBrush>
        </Border.Background>
    </Border>
</StackPanel>
</Window>

Похоже, что «секрет» заключает в себе холст, содержащий содержимое кисти, в StackPanel и заключает его в рамку. (Grid, DockPanel и WrapPanel также будут работать вместо StackPanel).

                        <Border BorderBrush="Transparent" BorderThickness="1"
                            Width="200" Height="200">
                        <StackPanel Width="200" Height="200">

Граница должна иметь набор BorderBrush и BorderThickness. Также они оба должны иметь явную ширину и высоту. Здесь я установил значения, соответствующие контенту, чтобы он правильно масштабировался.

Без всех 3 из этих компонентов возникает проблема с ограничивающей рамкой. Ясно, что что-то в политиках расположения контейнеров имеет значение, но я понятия не имею, что и почему.

Совсем не удовлетворительное решение, и я был бы признателен, если бы кто-нибудь смог пролить свет на то, что здесь происходит.

По крайней мере, это работает, как в приведенной выше демонстрации, так и в моем основном приложении, так или иначе!

Rob

...