WPF MVVM 清除绑定

晚安苏州 2018-07-01 12:52:29
WPF板块:

老哥们 ,我遇到一个情况,就是当界面里一个图片绑定了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/markup-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/markup-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里还有各种页面控件,看起来就很乱,有没有其它能从属性源头解绑的方式?或者其它更好的解绑做法?

谢谢 老哥们了~
...全文
2228 7 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
7 条回复
切换为时间正序
请发表友善的回复…
发表回复
lindexi_gd 2018-09-05
  • 打赏
  • 举报
回复
这个是 WPF 已知 bug 在我的 https://github.com/dotnet-campus/wpf-issues/tree/master/ImageMemoryLeak 已经报给微软,在经过很多年都没有修改

修复这个问题通过两个方面,一个是需要 Freeze 另一个是需要先设置 Image Source 为 null 再设置
ring_jp 2018-09-03
  • 打赏
  • 举报
回复
this.DataContext=null
晚安苏州 2018-08-21
  • 打赏
  • 举报
回复
经过多次试验,发现加了一句就可以自动释放 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();
imageSource1.Freeze();//加了此句即可释放图片资源,但不知道为什么!

Window1 w1 = new Window1();
w1.ImageSource1 = imageSource1;
w1.ShowDialog();
}
晚安苏州 2018-08-21
  • 打赏
  • 举报
回复
如果按照下面的写法:

<Image x:Name="image" Source="{Binding ImageSource1}"></Image>

在配合关闭窗体释放绑定:

private void main_Closed(object sender, EventArgs e)
{
BindingOperations.ClearBinding(this.image, System.Windows.Controls.Image.SourceProperty);
}


多次打开关闭 Window1 窗体,Window1 实例始终能在关闭后释放。
晚安苏州 2018-08-21
  • 打赏
  • 举报
回复
引用 2 楼 duanzi_peng 的回复:
Binding的时候 设置Mode为OneTime 呢?

不行 多次打开关闭 Window1 窗体,Window1 实例还是在内存中;

如果按照下面的写法,多次打开关闭 Window1 窗体,Window1 实例始终能在关闭后释放;

<Image x:Name="image" Source="test.png"></Image>



  • 打赏
  • 举报
回复
Binding的时候 设置Mode为OneTime 呢?
晚安苏州 2018-07-01
  • 打赏
  • 举报
回复
我试过使用s'tyle trigger , 在给ImageSource1赋值为null时,自动解除绑定,不过好像不行,不知道是不是写法不对:

<Image x:Name="image1" Grid.Row="1" Source="{Binding ImageSource1, Mode=OneWay}">
<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();
}
}

8,756

社区成员

发帖
与我相关
我的任务
社区描述
WPF/Silverlight相关讨论
社区管理员
  • WPF/Silverlight社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧