Как правильно избавиться от растрового изображения avalonia?

Я использую Avalonia UI Framework для создания приложения MVVM ядра dotnet.
Я хочу отображать кадры из WebCam и создал простую модель WebCamViewModel:

    public class WebCamViewModel : ViewModelBase
    {
        private Bitmap webCamImage;

        public Bitmap WebCamImage
        {
            get { return webCamImage; }
            private set { this.RaiseAndSetIfChanged(ref webCamImage, value); }
        }

        public WebCamViewModel(WebCamImageService webcamImageService)
        {
            webcamImageService.OnFrame += BitmapReceived;            
        }

        public void BitmapReceived(Bitmap bitmap)
        {    
            WebCamImage = bitmap;
        }
    }

Я попробовал наивный подход и избавился от старого растрового изображения следующим образом:

public void BitmapReceived(Bitmap bitmap)
        {    
            if (webCamImage != null) webCamImage.Dispose();
            WebCamImage = bitmap;
        }

Я получаю System.NullReferenceException: ссылка на объект не установлена ​​на экземпляр объекта. при изменении размера приложения. StackTrace

  1. Как я могу правильно избавиться от старых экземпляров растровых изображений, чтобы от сборщика мусора не было особо много работы?

  2. Есть ли лучший подход для отображения динамически изменяющегося содержимого изображения?


person CoOlManul    schedule 14.09.2020    source источник
comment
У вас есть потенциальная утечка памяти - вы не отписались от события OnFrame. Для удаления используйте интерфейс Dispose, когда объект больше не нужен.   -  person eocron    schedule 14.09.2020
comment
BitMap отображается как свойство. Что можно прочитать из этого свойства? Что еще может иметь ссылку на этот BitMap, который внезапно перестанет работать, если он будет удален? Чтобы безопасно избавиться от него, вы должны знать, что еще имеет ссылку на этот объект.   -  person Scott Hannen    schedule 15.09.2020
comment
@ScottHannen на самом деле это свойство используется только через привязку данных в представлении   -  person CoOlManul    schedule 15.09.2020
comment
@eocron Спасибо, что указали на это. Я намеревался использовать событие OnFrame на протяжении всего времени жизни приложения.   -  person CoOlManul    schedule 15.09.2020
comment
Растровые изображения должны иметь внутренний счетчик ссылок, поэтому должно быть безопасно избавляться от класса Bitmap, обращенного к пользователю, если вы больше не предоставляете удаленное растровое изображение как свойство. У вас есть трассировка стека для этого исключения?   -  person kekekeks    schedule 15.09.2020
comment
@kekekeks да, я обновил исходный пост   -  person CoOlManul    schedule 15.09.2020
comment
Согласно трассировке стека растровое изображение все еще привязано к элементу управления Image.   -  person kekekeks    schedule 16.09.2020


Ответы (1)


Есть пара вопросов:

  1. От события OnFrame следует отказаться, независимо от того, используете ли вы его для каждого приложения или для чего-то еще. Это просто хорошая практика, например, «использование использования на одноразовых объектах», если вы случайно создаете несколько окон или хотите переключаться между несколькими окнами с нулевой стоимостью или что-то еще. Так что это обязательно:
public void Dispose()
{
     _service.OnFrame -= BitmapReceived;
}
  1. Если растровое изображение является общедоступным доступным свойством - кто-то может ссылаться на него, будь то DataBind или что-то еще, И непреднамеренное использование кода ДОЛЖНО обрабатывать его время жизни - вызывать Close / Dispose / Finish / или что-то еще. Этот недопустимый подход в пользовательском интерфейсе приведет к проблемам, когда вы должны подсчитывать ссылки на этот экземпляр, чтобы управлять его смертью (и вы также столкнетесь со случайным NRE и другим исключением в приложении, которое вы должны просто пропустить). Вместо этого просто создайте событие, в котором удаление этого объекта будет выполняться пользователем. Это сделает это свойство бесполезным, и вам не нужно избавляться:
public event EventHandler<Bitmap> OnFrame
{
    add
    {
        _service.OnFrame += value;
    }
    remove
    {
        _service.OnFrame -= value;
    }
}

Таким образом, вы можете выполнить необходимые преобразования в Bitmap, прежде чем загружать его в View. Вот почему вы выбираете в первую очередь MVVM: просмотр после преобразования модели, преобразование перед фиксацией модели. Вероятно, будет хорошей идеей вместо этого переключиться на MVC для работы с веб-камерой.

person eocron    schedule 15.09.2020
comment
1.) Спасибо, я это изменил. 2.) Возможно, я неправильно выразился: во время выполнения сборщика мусора у меня появляется зубчатая структура памяти, чего я хотел избежать, избавившись от самого изображения. Это кажется контрпродуктивным, поскольку (как подчеркнул Кекекекс) изображение все еще связано. - person CoOlManul; 17.09.2020