程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> WPF Bug清單之(11)——錯位的RenderTransform動畫

WPF Bug清單之(11)——錯位的RenderTransform動畫

編輯:關於.NET

在WPF中制作位移類動畫大致有3種方式,Margin、RenderTransform和 LayoutTransform。雖然3者的效果略有不同,但是不少情況下3種方式可以通用 。但是當你了解到RenderTransform所存在的Bug時,可能就需要考慮一番了。

我們都知道很多控件都有FocusVisualStyle,一般就是一個虛線框。 RenderTransform的問題就在於, 控件的FocusVisualStyle中的元素,不會隨著 控件本身一起被Transform。

Bug的重現過程如下圖所示。

圖1. 程序運行圖

一個簡單得不能再簡單的程序。在空窗體上放一個Button,建立一個動畫, 當MouseEnter這個Button的時候,用RenderTransform把這個Button向右向下移 動100個像素。代碼如下。

Demo Code

 1 <Window  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  2      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  3     x:Class="AnimationConflict.MainWindow"
  4     x:Name="Window" Title="MainWindow"
  5     Width="200" Height="200">
  6     <Window.Resources>
  7         <Storyboard x:Key="OnMouseEnter">
  8             <DoubleAnimationUsingKeyFrames  BeginTime="00:00:00" Storyboard.TargetName="button"
  9                  Storyboard.TargetProperty="(UIElement.RenderTransform). (TranslateTransform.X)">
10                 <SplineDoubleKeyFrame  KeyTime="00:00:01" Value="100"/>
11              </DoubleAnimationUsingKeyFrames>
12             <DoubleAnimationUsingKeyFrames  BeginTime="00:00:00" Storyboard.TargetName="button"
13                  Storyboard.TargetProperty="(UIElement.RenderTransform). (TranslateTransform.Y)">
14                 <SplineDoubleKeyFrame  KeyTime="00:00:01" Value="100"/>
15              </DoubleAnimationUsingKeyFrames>
16         </Storyboard>
17     </Window.Resources>
18     <Window.Triggers>
19         <EventTrigger RoutedEvent="Mouse.MouseEnter"  SourceName="button">
20             <BeginStoryboard  Storyboard="{StaticResource OnMouseEnter}"/>
21         </EventTrigger>
22     </Window.Triggers>
23     <Grid x:Name="LayoutRoot">
24         <Button x:Name="button"  RenderTransformOrigin="0.5,0.5"
25                 HorizontalAlignment="Left"  VerticalAlignment="Top"
26                 Width="75"  Content="Button">
27             <Button.RenderTransform>
28                 <TranslateTransform/>
29             </Button.RenderTransform>
30         </Button>
31     </Grid>
32  </Window>

程序剛運行起來的時候Button是沒有獲得焦點的,我們按幾下Tab鍵,讓這個 Button獲得焦點。如圖2所示。

圖2. Button得到了焦點

然後不要再動任何鍵了,把鼠標移到Button上面以觸發動畫。發現什麼了? 看圖3。

圖3. Focus被Button落下了

當鼠標再次MouseEnterButton時,虛框會被自動放回正確的位置。整個示例 程序可以從這裡下載。運行環境是.NET Framework 3.5 SP1。

初步判斷,這個Bug與WPF對FocusVisualStyle的設計方式有關。這個虛框與 Adorner Layer類似,並不屬於這個Button,所以渲染時沒有被當被Button的一 部分。而RenderTransform是一種純渲染時行為,所以虛框就被無視了。從邏輯 上來講似乎這個Bug很合理,不然會讓Render的設計很復雜,本來Render一個控 件只要關心控件自身就可以了,現在還要關心相關的其它控件。但是我相信以微 軟的水平,應該是有能力解決這個問題的。就像文字渲染模糊的問題,WPF剛出 來就被人诟病,微軟還振振有詞地解釋說這就是WPF的像素無關和理想渲染模型 設計原則的體現。這不到了.NET 4.0最終還是提供了選項關閉WPF的理想渲染模 型。

其實在WPF中類似這樣的問題有很多,比如Validation Error Template、 Popup Window都有類似的問題。沒有為PopupWindow寫一個專題是因為產生Bug的 條件可以避免出現。但是對於這類,動畫與Focus的組合,是很常見的情況。

而且這個問題從WPF的使用者而言是如此底層。到目前為止,我也只想到兩個 不是辦法的辦法。

1.不顯示FocusVisualStyle。

2.不用RenderTransform。

其實這只是回避問題式的方案。不知大家有什麼好的解決方案?

更新解決方案:

根據Curry的回復。目前已經的最佳解決方案是。在Storyboard的 CurrentTimeInvalidated事件處理函數中加入下面的代碼。

AdornerLayer.GetAdornerLayer(button).Update();

這樣Button的行為就正確了。但是大量使用可能導致一些性能問題。當然如 果只有幾個控件應該是沒有問題的。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved