Можете ли вы реализовать IDisposable в динамически создаваемой форме

#vb.net #module #idisposable

#vb.net #модуль #idisposable

Вопрос:

Я экспериментирую с messagebox, который при отображении использует визуальный стиль, используемый основным приложением (но для этого я бы не стал тратить свое время на повторное изобретение колеса). Как выяснилось, это превратилось в довольно интересное небольшое упражнение, и в процессе я многому научился на этом пути.

Прежде всего, я делаю это в VB, поэтому я поместил весь свой код в его собственную библиотеку dll и, в свою очередь, в модуль, чтобы в конечных проектах, которые ссылаются на эту библиотеку dll, конечный пользователь (в данном случае я) мог просто вызвать MyDLL.MessageBox.show().

В первый раз, когда я вызываю это, все работает точно так, как ожидалось, во второй раз, однако, начали происходить странные вещи. После долгих экспериментов я могу только заключить, что после того, как мое окно сообщения закрыто в первый раз, оно просто не утилизируется должным образом.

Теперь я не могу реализовать IDisposable в модуле, который содержит код для создания окна сообщения, потому что VB этого не позволяет. Я попытался явно удалить объект по мере его закрытия, но, очевидно, это не работает. Я чего-то не понимаю, но, честно говоря, я немного не в себе в этом вопросе.

Я прочитал различные сообщения здесь (хотя почти все они относятся к c #, который и к областям, где вы можете активно внедрять IDisposable), так что я все еще ничего не понял.

Я начинаю смотреть на правильную область (IDisposable), и в этом случае, как мне следует поступить, учитывая, что это исходит из модуля, или я смотрю в совершенно неправильной области?

Спасибо

Код:

Это метод show:

 Public Function Show(ByVal text As String) As DialogResult
    If String.IsNullOrEmpty(text) Then
        Throw New ArgumentNullException("text", "You need to supply text for the message itself.")
    Else
        MessageText = text
    End If

    MessageCaption = String.Empty
    SetMessageButtons(VtlMessageBoxButtons.OK)
    IconSelected = False

    Return CreateVtlMessageBox()
End Function
  

Что приводит к CreateVtlMessageBox

 Private Function CreateVtlMessageBox() As DialogResult
    'check to see that we have a theme to use
    If String.IsNullOrEmpty(CurrentC1ThemeInUse) Then
        Throw New ArgumentException("No theme has been set for the message box to use.  Please ensure that you have set a value for the property 'CurrentC1ThemeInUse'.")
        Exit Function
    End If

    'we have a theme so we'll continue
    _maximumWidth = CType((SystemInformation.WorkingArea.Width * 0.6), Integer)
    _maximumHeight = CType((SystemInformation.WorkingArea.Height * 0.9), Integer)
    frm = New Form With {.Text = MessageCaption,
                               .MaximizeBox = False,
                               .MinimizeBox = False,
                               .ShowIcon = False,
                               .ShowInTaskbar = False,
                               .FormBorderStyle = FormBorderStyle.FixedDialog,
                               .StartPosition = FormStartPosition.CenterParent}

    AddHandler frm.Load, AddressOf FormLoad
    AddHandler frm.FormClosing, AddressOf FormClosing
    AddHandler frm.FormClosed, AddressOf FormClosed

    Dim result As DialogResult
    Using frm
        result = frm.ShowDialog
    End Using
    Return result
End Function
  

Я добавил методы FormClosing и Closed в порядке эксперимента, я думаю, по правде говоря, что они избыточны, и я их удалю.

 Private Sub FormClosing(sender As Object, e As FormClosingEventArgs)
    If sl isNot nothing Then
        sl.Dispose
    End If
End Sub
Private Sub FormClosed(sender As Object,e As FormClosedEventArgs)
    frm.Dispose
End Sub
  

For clarification sl is a label control which I had originally thought to be the issue.
FormLoad on the other hand does the donkey work and I think the root of the problem may well be there and the methods it in turn calls.

 Private Sub FormLoad(sender As Object, e As EventArgs)


    frm.Size = New Size(_maximumWidth, _maximumHeight)
    _maximumLayoutWidth = frm.ClientSize.Width - LeftPadding - RightPadding
    _maximumLayoutHeight = frm.ClientSize.Height - TopPadding - BottomPadding

    If IconSelected Then
        CreateAndPositionIconOnForm()
    End If
    SetTheText()
    PositionAndSizeTheSuperLabel()
    SetTheOptimumSizeForTheForm()
    LayoutTheForm()
    If frm Is Nothing Then
        Return
    Else
        If IconSelected Then
            frm.Controls.Add(IconPanel)
        End If
        frm.Controls.Add(sl)
    End If




    Dim lThemeName As String = CurrentC1ThemeInUse
    If Not String.IsNullOrEmpty(lThemeName) Then
        Dim lThemeLocator As New C1ThemeLocator(locationType:=C1ThemeLocator.LocationType.ThemesFolder, themeName:=lThemeName)
        Dim lTheme As C1Theme = New C1ThemeLocator(lThemeLocator).GetTheme()

        C1ThemeController.ApplyThemeToControlTree(frm, lTheme)
    End If

    If NoCancelButton Then
        'disable the close Button
        Disable(frm)
    End If


End Sub
  

Приведенное ниже добавление метода SetTheTex решило проблему с sl, явно удалив его, когда я вызываю окно сообщения во второй раз.

 Private Sub SetTheText
     If sl Is Nothing Then
        sl = New C1SuperLabel With {.Text = MessageText}
    Else
        sl.Dispose
         sl = New C1SuperLabel With {.Text = MessageText}
    End If
End Sub
  

Теперь, когда вы вызываете окно сообщения во второй раз, оно не выдает необработанное исключение, как это было до того, как я удалил sl, но оно дублирует все buutons и будет продолжать добавлять к ним каждый раз, когда оно вызывается снова.

Два фрагмента кода, которые относятся к этому, показаны ниже.

 Private Sub SetTheOptimumSizeForTheForm()
    Dim ncWidth As Integer = frm.Width - frm.ClientSize.Width
    Dim ncHeight As Integer = frm.Height - frm.ClientSize.Height

    Dim messageRowWidth As Integer
    If IconSelected Then
        messageRowWidth = sl.Width   IconToMessagePadding   IconPanel.Width
    Else
        messageRowWidth = sl.Width   RightPadding
    End If




    _buttonsRowWidth = GetWidthOfAllAvailableButtons()
    Dim captionWidth As Integer = GetCaptionSize().Width   CloseButtonWidth



    Dim maxItemWidth As Integer = Math.Max(messageRowWidth, _buttonsRowWidth)
    Dim requiredWidth As Integer = LeftPadding   maxItemWidth   RightPadding   ncWidth
    'Since Caption width is not client width, we do the check here
    If requiredWidth < captionWidth Then
        requiredWidth = captionWidth

    End If

    Dim requiredHeight As Integer
    If IconSelected Then
        requiredHeight = TopPadding   Math.Max(sl.Height, IconPanel.Height)   ItemPadding   ItemPadding   GetButtonSize().Height   BottomPadding   ncHeight
    Else
        requiredHeight = TopPadding   sl.Height   ItemPadding   ItemPadding   GetButtonSize().Height   BottomPadding   ncHeight
    End If


    If requiredHeight > _maximumHeight Then
        sl.Height -= requiredHeight - _maximumHeight
    End If
    Dim height As Integer = Math.Min(requiredHeight, _maximumHeight)
    Dim width As Integer = Math.Min(requiredWidth, _maximumWidth)

    frm.Size = New Size(width, height)


End Sub






Private Sub LayoutTheForm()

    If IconSelected Then
        IconPanel.Location = New Point(LeftPadding, TopPadding)
        sl.Location = New Point(LeftPadding   IconPanel.Width   IconToMessagePadding * (If(IconPanel.Width = 0, 0, 1)), TopPadding)
    Else
        sl.Location = New Point(LeftPadding   IconToMessagePadding, TopPadding)
    End If



    Dim buttonSize As Size = GetButtonSize()

    'buttons need to be positioned from the right of the message box
    Dim allButtonsWidth As Integer = _buttonsRowWidth   ButtonPadding
    Dim firstButtonX As Integer = CType(frm.ClientSize.Width - allButtonsWidth, Integer)
    Dim firstButtonY As Integer = frm.ClientSize.Height - BottomPadding - buttonSize.Height


    Dim nextButtonLocation As Point = New Point(firstButtonX, firstButtonY)
    Dim foundDefaultButton As Boolean = False
    Dim i As Integer


    For Each button As String In MessageButtons
        Dim buttonCtrl As C1Button = AddMessageBoxButton(button, buttonSize, nextButtonLocation)
        nextButtonLocation.X  = buttonSize.Width   ButtonPadding
        i = buttonCtrl.Location.Y
        buttonCtrl.Anchor = AnchorStyles.Bottom And AnchorStyles.Right
        frm.Controls.Add(buttonCtrl)
    Next

End Sub
  

Я надеюсь, что это помогает следовать моей логике или ее отсутствию!

Комментарии:

1. похоже, что на самом деле это диалоговое окно, используемое в MessageBox. Что это такое и как оно используется (ваш код) и что означают «странные вещи», помогло бы узнать, в чем проблема (ы). IDisposable не звучит так, как будто это применимо.

2. Вопрос: Вы абсолютно правы, что это диалоговое окно. Я изначально не добавлял код, поскольку его довольно много, но я добавлю столько, сколько, как я думаю, даст вам представление о том, что происходит.

3. вероятно, это проблема в том, как это вызывается / используется. начните с того, как она вызывается

4. Наконец-то я нашел проблему, в которую верю. Суперметка (sl) явно удалялась, но при явном выполнении этого во второй раз это сработало. Я также должен был избавиться от массива, используемого для хранения кнопок окна сообщений, хотя и это я пропустил.

Ответ №1:

Я бы настоятельно рекомендовал вам удалить весь этот код из модуля. На самом деле это не использование модуля. Вместо этого создайте подкласс form.

 Class MyMessageBox
    Inherits Form

    Public Sub New(ByVal messageCaption As String)

        'we have a theme so we'll continue
        _maximumWidth = CType((SystemInformation.WorkingArea.Width * 0.6), Integer)
        _maximumHeight = CType((SystemInformation.WorkingArea.Height * 0.9), Integer)

        Text = messageCaption,
        MaximizeBox = False,
        MinimizeBox = False,
        ShowIcon = False,
        ShowInTaskbar = False,
        FormBorderStyle = FormBorderStyle.FixedDialog,
        StartPosition = FormStartPosition.CenterParent}

    End Sub

    Public Shared Function Show(ByVal text As String) As DialogResult
        If String.IsNullOrEmpty(text) Then
            Throw New ArgumentNullException("text", "You need to supply text for the message itself.")
        Else
            MessageText = text
        End If

        MessageCaption = String.Empty
        SetMessageButtons(VtlMessageBoxButtons.OK)
        IconSelected = False

        'check to see that we have a theme to use
        If String.IsNullOrEmpty(CurrentC1ThemeInUse) Then
            Throw New ArgumentException("No theme has been set for the message box to use.  Please ensure that you have set a value for the property 'CurrentC1ThemeInUse'.")
            Exit Function
        End If

        Dim frm = New MyMessageBox(MessageCaption)

        Dim result As DialogResult
        Using frm
            result = frm.ShowDialog
        End Using
        Return result
    End Function

    Private Sub FormLoad(sender As Object, e As EventArgs) Handles Me.Load
    End Sub

End Class
  

Идея заключается в том, что совместно используемая функция создает экземпляр унаследованной формы со всеми специальными функциями, которые вы хотите добавить к ней. Таким образом, эта форма может обрабатывать IDispose. Все ваши события также будут частью этой формы, а не находиться в модуле. Каждая форма также будет иметь свой собственный экземпляр своей переменной, что уменьшит конфликт.

Комментарии:

1. Большое вам спасибо за ваш ответ и код для иллюстрации. Если ничего другого, это, наконец, не привело к снижению цен на то, как следует относиться к подклассу, для которого это определенный плюс.