런타임에 CroppedBitMap의 Sourcerect를 변경하려고합니다
-
06-07-2019 - |
문제
런타임에 cruppedbitmap의 Sourcerect 속성을 변경하려고 할 때 아무 일도 일어나지 않습니다. 오류가 없으며 속성 값이 실제로 변경되지 않습니다.
스프라이트 애니메이션을하려고합니다. 스프리 시트가 포함 된 비트 맵스 소스가 있습니다. 여기에는 스프라이트를 위해 다른 포즈의 그리드를 포함하는 단일 비트 맵입니다. 그런 다음 스프리 시트를 소스로 사용하는 CruppedBitMap과 스프리 시트에서 포즈 중 하나를 끌어내는 출처가 있습니다. 런타임에 애니메이션을 원할 때 CruppedBitMap의 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>
그리고 CodeBehind는 다음을 시도합니다.
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입니다).
이런 일이 발생하는 이유와이를 고치는 방법에 대한 아이디어가 있습니까?
해결책
나는 결국 답을 찾았다. 문서에서 CrpedpitBitMap:
CruppedBitMap은 여러 속성에서의 초기화를 최적화하기 위해 isupportinitialize 인터페이스를 구현합니다. 객체 초기화 중에 만 속성 변경이 발생할 수 있습니다. 초기화가 시작되었음을 알리고 초기화가 완료되었음을 알리기 위해 ENDINIT가 시작되었음을 알리십시오. 초기화 후 속성 변경은 무시됩니다. (강조 광산)
재미를 위해, 나는 method () .. endinit () 호출을 내 메소드에 추가하여 수정할 수 있는지 확인했습니다. 놀랍게도, 나는 무효화 외과를 얻었습니다 ( "초기화 상태를 두 번 이상 설정할 수 없습니다").
따라서 CrpedpedBitMap은 효과적입니다 불변. (그러나 그들은 자신의 동결성 시스템을 무시했는데, 내가 뭔가 잘못하고 있다고 말하면서 예외를 던지고 더 많은 것을 구현했습니다. 놀라운 대신에.)
즉, Sourcerect 속성을 변경하는 데 아무것도 없음을 의미합니다. 스프리 시트 내의 각 하위 이미지에 대해 별도의 CrpedpedBitMap 인스턴스를 만들어야합니다.
다른 팁
다음은 이것을 다루는 대체 방법입니다.
a를 사용하는 대신 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);
다음은 사용 방법이 있습니다 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();
}
}
잠재적으로 가난한 성능.