处理WPF窗口

时间:2010-12-05 07:36:52

标签: wpf vb.net wpf-controls window dispose

我有一个WPF窗口,我用Window.Show()显示。 当我单击X时,表单关闭。 但它仍然在记忆中,GC永远不会来清理它。 我也没有任何参考/处理。

有没有人知道是什么原因导致它留在记忆中?

谢谢!

更新: 我使用以下代码来创建窗口:

   Public Sub OpenPageWindow(ByVal nick As String)
        Dim found As Boolean

        For Each pw As PageWindow In Application.Current.Windows.OfType(Of PageWindow)()
            If Not pw.Tag Is Nothing Then
                If pw.Tag.ToString() = nick Then
                    If pw.IsVisible = False Then
                        pw.Show()
                    End If
                    Exit Sub
                End If
            End If
        Next

        If found = False Then
            Dim p As New PageWindow With {.Name = "pw" & nick, .Tag = nick, _
                                          .Title = "Chatting with " & nick, .ShowActivated = False}
            p.Show()
        End If
    End Sub

以及窗口本身的以下代码隐藏:

Public Class PageWindow
    Implements System.IDisposable

    Public UserPressedExit As Boolean
    Dim MainWin As MainWindow

    Private _IsBuddy As Boolean
    Private _IsBlocked As Boolean
    Private _IsOnline As Boolean

    Public Property FirstOpen As Boolean

    Public Property IsOnline As Boolean
        Get
            Return _IsOnline
        End Get
        Set(ByVal value As Boolean)
            If _IsOnline <> value Then
                _IsOnline = value
            End If
        End Set
    End Property

    Public Property IsBuddy As Boolean
        Get
            Return _IsBuddy
        End Get
        Set(ByVal value As Boolean)
            If _IsBuddy <> value Then
                _IsBuddy = value
                'If value Then
                '    btnAddBuddy.IsEnabled = False
                '    iDeleteBuddy.IsEnabled = True
                'Else
                '    btnAddBuddy.IsEnabled = True
                '    iDeleteBuddy.IsEnabled = False
                'End If
            End If
        End Set
    End Property

    Private Sub Window_Loaded(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
        Try
            MainWin = CType(Application.Current.Windows(0), MainWindow)
        Catch ex As Exception
            txtChat.AppendText("ERROR: " & ex.Message.ToString() & Environment.NewLine)
        End Try
    End Sub

    Private Sub Window_Closed(ByVal sender As System.Object, ByVal e As System.EventArgs)
        Me.Dispose()
    End Sub

    Private Sub txtTitle_PreviewMouseDown(ByVal sender As System.Object, ByVal e As System.Windows.Input.MouseButtonEventArgs)
        Me.DragMove()
    End Sub

    Private Sub pbMin_PreviewMouseUp(ByVal sender As System.Object, ByVal e As System.Windows.Input.MouseButtonEventArgs)
        WindowState = Windows.WindowState.Minimized
    End Sub

    Private Sub pbClose_PreviewMouseUp(ByVal sender As System.Object, ByVal e As System.Windows.Input.MouseButtonEventArgs)
        UserPressedExit = True
        txtChat.Clear()
        Me.Close()
    End Sub

    Private Sub txtSend_KeyUp(ByVal sender As System.Object, ByVal e As System.Windows.Input.KeyEventArgs)
        If e.Key = Key.Enter Then
            btnSend_Click(Nothing, Nothing)
        End If
    End Sub

    Private Sub btnSend_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
        If String.IsNullOrWhiteSpace(txtSend.Text) Then
            MessageBox.Show("Empty Message.")
            txtSend.Text = ""
        Else
            Send(txtSend.Text)

            txtSend.Text = ""
        End If
    End Sub

    Public Sub Page(ByVal message As String)
        If String.IsNullOrEmpty(message) = False Then
            If MainWin.Settings.ShowPageTimestamp Then
                txtChat.AppendText(Me.Tag.ToString() & " (" & Format(Date.Now, "HH:mm:ss") & "): " & message & Environment.NewLine)
            Else
                txtChat.AppendText(Me.Tag.ToString() & ": " & message & Environment.NewLine)
            End If

            If Me.IsFocused = False Then

            End If
        End If
    End Sub

    Private Sub Send(ByVal text As String)
        'work on 389 event
        MainWin.Send("PAGE " + Me.Tag.ToString + " " + text)

        If MainWin.Settings.ShowPageTimestamp Then
            txtChat.AppendText(MainWin.Settings.Nick & ": " & text & Environment.NewLine)
        Else
            txtChat.AppendText(MainWin.Settings.Nick & " (" & Format(Date.Now, "HH:mm:ss") & "): " & text & Environment.NewLine)
        End If
    End Sub

#Region "IDisposable Support"
    Private disposed As Boolean ' To detect redundant calls

    ' This code added by Visual Basic to correctly implement the disposable pattern.
    Public Sub Dispose() Implements IDisposable.Dispose
        ' Do not change this code.  Put cleanup code in Dispose(ByVal disposing As Boolean) above.
        Dispose(True)
        GC.SuppressFinalize(Me)
    End Sub

    Protected Overridable Sub Dispose(ByVal disposing As Boolean)
        If Not Me.disposed Then
            If disposing Then
                'dispose managed state (managed objects).
                RemoveHandler Me.Loaded, AddressOf Window_Loaded
                RemoveHandler txtTitle.PreviewMouseDown, AddressOf txtTitle_PreviewMouseDown
                RemoveHandler pbMin.PreviewMouseUp, AddressOf pbMin_PreviewMouseUp
                RemoveHandler pbClose.PreviewMouseUp, AddressOf pbClose_PreviewMouseUp
                RemoveHandler txtSend.KeyUp, AddressOf txtSend_KeyUp
                RemoveHandler btnSend.Click, AddressOf btnSend_Click
                RemoveHandler Me.Closed, AddressOf Window_Closed

                BindingOperations.ClearBinding(txtTitle, TextBlock.TextProperty)

                Me.Icon = Nothing
                ibBackground = Nothing
                'iDeleteBuddy = Nothing
                'btnAddBuddy = Nothing
                'iBlockUser = Nothing
                pbMin = Nothing
                pbClose = Nothing
                MainWin = Nothing

                Me.Resources.Clear()

                GC.Collect()
            End If
        End If
        Me.disposed = True
    End Sub

    Protected Overrides Sub Finalize()
        ' Do not change this code.  Put cleanup code in Dispose(ByVal disposing As Boolean) above.
        Dispose(False)
        MyBase.Finalize()
    End Sub
#End Region
End Class

然后是XAML的以下代码:

<Window x:Class="PageWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="PageWindow" Height="300" Width="400"
        Icon="Images\R2.ico" WindowStyle="None" ResizeMode="NoResize"
        WindowStartupLocation="Manual" Loaded="Window_Loaded"
        BorderThickness="2" BorderBrush="#FFAE28"
        Closed="Window_Closed">
    <Window.Resources>
        <Style x:Key="sRenegadeButton" TargetType="Button">
            <Setter Property="FontFamily" Value="Franklin Gothic Medium" />
            <Setter Property="FontSize" Value="12px" />
            <Setter Property="FontWeight" Value="Bold" />
            <Setter Property="Background" Value="Transparent" />
            <Setter Property="Foreground" Value="#FFAE28" />
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="Button">
                        <Border Name="Border" BorderBrush="#FFAE28" BorderThickness="1" CornerRadius="3" 
                                Background="{TemplateBinding Background}" SnapsToDevicePixels="True">
                            <Border Name="innerborder" BorderBrush="#FFAE28" BorderThickness="1" CornerRadius="3" 
                                    Background="{TemplateBinding Background}" SnapsToDevicePixels="True" Margin="1">
                                <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" Name="content" />
                            </Border>
                        </Border>
                        <ControlTemplate.Triggers>
                            <Trigger Property="IsMouseOver" Value="True">
                                <Setter TargetName="Border" Property="BorderBrush" Value="#FFD528" />
                                <Setter TargetName="innerborder" Property="BorderBrush" Value="#FFD528" />
                                <Setter Property="Background" Value="#28FFAE28" />
                                <Setter Property="Foreground" Value="#FFD528" />
                            </Trigger>
                            <Trigger Property="IsPressed" Value="True">
                                <Setter Property="Background" Value="#28FFAE28" />
                                <Setter TargetName="content" Property="RenderTransform" >
                                    <Setter.Value>
                                        <TranslateTransform Y="1.0" />
                                    </Setter.Value>
                                </Setter>
                            </Trigger>
                            <Trigger Property="IsEnabled" Value="False">
                                <Setter TargetName="Border" Property="BorderBrush" Value="#80E6A023" />
                                <Setter TargetName="innerborder" Property="BorderBrush" Value="#80E6A023" />
                                <Setter Property="Foreground" Value="#8CFFD528" />
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

        <Style x:Key="sRenegadeTextBox" TargetType="TextBox">
            <Setter Property="FontFamily" Value="Franklin Gothic Medium" />
            <Setter Property="FontSize" Value="12px" />
            <Setter Property="Foreground" Value="#FFD528" />
            <Setter Property="Background" Value="#28FFAE28" />
            <Setter Property="BorderBrush" Value="#FFAE28" />
            <Setter Property="CaretBrush" Value="#FFAE28" />
            <Setter Property="SelectionBrush" Value="#FFD528" />
            <Setter Property="BorderThickness" Value="1" />
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="TextBox">
                        <Border Name="Bd" BorderThickness="{TemplateBinding BorderThickness}" 
                                BorderBrush="{TemplateBinding BorderBrush}" 
                                Background="{TemplateBinding Background}" SnapsToDevicePixels="true">
                            <ScrollViewer Name="PART_ContentHost" Background="{TemplateBinding Background}" 
                                          SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
                        </Border>
                        <ControlTemplate.Triggers>
                            <Trigger Property="IsEnabled" Value="False">
                                <Setter Property="Foreground" Value="#8CFFD528" />
                                <Setter Property="Background" Value="#1EFFAE28" />
                                <Setter Property="BorderBrush" Value="#80E6A023" />
                                <Setter TargetName="PART_ContentHost" Property="Background" Value="#1EFFAE28"/>
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </Window.Resources>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="21" />
            <RowDefinition Height="32" />
            <RowDefinition Height="*" />
            <RowDefinition Height="27" />
        </Grid.RowDefinitions>

        <Grid.Background>
            <ImageBrush x:Name="ibBackground"  ImageSource="Images\page_back.gif" />
        </Grid.Background>

        <Border Grid.Row="0" BorderBrush="#FFAE28" BorderThickness="0,0,0,2" 
                SnapsToDevicePixels="True" />

        <Grid Name="gTitleBar" Grid.Row="0" Background="#32FFAE28">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="30" />
                <ColumnDefinition Width="32" />
            </Grid.ColumnDefinitions>

            <TextBlock Name="txtTitle" Grid.Column="0" Text="{Binding Title,RelativeSource={RelativeSource FindAncestor,AncestorType=Window}}"
                       HorizontalAlignment="Stretch" VerticalAlignment="Center"
                       TextAlignment="Left" Margin="4,0,1,0" 
                       PreviewMouseDown="txtTitle_PreviewMouseDown"
                       Foreground="#FED528" FontFamily="Franklin Gothic Medium" />

            <Image Name="pbMin" Grid.Column="1" Width="28" Height="15" 
                    HorizontalAlignment="Center" VerticalAlignment="Center"
                    PreviewMouseUp="pbMin_PreviewMouseUp" Stretch="None">
                <Image.Style>
                    <Style TargetType="{x:Type Image}">
                        <Setter Property="Source" Value="Images\min.png" />

                        <Style.Triggers>
                            <Trigger Property="IsMouseOver" Value="True">
                                <Setter Property="Source" Value="Images\min_o.png" />
                            </Trigger>
                        </Style.Triggers>
                    </Style>
                </Image.Style>
            </Image>
            <Image Name="pbClose" Grid.Column="2" Width="28" Height="15" 
                    HorizontalAlignment="Left" VerticalAlignment="Center"
                    PreviewMouseUp="pbClose_PreviewMouseUp" Stretch="None">
                <Image.Style>
                    <Style TargetType="{x:Type Image}">
                        <Setter Property="Source" Value="Images\close2.png" />

                        <Style.Triggers>
                            <Trigger Property="IsMouseOver" Value="True">
                                <Setter Property="Source" Value="Images\close2_o.png" />
                            </Trigger>
                        </Style.Triggers>
                    </Style>
                </Image.Style>
            </Image>
        </Grid>

        <Grid Grid.Row="1">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="25" />
                <ColumnDefinition Width="25" />
                <ColumnDefinition Width="25" />
                <ColumnDefinition Width="*" />
            </Grid.ColumnDefinitions>

            <!--<Button Name="btnAddBuddy" Grid.Column="1" Margin="0,2,0,0">
                <Button.Style>
                    <Style TargetType="{x:Type Button}">
                        <Setter Property="Background" Value="Transparent" />
                        <Setter Property="Template">
                            <Setter.Value>
                                <ControlTemplate TargetType="{x:Type Button}">
                                    <Grid>
                                        <Border Name="Border" BorderBrush="Transparent" BorderThickness="1" CornerRadius="3" 
                                            Background="{TemplateBinding Background}" SnapsToDevicePixels="True">

                                        </Border>
                                        <Image Name="iAddBuddy" Margin="1" Source="Images\Add Buddy 32x36.png" />
                                        <Image Name="iAddBuddyDissabled" Margin="1" Source="Images\Add Buddy 32x36.png" Visibility="Hidden" />
                                    </Grid>

                                    <ControlTemplate.Triggers>
                                        <Trigger Property="IsMouseOver" Value="True">
                                            <Setter TargetName="Border" Property="BorderBrush" Value="#FFD528" />
                                        </Trigger>
                                        <Trigger Property="IsPressed" Value="True">
                                            <Setter Property="Background" Value="#FFD528" />
                                        </Trigger>
                                        <Trigger Property="IsEnabled" Value="False">
                                            <Setter TargetName="Border" Property="BorderBrush" Value="Transparent" />
                                            <Setter TargetName="iAddBuddy" Property="Visibility" Value="Hidden" />
                                            <Setter TargetName="iAddBuddyDissabled" Property="Visibility" Value="Visible" />
                                        </Trigger>
                                    </ControlTemplate.Triggers>
                                </ControlTemplate>
                            </Setter.Value>
                        </Setter>
                    </Style>
                </Button.Style>
            </Button>

            <Border Name="bDeleteBuddyBorder" Grid.Column="2" BorderThickness="1"
                    SnapsToDevicePixels="True" Margin="0,2,0,0">
                <Image Name="iDeleteBuddy" Margin="1" IsEnabled="True"
                   Source="Images\Delete 32x32.png">
                    <Image.Style>
                        <Style TargetType="{x:Type Image}">
                            <Style.Triggers>
                                <Trigger Property="IsEnabled" Value="False">
                                    <Setter Property="Source" Value="Images\Delete Disabled 32x32.png" />
                                </Trigger>
                            </Style.Triggers>
                        </Style>
                    </Image.Style>
                </Image>
                <Border.Style>
                    <Style TargetType="Border">
                        <Setter Property="BorderBrush" Value="Transparent" />
                        <Setter Property="Background" Value="Transparent" />
                        <Style.Triggers>
                            <Trigger Property="IsMouseOver" Value="True">
                                <Setter Property="BorderBrush" Value="#FFD528" />
                            </Trigger>
                        </Style.Triggers>
                    </Style>
                </Border.Style>
            </Border>

            <Border Name="bBlockUserBorder" Grid.Column="3" BorderThickness="1"
                    SnapsToDevicePixels="True" Margin="0,2,0,0">
                <Image Name="iBlockUser" Margin="1" IsEnabled="True"
                       Source="Images\Block Buddy 32x36.png">
                    <Image.Style>
                        <Style TargetType="{x:Type Image}">
                            <Style.Triggers>
                                <Trigger Property="IsEnabled" Value="False">
                                    <Setter Property="Source" Value="Images\Block Buddy Dissabled 32x36.png" />
                                </Trigger>
                            </Style.Triggers>
                        </Style>
                    </Image.Style>
                </Image>
                <Border.Style>
                    <Style TargetType="Border">
                        <Setter Property="BorderBrush" Value="Transparent" />
                        <Setter Property="Background" Value="Transparent" />
                        <Style.Triggers>
                            <Trigger Property="IsMouseOver" Value="True">
                                <Setter Property="BorderBrush" Value="#FFD528" />
                            </Trigger>
                        </Style.Triggers>
                    </Style>
                </Border.Style>
            </Border>-->
        </Grid>

        <TextBox Name="txtChat" Grid.Row="2" Margin="4,2,4,2"
                 Style="{StaticResource sRenegadeTextBox}" UndoLimit="0" />

        <Grid Grid.Row="3">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="45" />
            </Grid.ColumnDefinitions>

            <TextBox Name="txtSend" Grid.Column="0" MaxLength="495" 
                     Height="22" Margin="4,1,2,4" VerticalContentAlignment="Center" 
                     Style="{StaticResource sRenegadeTextBox}" UndoLimit="0"
                     KeyUp="txtSend_KeyUp" />
            <Button Name="btnSend" Content="Send" Grid.Column="1" 
                    Style="{StaticResource sRenegadeButton}" 
                    Height="22" Width="40" Margin="0,1,4,4" Click="btnSend_Click" />
        </Grid>
    </Grid>
</Window>

基本上即使我创建一个带有主网格背景图像的空WPF窗口和2个事件处理程序打开和关闭它仍然保留在内存中,但是当所有'空wpf'窗口关闭时,内存只会减少一点。只是一点点。为什么不完全处理简单的窗户?我甚至尝试过实现上面编码的处理功能。

4 个答案:

答案 0 :(得分:2)

首先,通过使用真实的内存工具(例如redgate的内存分析器,可以免费试用)来确保您的内存问题是您认为的(即没有得到清理)(http://www.red -gate.com/products/ants_memory_profiler /).

然后,如果您仍然遇到问题,探查器将突出显示告诉GC不要清理它的内容(其他对象引用等)。

从快速猜测中,我会说它可能是您已连接的事件处理程序,尝试在完成后取消订阅它们。

另外,如其他地方所述,请致电GC.Collect作为进一步检查

答案 1 :(得分:1)

如果你正在泄漏句柄,那么与内存一样重要的是 - 在进程中(在taskmanager中)为GDI对象和句柄添加一列。

当你打开和关闭你的窗户时,它会增加和减少 - 如果不是你有泄漏 - 泄漏会带来一些记忆。 我不会太担心一些kb不会立刻消失它们最终会被清理或重复使用,但是手柄必须消失,这样它们才能成为一个很好的指示。

通常在使用静态事件处理程序或其他包含对控件或窗口的引用的静态结构(即静态字典或哈希表)时会出现泄漏。如果需要引用,请记得在关闭时清理它或使用WeakReference。

只有在窗口/类上有资源作为成员变量时才需要Dispose方法,并且必须正确实现(你的看起来确实正确 - 但是不必要) - 你还必须确保Dispose()实际上是称为...

答案 2 :(得分:0)

  

有没有人知道是什么原因导致它留在记忆中?

您的窗口是否会收听任何外部事件?如果是这样,使用弱事件管理器可能会解决您的问题:http://msdn.microsoft.com/en-us/library/aa970850.aspx

答案 3 :(得分:0)

您是否确定运行时可以保证在这种情况下执行垃圾收集?

我认为在这种情况下GC很可能看不到执行垃圾收集的必要性。请务必在代码中调用GC.Collect,看看这是否会改变一切。