Search code examples
c#wpfdata-binding

Edit file after removing binding


I am trying to stream a desktop screen from one PC to another. I've started with just sending an image first which was really easy. My next thought was to just display the image using WPF and by continuously editing the saved image I would have a live stream of the desktop. After trying this I noticed that editing an image that is currently being used results in an exception.

The process cannot access the file 'D:\Desktop\ConsoleApp1\WpfApp1\img\Bild1.jpeg' because it is being used by another process.

So when I tried using two different images that would just swap every time, the same exception kept appearing.

The code below deletes the unbound image and creates a new file that will be bound to an Image.

// The Image that is currently not binded will be deleted with the code below

if (img1){
    if (File.Exists("./../../img/Bild2.jpeg"))
    {
        File.Delete("./../../img/Bild2.jpeg");
    }
}
else
{
    if (File.Exists("./../../img/Bild1.jpeg"))
    {
        File.Delete("./../../img/Bild1.jpeg");
    }
}

// This code save the Image
if (File.Exists("../../img/Bild1.jpeg")) // Image1 exists so I am editing image2
{
    bmp.Save("../../img/Bild2.jpeg", ImageFormat.Jpeg); 
    ms.Position = 0;
    FileInfo fi = new FileInfo("../../img/Bild2.jpeg");
    ImageBind = fi.FullName; // Image Bind is a string property which is binded to a Image Tag
    img1 = false; // To check which img has been edited last
}
else if (File.Exists("../../img/Bild2.jpeg"))
{
    bmp.Save("./../../img/Bild1.jpeg", ImageFormat.Jpeg);
    ms.Position = 0;
    FileInfo fi = new FileInfo("../../img/Bild1.jpeg");
    ImageBind = fi.FullName; 
    img1 = true; 
}
else // If neither Image1 or Image2 exists
{
    bmp.Save("../../img/Bild1.jpeg", ImageFormat.Jpeg);
    ms.Position = 0;
    FileInfo fi = new FileInfo("../../img/Bild1.jpeg");
    ImageBind = fi.FullName; 
    img1 = true; 
}

Solution

  • I do not think that copying and swapping images is the right approach for live desktop streaming in many ways, but that is another question. I will only focus on the exception that you get.

    The image files that you assign by file path to Image are locked until the application is shut down. In order to change that, you have to change caching options of the underlying BitmapImage.

    You can create a value converter to do this, so you can keep the ImageBind property as string.

    public class PathToBitmapSourceConverter : IValueConverter
    {
       public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
       {
          var bi = new BitmapImage();
          var uriString = (string)value;
    
          bi.BeginInit();
          bi.UriSource = new Uri(uriString, UriKind.RelativeOrAbsolute);
          bi.CacheOption = BitmapCacheOption.OnLoad;
          bi.CreateOptions = BitmapCreateOptions.IgnoreImageCache;
          bi.EndInit();
    
          return bi;
       }
    
       public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
       {
          throw new InvalidOperationException();
       }
    }
    

    This code will convert your file path to a BitmapImage. The OnLoad and IgnoreImageCache will prevent the image from being locked. From the documentation:

    • OnLoad - Caches the entire image into memory at load time. All requests for image data are filled from the memory store.
    • IgnoreImageCache - Loads images without using an existing image cache. This option should only be selected when images in a cache need to be refreshed.

    In your XAML you have to create an instance of the converter in any resource dictionary and adapt the binding of your Image to use the converter, assuming its key is PathToBitmapSourceConverter.

    <Image Source="{Binding ImageBind, Converter={StaticResource PathToBitmapSourceConverter}}" ... />