当我尝试在运行时更改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)。
关于为什么会发生这种情况的任何想法,以及如何解决它?
答案 0 :(得分:15)
我终于找到了答案。来自CroppedBitmap的文档:
CroppedBitmap实现ISupportInitialize接口以优化多个属性的初始化。只有在对象初始化期间才会发生属性更改调用BeginInit表示初始化已经开始,EndInit表示初始化已完成。初始化后,属性更改将被忽略。 (强调我的)
为了好玩,我尝试在我的方法中添加BeginInit().. EndInit()调用,以查看是否可以使其可修改。毫不奇怪,我得到了一个InvalidOperationException(“不能多次设置初始化状态”)。
所以CroppedBitmap实际上是不可变的。(但是他们忽略了他们自己的Freezable系统,这会抛出一个例外,告诉我我做错了什么,并实现了更多surprising代替。)
这意味着,不要更改SourceRect属性。我需要为spritesheet中的每个子图像创建一个单独的CroppedBitmap实例。
答案 1 :(得分:6)
以下是另一种处理此问题的方法:
不使用CroppedBitmap
,而是使用完整的源图像,但是:
image.RenderTransform
以调整可视区域。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);
答案 2 :(得分: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();
}
}
潜在的差劲。