Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/276.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# Wpf图像控件阻止该文件_C#_Wpf_Image - Fatal编程技术网

C# Wpf图像控件阻止该文件

C# Wpf图像控件阻止该文件,c#,wpf,image,C#,Wpf,Image,我有一个带有按钮的简单的窗口,当我点击按钮时,第二个窗口打开。第二个窗口有一个图像控件,它显示一个.png文件。所以,如果我使用FileObject属性进行绑定一切正常,我可以从文件资源管理器中删除文件。但如果我使用FileName属性进行绑定我无法从文件资源管理器中删除文件,则会出现操作系统异常。即使关闭第二个窗口,即使显式调用GC,我也无法执行此操作。 FileName属性有什么问题?有什么想法吗 赢得7场,净胜4.0 窗口1 <Grid> <Button Cont

我有一个带有按钮的简单的
窗口
,当我点击
按钮时,第二个
窗口
打开。第二个
窗口
有一个
图像
控件,它显示一个.png文件。所以,如果我使用
FileObject
属性进行
绑定
一切正常,我可以从
文件资源管理器中删除文件。但如果我使用
FileName
属性进行
绑定
我无法从
文件资源管理器
中删除文件,则会出现操作系统异常。即使关闭第二个窗口,即使显式调用
GC
,我也无法执行此操作。
FileName
属性有什么问题?有什么想法吗

赢得7场,净胜4.0

窗口1

<Grid>
    <Button Content="Ok"
            Width="100" 
            VerticalAlignment="Center" 
            HorizontalAlignment="Center" 
            Click="Click" 
            Padding="0,2,0,2" 
            IsDefault="True" 
            Name="_btnOk"/>
</Grid> 



public partial class Window : Window
{

    public Window()
    {
        InitializeComponent();
        DataContext = this;
    }

    private void Click(Object sender, RoutedEventArgs e)
    {
        var window = new Window3();
        window.ShowDialog();
    }
}

公共部分类窗口:窗口
{
公共窗口()
{
初始化组件();
DataContext=this;
}
私有无效单击(对象发送者,路由目标)
{
var窗口=新窗口3();
ShowDialog();
}
}
窗口2

<Grid>
    <Image Source="{Binding FileObject}"></Image>
</Grid>

public partial class Window2 : Window
{
    public Window2()
    {
        InitializeComponent();
        DataContext = this;
        FileName = "D:/pdf/myfile.png";

        Closing += Window2_Closing;
    }

    public String FileName { get; set; }

    public Object FileObject
    {
        get
        {
            if (String.IsNullOrEmpty(FileName))
                return null;

            if (!File.Exists(FileName))
                return null;

            var ms = new MemoryStream();
            var bi = new BitmapImage();

            using (var fs = new FileStream(FileName, FileMode.Open, FileAccess.Read))
            {
                fs.CopyTo(ms);
                bi.BeginInit();
                bi.StreamSource = ms;
                bi.EndInit();
            }
            return bi;
        }
    }

    void Window2_Closing(Object sender, System.ComponentModel.CancelEventArgs e)
    {
        GC.Collect();
        GC.WaitForPendingFinalizers();
    }
}

公共部分类Window2:Window
{
公共窗口2()
{
初始化组件();
DataContext=this;
FileName=“D:/pdf/myfile.png”;
关闭+=窗口2\u关闭;
}
公共字符串文件名{get;set;}
公共对象文件对象
{
得到
{
if(String.IsNullOrEmpty(文件名))
返回null;
如果(!File.Exists(FileName))
返回null;
var ms=新内存流();
var bi=新的位图图像();
使用(var fs=new FileStream(文件名,FileMode.Open,FileAccess.Read))
{
财政司司长(ms);
bi.BeginInit();
bi.StreamSource=ms;
bi.EndInit();
}
返回bi;
}
}
无效窗口2\u关闭(对象发送方,System.ComponentModel.CancelEventArgs e)
{
GC.Collect();
GC.WaitForPendingFinalizers();
}
}

使用此代码,稍后我将解释问题所在

var image = new BitmapImage();
image.BeginInit();
image.CacheOption = BitmapCacheOption.OnLoad;
image.CreateOptions = BitmapCreateOptions.IgnoreImageCache;
image.UriSource = new Uri(FilePath);
image.EndInit();
return image;

当您将
Image.Source
属性绑定到Uri(或从其内部创建Uri的字符串)时,WPF使用内置类型转换器从Uri创建
BitmapFrame

如果Uri包含本地文件的路径,则只要该文件存在,BitmapFrame就会将其保持打开状态。这可能比应用程序中实际使用的时间长,因为它可能被WPF缓存

当您需要能够删除从中加载图像的文件时,应始终使用
FileObject
方法,但它应该如下所示:

public ImageSource Image
{
    get
    {
        ...
        var bi = new BitmapImage();
        using (var fs = new FileStream(FileName, FileMode.Open, FileAccess.Read))
        {
            bi.BeginInit();
            bi.CacheOption = BitmapCacheOption.OnLoad;
            bi.StreamSource = fs;
            bi.EndInit();
        }
        return bi;
    }
}
public ImageSource Image
{
    get
    {
        using (var fs = new FileStream(FileName, FileMode.Open, FileAccess.Read))
        {
            return BitmapFrame.Create(
                fs, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
        }
    }
}
或者像这样:

public ImageSource Image
{
    get
    {
        ...
        var bi = new BitmapImage();
        using (var fs = new FileStream(FileName, FileMode.Open, FileAccess.Read))
        {
            bi.BeginInit();
            bi.CacheOption = BitmapCacheOption.OnLoad;
            bi.StreamSource = fs;
            bi.EndInit();
        }
        return bi;
    }
}
public ImageSource Image
{
    get
    {
        using (var fs = new FileStream(FileName, FileMode.Open, FileAccess.Read))
        {
            return BitmapFrame.Create(
                fs, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
        }
    }
}

或者使用绑定转换器绑定到
FileName
属性,该转换器创建位图图像或位图帧,如上所示。

为什么要这样绑定?仅供参考,在
FileObject
属性getter中不需要MemoryStream。只需设置
bi.StreamSource=fs
bi.CacheOption=BitmapCacheOption.OnLoad。属性还应返回
ImageSource
BitmapSource
而不是
object
。明白了,谢谢。但是为什么您不喜欢
MemoryStream
,而建议使用
BitmapCacheOption.OnLoad
?利润是多少?在第二种方法中(使用
位图帧
BitmapFrame
不会被WPF缓存?好处是您可以保存
fs.CopyTo(ms)
操作,并且可以立即关闭流(由于
BitmapCacheOption.OnLoad
)。您让内存流保持打开状态,这实际上不是问题,但是应该避免。在这两种情况下,都不会缓存图像。缓存只使用Uri作为键来完成,这里没有。