2009-06-22 24 views
3

當我嘗試在運行時更改CroppedBitmap的SourceRect屬性時,沒有任何反應。沒有錯誤,並且屬性值實際上不會被更改。嘗試在運行時更改CroppedBitmap的SourceRect

我想做精靈動畫。我有一個包含Spritesheet的BitmapSource,它是一個包含精靈不同姿勢網格的單個位圖。然後我有一個CroppedBitmap,它有Spritesheet作爲它的Source,並有一個SourceRect將其中一個姿勢從spritesheet中拉出來。在運行時,當我想要動畫時,我試圖改變CroppedBitmap的SourceRect屬性,從較大的位圖中拉出不同的姿勢;但是,如上所述,新的財產價值根本不存在。這是最奇怪的事情。

這是一些示例XAML:

<UserControl.Resources> 
    <BitmapImage x:Key="spritesheet" UriSource="Sprites/elf.png"/> 
</UserControl.Resources> 
<Image> 
    <Image.Source> 
     <CroppedBitmap x:Name="image" Source="{StaticResource spritesheet}" 
         SourceRect="240 640 240 320"/> 
    </Image.Source> 
</Image> 

而隱藏代碼試圖做到這一點:

var newRect = new Int32Rect(...); 
Debug.WriteLine("    Before: " + image.SourceRect); 
Debug.WriteLine("Assigning new value: " + newRect); 
image.SourceRect = newRect; 
Debug.WriteLine("    After: " + image.SourceRect); 

這給了我這調試輸出:

   Before: 240,640,240,320 
Assigning new value: 240,0,240,320 
       After: 240,640,240,320 

所以它的實際分配新的矩形(Y = 0)進入屬性;沒有例外;但之後,房產價值根本沒有變化(Y仍然是640)。

關於爲什麼發生這種情況以及如何解決它的任何想法?

回答

14

我最終找到了答案。從CroppedBitmap的文檔:

CroppedBitmap實現ISupportInitialize接口以優化多個屬性的初始化。屬性更改只能在對象初始化期間發生。調用BeginInit指示初始化已經開始,EndInit指示初始化已完成。初始化後,屬性更改被忽略。(重點煤礦)

只是爲了好玩,我嘗試添加BeginInit在().. EndInit()調用我的方法,看是否這將使它修改。毫不奇怪,我得到了一個InvalidOperationException(「不能多次設置初始化狀態」)。

所以CroppedBitmap實際上是不可變的。(但他們忽略了自己的可凍結系統,這將拋出一個異常,告訴我,我做錯了什麼,並實現更多的東西,而不是surprising

這意味着,在改變與sourceRect物業不走。我需要爲Spritesheet中的每個子圖像創建一個單獨的CroppedBitmap實例。

+0

+1在我拿到之前一年回答我的問題。 :) – chaosTechnician 2010-11-09 21:32:15

6

這裏是處理這個的另一種方法:
而不是使用一個CroppedBitmap的,使用完整的源圖像,但:

  1. image.RenderTransform調整可視區域。
  2. 必要時設置Image.Clip,以避免顯示不需要的圖像部分。

這意味着您不需要繼續製作新的CroppedBitmaps,只需調整轉換即可。
在我的測試中,我發現無論哪種方式,速度都沒有差異。

爲了完整起見,這裏就是我會調整自己的代碼做什麼,我建議:

<Image RenderTransform="1, 0, 0, 1, -240, -640"> 
    <!-- Still include your Image.Source here, just not as a CroppedBitmap --> 
    <Image.Clip> 
    <RectangleGeometry Rect="0, 0, 240, 320" /> 
    </Image.Clip> 
</Image> 

那麼以後調用做調整SourceRect相當於是:

image.RenderTransform = new MatrixTransform(1d, 0d, 0d, 1d, -240d, 0d); 
+0

感謝分享+1,這是我能找到的最佳解決方案。我只是在代碼中進行了一些修改:`image.RenderTransform = new TranslateTransform(-rect.X,-rect.Y);` – 2016-01-08 09:18:58

0

下面是使用IMultiValueConverter方式:

<Image> 
    <Image.Source> 
     <MultiBinding Converter="{x:Static local:SourceAndRectToCroppedBitmapConverter.Default}"> 
      <Binding Path="FileName" /> 
      <Binding Path="CropRect" /> 
     </MultiBinding> 
    </Image.Source> 

using System; 
using System.Globalization; 
using System.Windows; 
using System.Windows.Data; 
using System.Windows.Media; 
using System.Windows.Media.Imaging; 

public class SourceAndRectToCroppedBitmapConverter : IMultiValueConverter 
{ 
    public static readonly SourceAndRectToCroppedBitmapConverter Default = new SourceAndRectToCroppedBitmapConverter(); 

    private static readonly ImageSourceConverter Converter = new ImageSourceConverter(); 

    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) 
    { 
     if (values[0] is string text) 
     { 
      return new CroppedBitmap((BitmapSource)Converter.ConvertFrom(values[0]), (Int32Rect)values[1]); 
     } 

     return new CroppedBitmap((BitmapSource)values[0], (Int32Rect)values[1]); 
    } 

    object[] IMultiValueConverter.ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) 
    { 
     throw new NotSupportedException(); 
    } 
} 

潛在的不良perf。