【问题标题】:MenuStrip can't get focus on loadMenuStrip 无法专注于负载
【发布时间】:2013-10-07 00:39:21
【问题描述】:

我会尽量准确,我有一个主窗体,我们将其称为“Form1”,在 Form1 中用户有可能通过菜单条启动另一个窗体,我们将其称为“Form2”,在 Form2 中,我有另一个菜单条和一个 datagridview。

当用户启动 Form2 时我的问题我必须在菜单条“激活”之前用左键单击 2 次我的意思是

  • form2 加载
  • 我点击菜单条项:“菜单”
  • 什么都没有发生
  • 我再次单击菜单条向下滚动

这真的很烦人,我无法解决这个问题,因为我不知道是什么原因造成的

如果你们有任何解决方案或需要更多信息,请告诉我。

这是名为 Ajout.vb 的 Form2

Imports System.Data.OleDb
Imports System.Globalization

Public Class Ajout
    Private dSet As DataSet
    Private dAdapter As New OleDbDataAdapter
    Private bJustEdit As Boolean = False

    Sub New(ByRef dSet As DataSet, ByRef dAdapter As OleDbDataAdapter)
        InitializeComponent()
        Me.dSet = dSet
        Me.dAdapter = dAdapter
    End Sub

    Private Sub Ajout_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        With DataGridView1
            .DataSource = dSet
            .DataMember = "Articles_table"
            .Columns("Prix").DefaultCellStyle.Format = "C2"
            Console.WriteLine(.Columns("Prix").ValueType)
            For Each clm As DataGridViewColumn In .Columns
                clm.SortMode = DataGridViewColumnSortMode.NotSortable
            Next
        End With
    End Sub

    Private Sub DataGridView1_DataError(ByVal sender As Object, ByVal e As DataGridViewDataErrorEventArgs) Handles DataGridView1.DataError
        'Quelle est l'erreur
        If (TypeOf (e.Exception) Is ConstraintException) Then
            'Envoie une message box pour informer l'utilisateur avec une possibiliter
            If (drMessageBoxFuntion(0) = Windows.Forms.DialogResult.Yes) Then
                'Possibiliter choisi on regarde si le sender est bien de datagridview pour eviter un erreur de cast
                If (TypeOf sender Is DataGridView) Then
                    'Nouvelle variable car sa devien inlisible avec beaucoup de cast
                    Dim dgvLocal As DataGridView = CType(sender, DataGridView)
                    Dim sNameValue As String = dgvLocal.Rows(e.RowIndex).Cells("Nom").Value.ToString
                    Dim dgvOriginalCells As DataGridViewCellCollection = dgvLocal.Rows(dgvFindRowsBy_Name(sNameValue).Index).Cells
                    Dim dgvErrorCells As DataGridViewCellCollection = dgvLocal.Rows(e.RowIndex).Cells

                    'Regarde si le prix est pareille si faux propose a l'utilisateur d'updater le prix avec le nouveau
                    'ou de simplement ajouter la quantite
                    If (Not Equals(dgvOriginalCells("Prix").Value.ToString, dgvErrorCells("Prix").Value.ToString)) Then
                        'Prix different propose de mettre a jour
                        If (drMessageBoxFuntion(1) = Windows.Forms.DialogResult.Yes) Then
                            dgvOriginalCells("Prix").Value = dErrorRow()
                            dgvOriginalCells("Quantité").Value += dgvErrorCells("Quantité").Value
                        Else
                            dgvOriginalCells("Quantité").Value += dgvErrorCells("Quantité").Value
                        End If
                    Else
                        dgvOriginalCells("Quantité").Value += dgvErrorCells("Quantité").Value
                    End If
                    'Sender inconnu 
                Else
                    MsgBox("Une erreur inconnu est survenu, aucune operation n'a été effectué, vous n'avez qu'à recommencer")
                End If
            End If

            'Si lettre entré, msg pour informer le reste est gerer par le dataset qui n'accepte que
            'les chiffre, car defini dans la database
        ElseIf (TypeOf (e.Exception) Is FormatException) Then
            MsgBox("Vous ne pouvez pas entrer de lettre dans la collone de prix ou de quantité")
        End If
    End Sub


    'Fonction contenant plusieur message box
    Private Function drMessageBoxFuntion(ByVal index As Integer) As DialogResult
        If (index = 0) Then
            Dim drAction As DialogResult = MessageBox.Show("Vous ne pouvez pas ajouter deux fois le même nom," & _
                                               " voulez vous ajouter la quantité du nouvelle arti" & _
                                               "cle a celui deja présent ?", _
                                               "Erreur, article double.", _
                                               MessageBoxButtons.YesNo, _
                                               MessageBoxIcon.Question)
            Return drAction
        ElseIf (index = 1) Then
            Dim drAction As DialogResult = MessageBox.Show("Le prix de vos deux article, de même genre, diffère." & _
                                                           "Voulez-vous mettre a jour le prix à jour (oui), ou " & _
                                                           "simplement ajouter la quantité a l'item déjà présent (no" & _
                                                           "n).", "Erreur, prix different", _
                                                            MessageBoxButtons.YesNo, _
                                                            MessageBoxIcon.Question)
            Return drAction
        End If
        Return Nothing
    End Function

    'Retourne une datagridviewROW et non l'index car permet d'avoir l'objet
    'et donc de prendre la methode index ou autre methode si le besoin est
    Private Function dgvFindRowsBy_Name(ByVal oNameValue As Object) As DataGridViewRow
        For Each row As DataGridViewRow In DataGridView1.Rows
            If row.Cells.Item("Nom").Value = oNameValue Then
                Return row
            End If
        Next
        Return Nothing
    End Function

    'Message pre programmer dans une array permettant l'affichage de message avec une input
    Private Function dErrorRow() As Single
        Dim dNewValue As Object = InputBox("Nouveau prix, entrez uniquement un nombre s'il vous plait.")

        Do Until IsNumeric(dNewValue)
            dNewValue = InputBox("Nouveau prix, entrez uniquement un nombre s'il vous plait.")
        Loop

        Return CType(dNewValue, Single)
    End Function

    Private Sub DataGridView1_RowValidating(sender As Object, e As DataGridViewCellCancelEventArgs) Handles DataGridView1.RowValidating
        If (TypeOf sender Is DataGridView) Then
            Dim dgvRow As DataGridViewRow = CType(sender, DataGridView).Rows(e.RowIndex)
            If (Not ((IsDBNull(dgvRow.Cells("Nom").Value) Or IsDBNull(dgvRow.Cells("Prix").Value) Or IsDBNull(dgvRow.Cells("Quantité").Value)) = (IsDBNull(dgvRow.Cells("Nom").Value) And IsDBNull(dgvRow.Cells("Prix").Value) And IsDBNull(dgvRow.Cells("Quantité").Value)))) Then
                MsgBox("Veuillez remplir toute les cases.")
                e.Cancel = True
            End If
        End If
    End Sub

    Private Sub DataGridView1_CellValidating(sender As Object, e As DataGridViewCellValidatingEventArgs) Handles DataGridView1.CellValidating
        If (TypeOf sender Is DataGridView) Then
            Dim dgvRow As DataGridViewRow = CType(sender, DataGridView).Rows(e.RowIndex)

            If (Not dgvRow.IsNewRow) Then
                If (e.ColumnIndex = 1) Then
                    Dim dTemp As Single

                    If (Not Single.TryParse(e.FormattedValue.ToString, NumberStyles.Currency, CultureInfo.CurrentCulture, dTemp) OrElse dTemp < 0) Then
                        MsgBox("La valeur ne doit pas être négative ni être une lettre. Ne laisser pas la case vide non plus.")
                        e.Cancel = True
                    End If
                ElseIf (e.ColumnIndex = 2) Then
                    Dim iTemp As Integer

                    If (Not Integer.TryParse(e.FormattedValue.ToString, NumberStyles.Currency, CultureInfo.CurrentCulture, iTemp) OrElse iTemp < 0) Then
                        MsgBox("La valeur ne doit pas être négative ni être une lettre. Ne laisser pas la case vide non plus.")
                        e.Cancel = True
                    End If
                End If
            End If
            dgvRow.Selected = False
        End If
    End Sub

    Private Sub EnregistrerToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles EnregistrerToolStripMenuItem.Click
        If dSet.HasChanges Then
            Try
                Using con = New OleDbConnection("Provider=Microsoft.ACE.OLEDB.12.0;Data Source = Mokmeuh.accdb")
                    con.Open()
                    Dim cmb As New OleDbCommandBuilder(dAdapter)
                    dAdapter.Update(dSet.Tables("Articles_Table"))
                End Using
            Catch ex As Exception

            End Try
        End If
    End Sub

    Private Sub AnnulerToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles AnnulerToolStripMenuItem.Click
        dSet.RejectChanges()
        DataGridView1.Refresh()
    End Sub
End Class

更精确

【问题讨论】:

  • 您所描述的行为不响应任何标准情况。您的问题是由代码中的某些内容引起的。请张贴(相关位)。
  • 我已经更新了,我给你Form2的代码
  • 您为两个不同的 MenuItems 包含两个不同的 Click 事件(您指的是哪一个?)。也没有足够的信息可以告诉;例如:dSet.HasChanges 是这些事件之一的航向条件(它是否改变?!)。请澄清这一切。
  • 我不认为事件的内部应该为此改变任何东西,因为它们无论如何都与数据网格视图相关你回答你的问题是的,如果不是数据库没有更新,dSet 将是真的我也有一个 MenuToolStripMenuItem 像这样注册 3 个子项目 Me.MenuToolStripMenuItem.DropDownItems.AddRange(New System.Windows.Forms.ToolStripItem() {Me.EnregistrerToolStripMenuItem, Me.AnnulerToolStripMenuItem, Me.QuitterToolStripMenuItem}) 什么不起作用是主菜单,我必须单击 2 次才能下拉其他 3 个项目
  • 我放了一张图片,如果我能更清楚地告诉我,我会尽量给你尽可能多的信息

标签: .net vb.net


【解决方案1】:

这是 MenuStrip 和 ToolStrip 类中的一个缺陷,它们不能正确处理 WM_MOUSEACTIVATE 通知。这些类有很多怪癖,它们支持 window-less 控件,并且让它们模拟与普通 Windows 窗口相同的 exact 行为从来都不是问题。这些怪癖没有得到解决,Winforms 团队在 .NET 2.0 发布后不久就解散了,将资源专用于 WPF。

这应该是一个评论,但是已经有太多的解决方案了,LarsTech 已经想出了一个很好的解决方案。您可以在 this answer 中找到它。

要做到这一点是 VB.NET,右键单击您的项目,然后单击添加 + 类。粘贴此代码:

Public Class MyMenuStrip
    Inherits MenuStrip

    Protected Overrides Sub WndProc(ByRef m As Message)
        '' Set focus on WM_MOUSEACTIVATE message
        If m.Msg = &H21 AndAlso Me.CanFocus AndAlso Not Me.Focused Then
            Me.Focus()
        End If
        MyBase.WndProc(m)
    End Sub

End Class

单击构建 + 构建。您现在将在工具箱顶部拥有 MyMenuStrip 项。将其放在您的表单上,替换现有的 MenuStrip。

【讨论】:

  • 我猜这是在c#中,我对c#的了解还不够,无法处理降低的部分
  • VB.NET 特定版本已添加到帖子中。
【解决方案2】:

显然是这样

Windows requires a click to activate a window before a second click will select a button. How can I change this?

看起来,就像 Mac OS X 一样,Windows 已经做出了一种 GUI 样式决定,要求首先激活一个窗口,然后才能选择任何控件。但是,Windows 仅对特定控件执行此操作,例如 ToolStrip 和 MenuStrip。当您的窗口不活动时,这些控件不会发送鼠标 DOWN 事件。我不确定 WinForms 如何执行此 GUI 指南,但也许它使用 Application.AddMessageFilter() 使用消息过滤器。

所以我找到了一个解决方法,它可能很草率,但这就是我找到的。

Private Sub MenuToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles MenuToolStripMenuItem.Click
    If (TypeOf sender Is ToolStripMenuItem) Then
        CType(sender, ToolStripMenuItem).ShowDropDown()
    End If
End Sub

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多