Попытка изменить SourceRect CroppedBitmap во время выполнения - PullRequest
3 голосов
/ 22 июня 2009

Когда я пытаюсь изменить свойство SourceRect CroppedBitmap во время выполнения, ничего не происходит. Там нет ошибки, и значение свойства фактически не изменяется.

Я пытаюсь сделать спрайт-анимацию. У меня есть BitmapSource, который содержит спрайт-лист, который является одним растровым изображением, содержащим сетку разных поз для спрайта. Затем у меня есть CroppedBitmap, в котором в качестве источника используется таблица спрайтов, и SourceRect, который вытягивает одну из поз из таблицы спрайтов. Во время выполнения, когда я хочу анимировать, я пытаюсь изменить свойство SourceRect CroppedBitmap, чтобы вытянуть другую позу из большего растрового изображения; но, как отмечено выше, новое значение свойства просто не прилипает. Это самая странная вещь.

Вот пример 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).

Есть идеи о том, почему это происходит и как это исправить?

Ответы [ 3 ]

15 голосов
/ 23 июня 2009

Я в конце концов нашел ответ. Из документации для CroppedBitmap :

CroppedBitmap реализует интерфейс ISupportInitialize для оптимизации инициализации нескольких свойств. Изменения свойств могут происходить только во время инициализации объекта. Вызовите BeginInit, чтобы сообщить, что инициализация началась, и EndInit, чтобы сообщить, что инициализация завершена. После инициализации изменения свойств игнорируются. (выделено мной)

Просто для забавы, я попытался добавить вызовы BeginInit () .. EndInit () в мой метод, чтобы посмотреть, сделает ли это его модифицируемым. Неудивительно, что я получил InvalidOperationException («Невозможно установить состояние инициализации более одного раза»).

Таким образом, CroppedBitmap эффективно неизменен. (Но они игнорировали свою собственную систему Freezable, которая вызвала бы исключение, чтобы сказать мне, что я что-то делал неправильно, и реализовала что-то более удивительное вместо этого.)

Это означает, что нельзя изменять свойство SourceRect. Мне нужно создать отдельный экземпляр CroppedBitmap для каждого подизображения в таблице спрайтов.

6 голосов
/ 25 июля 2011

Вот альтернативный способ справиться с этим:
Вместо использования 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 голосов
/ 01 июня 2017

Вот способ использования 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();
    }
}

Потенциально плохой перф.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...