Question

Lorsque j'essaie de modifier la propriété SourceRect d'un CroppedBitmap au moment de l'exécution, rien ne se produit. Il n'y a pas d'erreur et la valeur de la propriété n'est pas modifiée.

J'essaie de faire de l'animation de sprite. J'ai un BitmapSource qui contient un spritesheet, qui est un bitmap unique contenant une grille de différentes poses pour le sprite. Ensuite, j'ai un CroppedBitmap qui a la feuille de sprite comme source et un SourceRect qui tire une des poses de la feuille de sprites. Au moment de l'exécution, lorsque je veux animer, j'essaie de modifier la propriété SourceRect du CroppedBitmap pour obtenir une pose différente du bitmap plus grand. mais, comme indiqué ci-dessus, la nouvelle valeur de propriété ne tient tout simplement pas. C'est la chose la plus étrange.

Voici un exemple de code 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>

Et le codebehind essaie de faire ceci:

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

Cela me donne cette sortie de débogage:

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

Il s'agit donc d'assigner le nouveau rectangle (avec Y = 0) dans la propriété; il n'y a pas d'exception; mais ensuite, la valeur de la propriété n’a tout simplement pas changé (Y est toujours 640).

Avez-vous des idées sur les raisons pour lesquelles cela se produit et comment y remédier?

Était-ce utile?

La solution

J'ai finalement trouvé la réponse. De la documentation de CroppedBitmap :

  

CroppedBitmap implémente l'interface ISupportInitialize pour optimiser l'initialisation sur plusieurs propriétés. Les modifications de propriétés ne peuvent avoir lieu que pendant l'initialisation de l'objet. Appelez BeginInit pour signaler que l'initialisation a commencé et EndInit pour signaler que l'initialisation est terminée. Après l’initialisation, les modifications de propriétés sont ignorées. (emphase mienne)

Juste pour le fun, j’ai essayé d’ajouter BeginInit () .. EndInit () appelle dans ma méthode, pour voir si cela le rendrait modifiable. Sans surprise, j'ai reçu une InvalidOperationException ("Je ne peux pas définir l'état d'initialisation plus d'une fois").

Donc, CroppedBitmap est effectivement immuable. (mais ils ont ignoré leur propre système Freezable, qui aurait jeté une exception pour me dire que je faisais quelque chose de mal et a mis en œuvre quelque chose de plus surprenant à la place.)

Ce qui signifie qu’il est interdit de modifier la propriété SourceRect. Je devrai créer une instance distincte de CroppedBitmap pour chaque sous-image dans la feuille de sprites.

Autres conseils

Voici une autre façon de gérer cela:
Au lieu d'utiliser un CroppedBitmap , utilisez l'image source complète, mais:

  1. Définissez image.RenderTransform pour ajuster la zone visible.
  2. Définissez un Image.Clip si nécessaire, afin d'éviter d'afficher des parties non désirées de l'image.

Cela signifie que vous n'avez pas besoin de créer de nouveaux CroppedBitmaps , vous pouvez simplement ajuster la transformation.
Lors de mes tests, je n’ai constaté aucune différence de vitesse.

Par souci d'exhaustivité, voici comment ajuster votre code pour qu'il réponde à mes attentes:

<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>

Ensuite, le dernier appel à effectuer l'équivalent de l'ajustement du SourceRect est:

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

Voici un moyen d'utiliser 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. potentiellement médiocre

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top