Kumar
Kumar

Reputation: 11369

Exception in FileInfo.Delete - IOException

This is happening for a image gallery WPF application which shows the thumbnails in a listbox and the selected image using xaml

Question - Is there a way to delete the currently selected image safely without getting the IOException ?

FYI - the user has ALL rights to the directory, no other process is using the file

here's the code to delete the file

 void deleteCurrentlySelectedImageClick()
{
var o = SelectedPhoto; // class MyPhoto with a string FilePath
string path = o.FilePath;
// ViewList is of type List<MyPhoto> bound to listbox for displaying thumbnails            
// for the purists 
// it can/should be of type ObservableCollection<> 
// but this doesn't change that often here :)
ViewList.Remove(o);   
o = null;
firePropertyChanged("ViewList");
firePropertyChanged("SelectedPhoto");

FileInfo fi = new FileInfo(path);
fi.Delete();
}

the exception is

System.IO.IOException was unhandled by user code
  HResult=-2147024864
  Message=The process cannot access the file 'C:\<path>\US-wp2.jpg' because it is being used by another process.
  Source=mscorlib
  StackTrace:
       at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
       at System.IO.FileInfo.Delete()

the XAML for thumbnails is

<ListBox 
   IsSynchronizedWithCurrentItem="True"
   Name="PhotosListBox" 
   Style="{StaticResource PhotoListBoxStyle}" 
   Margin="5" 
   SelectionMode="Extended" 
   ItemsSource="{Binding ViewList}" 
   SelectedIndex="0" 
   SelectionChanged="PhotosListBox_SelectionChanged"
   >

.... // resources xaml is ....

    <DataTemplate DataType="{x:Type sample1:MyPhoto}">
        <Grid VerticalAlignment="Center" HorizontalAlignment="Center" Margin="6">
            <!-- Drop Shadow -->
            <Border HorizontalAlignment="Stretch" VerticalAlignment="Stretch" CornerRadius="4" Background="#44000000">
                <Border.RenderTransform>
                    <TranslateTransform X="5" Y="5" />
                </Border.RenderTransform>
                <Border.BitmapEffect>
                    <BlurBitmapEffect Radius="8" />
                </Border.BitmapEffect>
            </Border>
            <!-- Image Template -->
            <Border Padding="4" Background="White" BorderBrush="#22000000" BorderThickness="1">
                <StackPanel Orientation="Vertical">
                    <Image Source="{Binding FilePath}"/>
                </StackPanel>
            </Border>
        </Grid>
    </DataTemplate>

        <!-- Main photo catalog view -->
    <Style TargetType="{x:Type ListBox}" x:Key="PhotoListBoxStyle">
        <Setter Property="Foreground" Value="White" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type ListBox}" >
                    <WrapPanel Margin="5" IsItemsHost="True" Orientation="Horizontal" 
                   ItemHeight="{Binding ElementName=ZoomSlider, Path='Value'}" 
                   ItemWidth="{Binding ElementName=ZoomSlider, Path='Value'}" 
                   VerticalAlignment="Top" HorizontalAlignment="Stretch" />
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

    <!-- Style for an individual generic item -->
    <Style TargetType="{x:Type ListBoxItem}">
        <Setter Property="Background" Value="Transparent" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type ListBoxItem}" >
                    <Border SnapsToDevicePixels="True" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Background="{TemplateBinding Background}">
                        <ContentPresenter />
                    </Border>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsSelected" Value="True">
                            <Setter Property="Background" Value="#445B6249"   />
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

The full-size image xaml is simply

 <Image Source="{Binding SelectedPhoto.FilePath}" HorizontalAlignment="Center" VerticalAlignment="Center" />

Upvotes: 3

Views: 2685

Answers (3)

ergohack
ergohack

Reputation: 1378

    public static bool Delete(FileInfo fi)
    {
        int retries = 40;
        bool ret = false;
        SpinWait _sw = new SpinWait();

        while (!ret && retries-- > 0)
        {
            if (fi?.Exists ?? false)
            {
                fi.IsReadOnly = false;
                try
                {
                    fi.Delete();
                    ret = true;
                }
                catch (IOException) { _sw.SpinOnce(); }
            }
            else break;
        }
        return ret;
    }

Will edit if explanation is needed.

Upvotes: 0

Szymon
Szymon

Reputation: 43023

The answer to your question is: no, there's no safe way of deleting a file and you need to handle IOException. There may be multiple reasons, e.g.:

  • you may not have access rights to delete the file
  • the file is used by another process (someone/something else opened the file)
  • the file has already been deleted and doesn't exist

In your specific case, check this question: Problems overwriting (re-saving) image when it was set as image source

Upvotes: 2

atomaras
atomaras

Reputation: 2568

You should close/dispose the original file stream of the image. Copy them to a MemoryStrean when loading.

Upvotes: 1

Related Questions