我将尽可能准确,我有一个主要形式,我们称之为" Form1"在Form1中,用户有可能通过菜单条启动另一个表单,我们将其称为“Form2"”,在Form2中我有另一个menustrip和datagridview。
用户启动Form2时的问题我必须在菜单条之前用左键单击2次"激活"我的意思是
如果你们有任何解决方案或需要更多信息,请告诉我。
这是名为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
更精确
答案 0 :(得分:4)
这是MenuStrip和ToolStrip类中的一个缺陷,它们无法正确处理WM_MOUSEACTIVATE通知。这些类有很多怪癖,它们支持无窗口控件并让它们模拟完全相同的行为,因为普通的Windows窗口永远不会成为问题。这些怪癖没有得到解决,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
单击Build + Build。您现在将MyMenuStrip项目放在工具箱的顶部。将其放在表单上,替换现有的MenuStrip。
答案 1 :(得分:0)
根据这个
看起来,就像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