老哥们 ,我遇到一个情况,就是当界面里一个图片绑定了BitmapImage 属性源的情况下,无法释放内存。是一个大项目中的一个问题,我整理了一下,下面用一个简单的示例演示:界面绑定了一个图片:<Window x:Class="WpfApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/up-compatibility/2006"
xmlns:local="clr-namespace:WpfApplication1"
mc:Ignorable="d"
x:Name="main"
DataContext="{Binding RelativeSource={RelativeSource Self}}"
Title="Window1" Height="300" Width="300">
<Grid>
<Image x:Name="image" Source="{Binding ImageSource1}"></Image>
</Grid>
</Window>
这个图片绑定的属性源: private BitmapImage imageSource1; public BitmapImage ImageSource1
{
get
{
return imageSource1;
}
set
{
imageSource1 = value;
if (null != PropertyChanged)
{
PropertyChanged.Invoke(this, new PropertyChangedEventArgs("ImageSource1"));
}
}
}
为了演示内存没被释放 ,用一个在MainWindow上的按钮来弹出上面的Window1界面:<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/up-compatibility/2006"
xmlns:local="clr-namespace:WpfApplication1"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Button x:Name="button" Content="Button" HorizontalAlignment="Left" Width="75" Click="button_Click"/>
</Grid>
</Window> private void button_Click(object sender, RoutedEventArgs e)
{ BitmapImage imageSource1 = new BitmapImage();
imageSource1.BeginInit();
imageSource1.CacheOption = BitmapCacheOption.OnLoad;
imageSource1.StreamSource = new MemoryStream(File.ReadAllBytes("TestImage.png"));
imageSource1.EndInit(); Window1 w1 = new Window1();
w1.ImageSource1 = imageSource1;
w1.ShowDialog(); //BindingOperations.ClearBinding(w1.image, System.Windows.Controls.Image.SourceProperty); }
在没关闭Window1界面的时候,内存里是有 Window1 这个实例的:
当我关闭Window1界面的时候,内存里是还是有 Window1 这个实例的,显然Window1 没被释放掉:
找了很久,发现原来是图片一直占用着绑定资源,直到我手动加上最后一句:
private void button_Click(object sender, RoutedEventArgs e)
{ BitmapImage imageSource1 = new BitmapImage();
imageSource1.BeginInit();
imageSource1.CacheOption = BitmapCacheOption.OnLoad;
imageSource1.StreamSource = new MemoryStream(File.ReadAllBytes("TestImage.png"));
imageSource1.EndInit(); Window1 w1 = new Window1();
w1.ImageSource1 = imageSource1;
w1.ShowDialog(); BindingOperations.ClearBinding(w1.image, System.Windows.Controls.Image.SourceProperty); }
内存就被释放掉了:但是用这句就不能释放,存留疑问:BindingOperations.ClearAllBindings(w1);
有人说换图片数据源,不要这么赋值,我也试过了,从一个文件直接绑定图片,是可以释放掉的,但是项目里是从硬件里copy过来byte[]转换成的图片, 上面的只是我为了演示,暂时从图片文件里获取。最后,我就是想知道有没有其它方法能够释放掉上面的图片绑定,我不想给界面控件赋上一个x:Name="xxx" ,然后再用下面的方式去解绑BindingOperations.ClearBinding(w1.xxx, System.Windows.Controls.Image.SourceProperty)显然不符MVVM的风格,ViewModel里还有各种页面控件,看起来就很乱,有没有其它能从属性源头解绑的方式?或者其它更好的解绑做法?谢谢 老哥们了~
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/up-compatibility/2006"
xmlns:local="clr-namespace:WpfApplication1"
mc:Ignorable="d"
x:Name="main"
DataContext="{Binding RelativeSource={RelativeSource Self}}"
Title="Window1" Height="300" Width="300">
<Grid>
<Image x:Name="image" Source="{Binding ImageSource1}"></Image>
</Grid>
</Window>
这个图片绑定的属性源: private BitmapImage imageSource1; public BitmapImage ImageSource1
{
get
{
return imageSource1;
}
set
{
imageSource1 = value;
if (null != PropertyChanged)
{
PropertyChanged.Invoke(this, new PropertyChangedEventArgs("ImageSource1"));
}
}
}
为了演示内存没被释放 ,用一个在MainWindow上的按钮来弹出上面的Window1界面:<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/up-compatibility/2006"
xmlns:local="clr-namespace:WpfApplication1"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Button x:Name="button" Content="Button" HorizontalAlignment="Left" Width="75" Click="button_Click"/>
</Grid>
</Window> private void button_Click(object sender, RoutedEventArgs e)
{ BitmapImage imageSource1 = new BitmapImage();
imageSource1.BeginInit();
imageSource1.CacheOption = BitmapCacheOption.OnLoad;
imageSource1.StreamSource = new MemoryStream(File.ReadAllBytes("TestImage.png"));
imageSource1.EndInit(); Window1 w1 = new Window1();
w1.ImageSource1 = imageSource1;
w1.ShowDialog(); //BindingOperations.ClearBinding(w1.image, System.Windows.Controls.Image.SourceProperty); }
在没关闭Window1界面的时候,内存里是有 Window1 这个实例的:
当我关闭Window1界面的时候,内存里是还是有 Window1 这个实例的,显然Window1 没被释放掉:
找了很久,发现原来是图片一直占用着绑定资源,直到我手动加上最后一句:
private void button_Click(object sender, RoutedEventArgs e)
{ BitmapImage imageSource1 = new BitmapImage();
imageSource1.BeginInit();
imageSource1.CacheOption = BitmapCacheOption.OnLoad;
imageSource1.StreamSource = new MemoryStream(File.ReadAllBytes("TestImage.png"));
imageSource1.EndInit(); Window1 w1 = new Window1();
w1.ImageSource1 = imageSource1;
w1.ShowDialog(); BindingOperations.ClearBinding(w1.image, System.Windows.Controls.Image.SourceProperty); }
内存就被释放掉了:但是用这句就不能释放,存留疑问:BindingOperations.ClearAllBindings(w1);
有人说换图片数据源,不要这么赋值,我也试过了,从一个文件直接绑定图片,是可以释放掉的,但是项目里是从硬件里copy过来byte[]转换成的图片, 上面的只是我为了演示,暂时从图片文件里获取。最后,我就是想知道有没有其它方法能够释放掉上面的图片绑定,我不想给界面控件赋上一个x:Name="xxx" ,然后再用下面的方式去解绑BindingOperations.ClearBinding(w1.xxx, System.Windows.Controls.Image.SourceProperty)显然不符MVVM的风格,ViewModel里还有各种页面控件,看起来就很乱,有没有其它能从属性源头解绑的方式?或者其它更好的解绑做法?谢谢 老哥们了~
解决方案 »
- 透明窗体的一些用法及实现
- 按中间字母排序
- datagridview如何在前面增加一列序号
- 求firefox 把页面放在桌面快捷方式.求求求.ie下可以
- 关于datagridview导出到Excel后,对Excel的单元格属性的设置的问题!![问题点数:20分]
- 高人给推荐几本好的稍难的,新点的C#方面书籍,有很多书挺好但是都太老了。推荐一下。一起分享。
- 如何在winform 中给下拉菜绑定数据?
- 请问一个SendKeys.Send();发送字符串重复的问题
- Excel文件怎么关闭,Close有三个参数,不知道怎么填
- 在winform中如何打开另一个用C#写的exe可执行文件?
- C#爬虫爬去异步加载页面
- c#处理excel和txt
非常感谢老哥的提醒,我重写了一下示例,用了一个VM作为Window1的DataContext:
public class Window1VM : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged; private BitmapImage imageSource1; public BitmapImage ImageSource1
{
get
{
return imageSource1;
}
set
{
imageSource1 = value;
if (null != PropertyChanged)
{
PropertyChanged.Invoke(this, new PropertyChangedEventArgs("ImageSource1"));
}
}
} public Window1VM()
{
BitmapImage imageSource1 = new BitmapImage();
imageSource1.BeginInit();
imageSource1.CacheOption = BitmapCacheOption.OnLoad;
imageSource1.StreamSource = new MemoryStream(File.ReadAllBytes("TestImage.png"));
imageSource1.EndInit();
ImageSource1 = imageSource1;
} public DelegateCommand<object> AppClosingCommand
{
get
{
return new DelegateCommand<object>((a) =>
{
//ImageSource1 = null;
ImageSource1.ClearValue(Image.SourceProperty);
GC.Collect();
GC.WaitForPendingFinalizers();
});
}
} }
前端就剩下:<Window x:Class="WpfApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/up-compatibility/2006"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:local="clr-namespace:WpfApplication1"
mc:Ignorable="d"
x:Name="main"
Title="Window1" Height="300" Width="300">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Closing">
<i:InvokeCommandAction Command="{Binding AppClosingCommand}">
</i:InvokeCommandAction>
</i:EventTrigger>
</i:Interaction.Triggers>
<Grid>
<Image x:Name="image" Source="{Binding ImageSource1}"></Image>
</Grid>
</Window>
原先的MainWindow button 按钮事件里代码就变成: private void button_Click(object sender, RoutedEventArgs e)
{
Window1 w1 = new Window1();
Window1VM w1VM = new Window1VM();
w1.DataContext = w1VM;
w1.ShowDialog(); //BindingOperations.ClearBinding(w1.image, System.Windows.Controls.Image.SourceProperty);
}
如果注释掉下面这行代码,依然是无法回收 Window1VM 以及 Window1: BindingOperations.ClearBinding(w1.image, System.Windows.Controls.Image.SourceProperty);
问题就在于我不知道 如何正确的回收这种ImageSource,下面的写法都不对,最终都无法释放: //ImageSource1 = null;
ImageSource1.ClearValue(Image.SourceProperty);
GC.Collect();
GC.WaitForPendingFinalizers();
在不将前端页面控件传到VM的情况下,如何在窗体关闭时去释放这种图片资源。
<Image.Style>
<Style TargetType="{x:Type Image}">
<Style.Triggers>
<DataTrigger Binding="{Binding ImageSource1, Converter={StaticResource NullToBoolenConverter}}" Value="True">
<Setter Property="Source" Value="{x:Null}" />
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
public class NullToBoolenConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if ((BitmapImage)value == null)
{
return true;
}
else
{
return false;
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
<Image.Style>
<Style TargetType="{x:Type Image}">
<Style.Triggers>
<DataTrigger Binding="{Binding ImageSource1, Converter={StaticResource NullToBoolenConverter}}" Value="True">
<Setter Property="Source">
<Setter.Value>
<MultiBinding Converter="{StaticResource ReleaseImageConverter}">
<Binding Path="ImageSourceNULL"/>
<Binding ElementName="image1" />
</MultiBinding>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>public class ReleaseImageConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if ((BitmapImage)values[0] == null)
{
System.Windows.Controls.Image image = (Image)values[1] as System.Windows.Controls.Image;
BindingOperations.ClearBinding(image, System.Windows.Controls.Image.SourceProperty);
return DependencyProperty.UnsetValue; ;
}
else
{
return DependencyProperty.UnsetValue; ;
}
} public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
} }
都不行
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525"
xmlns:ig="http://schemas.infragistics.com/xaml"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
Name="myWindow">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Closing">
<i:InvokeCommandAction Command="{Binding CloseWindowCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
<Grid>
</Grid>
</Window>
然后在 CloseWindow方法里
ImageSource1 =null
这个试过了 也不行 在4楼: public DelegateCommand<object> AppClosingCommand
{
get
{
return new DelegateCommand<object>((a) =>
{
//ImageSource1 = null;
ImageSource1.ClearValue(Image.SourceProperty);
GC.Collect();
GC.WaitForPendingFinalizers();
});
}
}