1

我编写 wpf 应用程序。我有一个很大的计划,其中包含许多动态创建和出现的按钮。当用户单击按钮时,其图像也必须动态更改。但是我遇到了一个问题:当按钮图像被改变时,过去的图像留在了网格上。如何正确更改按钮图像,或删除保留的图像?

这是我的 xaml 文件:

<Grid x:Name="MainGrid">
    <ScrollViewer x:Name="MainScroll" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0,0,0,0" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
        <Canvas x:Name="InCanvas"  Width="{Binding ActualWidth, ElementName=imageMnemoScheme}" Height="{Binding ActualHeight, ElementName=imageMnemoScheme}">
            <Image x:Name="imageMnemoScheme" RenderOptions.BitmapScalingMode="HighQuality" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0,0,0,0" Source="pack://siteoforigin:,,,/images/mnemoscheme.bmp" Stretch="None" />
         </Canvas>
    </ScrollViewer>
</Grid>

我需要 ScrollViewer 因为方案非常大。

这是动态创建的按钮的样式:

<Window.Resources>
    <Style x:Key="NoChromeButton" TargetType="{x:Type Button}">
        <Setter Property="Background" Value="Transparent"/>
        <Setter Property="BorderThickness" Value="0"/>
        <Setter Property="HorizontalContentAlignment" Value="Center"/>
        <Setter Property="VerticalContentAlignment" Value="Center"/>
        <Setter Property="BorderBrush" Value="White" />
    </Style>
</Window.Resources>

下面是创建按钮的代码:

    private ImageSource BitmapFromImagePath(string path)
    {
        byte[] imageData;
        using (FileStream fileStream = new FileStream(path, FileMode.Open, FileAccess.Read))
        {
            using (BinaryReader binaryReader = new BinaryReader(fileStream))
            {
                imageData = binaryReader.ReadBytes((int)fileStream.Length);
            }
        }
        var bitmap = new BitmapImage();
        bitmap.BeginInit();
        bitmap.CacheOption = BitmapCacheOption.OnLoad;
        MemoryStream st = new MemoryStream(imageData);
        bitmap.StreamSource = st;
        bitmap.EndInit();
        return bitmap;
    }

    private void MakeImage(Point pos, int objType, int objState, int objOrientation, int objColor)
    {
        Image xz = new Image();
        xz.Source = BitmapFromImagePath(GetImagePathByType(objType, objState, objOrientation, objColor));
        xz.Stretch = Stretch.Uniform;
        Button b = new Button();
        b.Style = style;
        b.Content = xz;
        b.Click += new RoutedEventHandler(ObjectImageClick);
        InCanvas.Children.Add(b);
    }

此代码用于从按钮中删除过去的图像,该图像保留在网格上并叠加在新按钮图像上:

    Image xz = (Image)myB.Content;
    BitmapImage bi = (BitmapImage)xz.Source;
    MemoryStream ms = (MemoryStream)bi.StreamSource;
    ms.FlushAsync();
    ms.Close();
    ms.Dispose();
    myB.Content = null;
    xz.Source = null;
    bi.StreamSource = null;
    ms = null;
    bi = null;
    xz = null;
    GC.Collect();
    GC.WaitForPendingFinalizers();
    Image smth = new Image();
    smth.Source = BitmapFromImagePath(GetImagePathByType(objType, newObjState, objOrientation, objColor));
    smth.Stretch = Stretch.Uniform;
    myB.Content = smth;
4

1 回答 1

1

显然,您永远不会从中删除任何按钮InCanvas,或者至少我可以在您的问题中找到任何相关代码。

您可以在添加新按钮之前清除画布MakeImage

InCanvas.Children.Clear();
InCanvas.Children.Add(b);

除此之外,您的代码太复杂了。从文件加载图像不需要比这更多的代码:

private ImageSource BitmapFromImagePath(string path)
{
    return BitmapFrame.Create(new Uri(path));
}

如果由于某种原因您需要手动读取文件(例如,如果您想在读取后立即删除它):

private ImageSource BitmapFromImagePath(string path)
{
    using (var fileStream = new FileStream(path, FileMode.Open, FileAccess.Read))
    {
        return BitmapFrame.Create(
            fileStream, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
    }
}

从路径字符串创建 ImageSource 的最安全或最简单的方法可能是使用内置的TypeConverterfor ImageSource

private ImageSource BitmapFromImagePath(string path)
{
    var converter = new System.Windows.Media.ImageSourceConverter();
    return converter.ConvertFrom(path) as ImageSource;
}

您的图像删除代码完全是多余的。删除所有这些:

Image xz = (Image)myB.Content;
BitmapImage bi = (BitmapImage)xz.Source;
MemoryStream ms = (MemoryStream)bi.StreamSource;
ms.FlushAsync();
ms.Close();
ms.Dispose();
myB.Content = null;
xz.Source = null;
bi.StreamSource = null;
ms = null;
bi = null;
xz = null;
GC.Collect();
GC.WaitForPendingFinalizers();
于 2013-11-15T07:59:40.863 回答