【C#】ListBox中找到多个image中的其中一个并重置赋值以便清理占用内存

发布于:2024-12-06 ⋅ 阅读:(28) ⋅ 点赞:(0)

1.ListBox中定义多个image

定义ListBox前台代码及Image控件的赋值

<ListBox Background="{DynamicResource BackgroundBrush}" 
     ItemsSource="{Binding ElementName=DRFinish,Path=Images}" 
     Style="{x:Null}" Name="ImageList"
     ItemContainerStyle="{StaticResource imageItemStyle}">
<ListBox.ItemsPanel>
    <ItemsPanelTemplate>
        <WrapPanel></WrapPanel>
    </ItemsPanelTemplate>                                    
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
    <DataTemplate>
        <Border Width="100" Height="170" Tag="{Binding}" MouseDown="imageListItemBorder_MouseDown"  Name="imageListItemBorder">
            <Grid>
                <Grid.RowDefinitions>
                    <RowDefinition Height="20"/>
                    <RowDefinition Height="90"/>
                    <RowDefinition Height="20"/>
                </Grid.RowDefinitions>
                <Image Grid.Row="0" Visibility="{Binding Infor.ImageD,Converter={StaticResource boolVisibilityConverter}}" Name="ImageDelete" Source="../Resource/DeleteImage1.png" HorizontalAlignment="Left" VerticalAlignment="Top" Width="20" Height="20" />
                <Image Grid.Row="1" Source="{Binding ImageFullPath, Converter={StaticResource jpgConverter}}" Width="90" Height="90" />
                <Image Grid.Row="1" Visibility="{Binding Infor.DFilmed,Converter={StaticResource boolVisibilityConverter}}" Source="../Resource/DFilmed.png" HorizontalAlignment="Right" VerticalAlignment="Top" Width="20" Height="20"/>
            </Grid>
        </Border>
        <DataTemplate.Triggers>
            <DataTrigger Binding="{Binding Infor.ImageD}" Value="false">
                <Setter TargetName="ImageDelete" Property="Visibility" Value="Collapsed"/>
            </DataTrigger>
            <DataTrigger Binding="{Binding Infor.ImageD}" Value="true">
                <Setter TargetName="ImageDelete" Property="Visibility" Value="Visible" />
            </DataTrigger>
        </DataTemplate.Triggers>
    </DataTemplate>
</ListBox.ItemTemplate>
</ListBox>

2.后台操作

2.1使用方法

假设你有一个ListBox,并且你想要根据Name属性查找一个特定的Image控件:

设置 Source 属性为 null

try
{
    var image = FindImageByName("ImageDelete");
    if (image != null)
    {
      // 找到了Image,可以在这里做进一步的操作
      Console.WriteLine("找到了Image: " + image.Source);
    }
    else
    {
      Console.WriteLine("没有找到匹配的Image控件");
    }
}
catch (Exception ee) { }

Images.Clear();
ImageList.ItemsSource = null;

强制垃圾回收

// 强制垃圾回收
GC.Collect();
GC.WaitForPendingFinalizers();

 

使用 MemoryStream 加载图片

如果你是从字节流加载图片,使用完MemoryStream后应确保调用其Dispose方法,以释放与之相关的资源。

using (var stream = new MemoryStream(imageBytes))
{
    var bitmap = new BitmapImage();
    bitmap.BeginInit();
    bitmap.StreamSource = stream;
    bitmap.CacheOption = BitmapCacheOption.OnLoad; // 确保加载后释放流
    bitmap.EndInit();
    bitmap.Freeze(); // 使位图不可变,有助于提高性能和降低内存使用

    // 清除之前的图像
    image.Source = null;

    // 赋予新的图像
    image.Source = bitmap;
}

使用 BitmapCache 或 BitmapImage 的 CacheOption 属性

当使用BitmapImage加载图片时,可以通过设置CacheOption属性来控制缓存行为。例如,使用OnLoad选项可以在图片加载到内存后立即释放文件流,从而减少内存占用。

var bitmap = new BitmapImage();
bitmap.BeginInit();
bitmap.CacheOption = BitmapCacheOption.OnLoad;
bitmap.UriSource = new Uri("path_to_your_image.jpg", UriKind.RelativeOrAbsolute);
bitmap.EndInit();

// 清除之前的图像
image.Source = null;

// 赋予新的图像
image.Source = bitmap;

 

2.2根据Name属性查找特定的Image控件

寻找其中一个Image控件的方法,根据Name属性查找特定的Image控件:

定义查找方法

private void FindImageByName(string name)
{
    foreach (var item in ImageList.Items)
    {
        // 获取 ListBoxItem 容器
        var listBoxItem = (ListBoxItem)ImageList.ItemContainerGenerator.ContainerFromItem(item);
        if (listBoxItem != null)
        {
            // 在 ListBoxItem 中查找 Image 控件
            var image = FindChild<System.Windows.Controls.Image>(listBoxItem, name);
            BitmapImage bitmapImage = image.Source as BitmapImage;
            if (bitmapImage != null)
            {
                if (bitmapImage.StreamSource != null)
                {
                    bitmapImage.StreamSource.Dispose();
                }
            }
        }
    }
}

辅助方法 FindChild

这个方法用于递归查找子控件:

public static T FindChild<T>(DependencyObject parent, string childName) where T : DependencyObject
{
    if (parent == null) return null;
    T foundChild = null;
    int childrenCount = VisualTreeHelper.GetChildrenCount(parent);
    for (int i = 0; i < childrenCount; i++)
    {
        var child = VisualTreeHelper.GetChild(parent, i);
        // 如果找到了匹配的子控件
        var childType = child as T;
        if (childType != null && !string.IsNullOrEmpty(childName))
        {
            var frameworkElement = child as FrameworkElement;
            if (frameworkElement != null && frameworkElement.Name == childName)
            {
                foundChild = (T)child;
                break;
            }
        }
        else if (childType != null)
        {
            foundChild = (T)child;
            break;
        }
        // 如果没有找到,递归查找子控件
        if (foundChild == null)
        {
            foundChild = FindChild<T>(child, childName);
        }
    }
    return foundChild;
}

在C#中,FindChild<T> 方法是一个泛型方法,用于在WPF(Windows Presentation Foundation)应用程序中查找特定类型的子元素。该方法定义如下:

  • T:这是一个类型参数,代表你希望找到的子元素的具体类型。例如,如果想要找一个 Button 类型的子元素,那么调用这个方法时,T 就是 Button

  • DependencyObject:这是所有WPF UI元素的基类,它提供了依赖属性系统,允许属性值的继承、资源引用等功能。

  • parent:这是开始搜索的起点对象,通常是一个包含其他UI元素的容器,比如 WindowGrid

  • childName:这是一个字符串参数,表示要找的子元素的名字。在XAML中,每个元素都可以有一个 x:Name 属性来标识它,这个参数就是用来匹配那个名字的。

  • where T : DependencyObject:这是一条约束,表明类型参数 T 必须是 DependencyObject 类或其派生类的实例。这是因为WPF中的UI元素都直接或间接地继承自 DependencyObject

这个方法的目的是递归地遍历给定父级元素的所有子元素,直到找到名称与 childName 匹配且类型为 T 的子元素为止。如果找到了这样的子元素,则返回该子元素;如果没有找到,则可能返回 null 或者某种形式的默认值,具体取决于方法的实现。

 

注意事项 

确保 Name 属性已设置:在XAML中,确保你为每个Image控件设置了Name属性。
视觉树的复杂性:如果视觉树非常复杂,可能需要调整递归查找逻辑以确保能够正确找到目标控件。
性能考虑:如果ListBox中有大量项,频繁调用此方法可能会影响性能。在这种情况下,可以考虑缓存结果或优化查找逻辑。

 

 


网站公告

今日签到

点亮在社区的每一天
去签到