Удалить изображение, привязанное к элементу управления - PullRequest
3 голосов
/ 27 марта 2009

Я пишу приложение Image Manager WPF. У меня есть ListBox со следующим ItemsTemplate:

        <Grid x:Name="grid" Width="150" Height="150" Background="{x:Null}">
            <Grid.RowDefinitions>
                <RowDefinition Height="*"/>
                <RowDefinition Height="27.45"/>
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="150"/>
            </Grid.ColumnDefinitions>
            <Border Margin="5,5,5,5.745" Grid.RowSpan="2" Background="#FF828282" BorderBrush="{DynamicResource ListBorder}" CornerRadius="5,5,5,5" BorderThickness="1,1,2,2" x:Name="border">
                <Grid>
                    <Viewbox Margin="0,0,0,21.705">
                        <Image Width="Auto" Height="Auto" x:Name="picture" Source="{Binding Path=FullName}" />
                    </Viewbox>
                    <TextBlock Height="Auto" Text="{Binding Path=Name}" TextWrapping="Wrap" x:Name="PictureText" HorizontalAlignment="Left" Margin="70,0,0,0" VerticalAlignment="Bottom" />
                </Grid>
            </Border>
        </Grid>

Обратите внимание, что элемент управления «Изображение» связан со свойством «FullName», которое представляет собой строку, представляющую абсолютный путь к JPG.

Для некоторых функций приложения требуется изменить файл JPG (переместить, переименовать или удалить). Когда я пытаюсь это сделать (в настоящее время пытаюсь переместить файл), я получаю IOException: «Процесс не может получить доступ к файлу, потому что он используется другим процессом». Процесс блокировки файла - это мое приложение WPF.

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

  1. Установка для ListBox.Source значения null
  2. Добавление 10 секунд времени ожидания до попытка переезда.
  3. Выпуск GC.Collect ().
  4. Перемещение операции в другое нить.

Что еще я могу попробовать? Я думал о том, чтобы найти ссылку на объект Image в ItemsTemplate и попытаться избавиться от Image, но не могу понять, как получить ссылку.

Одним из возможных решений, о которых я читал, было создание копий изображений, а не фактических изображений, но поскольку привязка к имени файла, а не к фактическому изображению, я не знаю, смогу ли я сделать эту работу.

Любая помощь или предложения будут наиболее признательны.

Ответы [ 3 ]

6 голосов
/ 27 марта 2009

My Intuipic Приложение также позволяет пользователям удалять изображения. Мне пришлось написать этот конвертер , чтобы добиться этого. Соответствующий код:

//create new stream and create bitmap frame
BitmapImage bitmapImage = new BitmapImage();
bitmapImage.BeginInit();
bitmapImage.StreamSource = new FileStream(path, FileMode.Open, FileAccess.Read);
bitmapImage.DecodePixelWidth = (int) _decodePixelWidth;
bitmapImage.DecodePixelHeight = (int) _decodePixelHeight;
//load the image now so we can immediately dispose of the stream
bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
bitmapImage.EndInit();

//clean up the stream to avoid file access exceptions when attempting to delete images
bitmapImage.StreamSource.Dispose();
4 голосов
/ 04 августа 2009

Я отметил ответ Кента как ответ, и я бы также отметил ответ Бендевея, потому что я использовал их оба в окончательном решении.

Файл был определенно заблокирован, поскольку имя файла было связано с ним, поэтому элемент управления Image открыл фактический файл для создания изображения.

Чтобы решить эту проблему, я создал конвертер значений, как предложил Бендевей, а затем использовал (большую часть) кодовую форму, предложенную Кентом, для возврата нового BitmapImage:

    [ValueConversion(typeof(string), typeof(BitmapImage))]
public class PathToBitmapImage : IValueConverter
{
    public static BitmapImage ConvertToImage(string path)
    {
        if (!File.Exists(path))
            return null;

        BitmapImage bitmapImage = null;
        try
        {
            bitmapImage = new BitmapImage();
            bitmapImage.BeginInit();
            bitmapImage.StreamSource = new FileStream(path, FileMode.Open, FileAccess.Read);
            bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
            bitmapImage.EndInit();
            bitmapImage.StreamSource.Dispose();
        }
        catch (IOException ioex)
        {
        }
        return bitmapImage;
    }

    #region IValueConverter Members

    public virtual object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        if (value == null || !(value is string))
            return null;

        var path = value as string;

        return ConvertToImage(path);
    }

    public virtual object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }

    #endregion
}

Однако, как показывают комментарии выше, это не решило проблему. Я был в других проектах и ​​недавно вернулся к этому, чтобы найти решение.

Я создал другой проект, который только проверял этот код, и, конечно, он работал. Это сказало мне, что в оригинальной программе было больше ошибок.

Короче говоря, Образ создавался в трех местах, которые, как я думал, были рассмотрены:

1) ImageList, теперь связанный с помощью конвертера. 2) Основное изображение, которое было привязано к свойству ImageList SelectedItem. 3) Всплывающее окно DeleteImage, которое было связано с помощью конвертера.

Оказывается, проблема была в # 2. Связываясь с SelectedItem, я по ошибке предположил, что связывался с недавно отрендеренным изображением (на основе конвертера). В действительности, объект SelectedItem фактически был именем файла. Это означало, что основное изображение снова создавалось путем прямого доступа к файлу.

Таким образом, решение заключалось в том, чтобы связать основной элемент управления Image со свойством SelectedItem и использовать конвертер.

2 голосов
/ 27 марта 2009

Проверьте этот пост здесь.

http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/dee7cb68-aca3-402b-b159-2de933f933f1/

Sample

В основном вам придется предварительно загрузить изображение с помощью потока. Я хотел бы создать PreLoadImageConverter, что-то вроде этого, я не проверял его.

<Grid>
  <Grid.Resources>
    <local:PreLoadImageConverter x:Key="imageLoadingConverter" />
  </Grid.Resources>
  <Image Width="Auto" Height="Auto" x:Name="picture" Source="{Binding Path=FullName, Converter={StaticResource imageLoadingConverter}}" />
</Grid>

PreLoadImageConverter.cs

public class PreLoadImageConverter : IValueConverter
{
  public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
  {
    if (value == null) return null;
    string imagePath = value.ToString();

    ImageSource imageSource;
    using (var stream = new MemoryStream())
    {
      Bitmap bitmap = new Bitmap(imagePath);
      bitmap.Save(stream, System.Drawing.Imaging.ImageFormat.Png);   
      PngBitmapDecoder bitmapDecoder = new PngBitmapDecoder(stream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnLoad);
      imageSource = bitmapDecoder.Frames[0];
      imageSource.Freeze();
    }
    return imageSource;
  }

  public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
  {
    throw new Exception("The method or operation is not implemented.");
  }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...