?
Solved

Textbox to not accept characters like '+vb.net

Posted on 2016-08-18
13
Medium Priority
?
42 Views
Last Modified: 2016-08-19
Hello,

How can  I make a textbox to not accept character like '


Cheers
0
Comment
Question by:RIAS
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 7
  • 2
  • 2
  • +2
13 Comments
 
LVL 40

Assisted Solution

by:Kyle Abrahams
Kyle Abrahams earned 1332 total points
ID: 41761703
For asp.Net you can use javascript (http://www.w3schools.com/jsref/event_onkeydown.asp).

For Windows Forms use the TextChanged or keydown event to evaluate the characters https://msdn.microsoft.com/en-us/library/system.windows.forms.control.keydown(v=vs.110).aspx.  

At that point you can do a replace on any invalid character you don't want.

Text changed is fired only once (on leaving the textbox) whereas keydown will fire every time a key is pressed.
0
 
LVL 34

Assisted Solution

by:it_saige
it_saige earned 668 total points
ID: 41761707
Bind to the KeyDown event and check for the keys you don't want to allow; e.g. -

Form1.vb -
Public Class Form1
	Private Sub OnKeyDown(sender As Object, e As KeyEventArgs) Handles TextBox2.KeyDown, TextBox1.KeyDown
		If TypeOf sender Is TextBox Then
			Dim tb = DirectCast(sender, TextBox)
			If tb.Equals(TextBox1) Then
				' I wont take a b or c
				Dim excludes = {Keys.A, Keys.B, Keys.C}
				If excludes.Contains(e.KeyCode) Then
					Console.WriteLine("Ah ah ah...  You can't use {0}", e.KeyCode)
					e.SuppressKeyPress = True
					e.Handled = True
				End If
			ElseIf tb.Equals(TextBox2) Then
				' I wont take d e or f
				Dim excludes = {Keys.D, Keys.E, Keys.F}
				If excludes.Contains(e.KeyCode) Then
					Console.WriteLine("Ah ah ah...  You can't use {0}", e.KeyCode)
					e.SuppressKeyPress = True
					e.Handled = True
				End If
			End If
		End If
	End Sub
End Class

Open in new window

Form1.Designer.vb -
<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()> _
Partial Class Form1
    Inherits System.Windows.Forms.Form

    'Form overrides dispose to clean up the component list.
    <System.Diagnostics.DebuggerNonUserCode()> _
    Protected Overrides Sub Dispose(ByVal disposing As Boolean)
        Try
            If disposing AndAlso components IsNot Nothing Then
                components.Dispose()
            End If
        Finally
            MyBase.Dispose(disposing)
        End Try
    End Sub

    'Required by the Windows Form Designer
    Private components As System.ComponentModel.IContainer

    'NOTE: The following procedure is required by the Windows Form Designer
    'It can be modified using the Windows Form Designer.  
    'Do not modify it using the code editor.
    <System.Diagnostics.DebuggerStepThrough()> _
    Private Sub InitializeComponent()
		Me.Label1 = New System.Windows.Forms.Label()
		Me.TextBox1 = New System.Windows.Forms.TextBox()
		Me.TextBox2 = New System.Windows.Forms.TextBox()
		Me.Label2 = New System.Windows.Forms.Label()
		Me.SuspendLayout()
		'
		'Label1
		'
		Me.Label1.AutoSize = True
		Me.Label1.Location = New System.Drawing.Point(9, 9)
		Me.Label1.Name = "Label1"
		Me.Label1.Size = New System.Drawing.Size(183, 13)
		Me.Label1.TabIndex = 0
		Me.Label1.Text = "This textbox will not accept (a b or c):"
		'
		'TextBox1
		'
		Me.TextBox1.Location = New System.Drawing.Point(12, 25)
		Me.TextBox1.Name = "TextBox1"
		Me.TextBox1.Size = New System.Drawing.Size(260, 20)
		Me.TextBox1.TabIndex = 1
		'
		'TextBox2
		'
		Me.TextBox2.Location = New System.Drawing.Point(12, 64)
		Me.TextBox2.Name = "TextBox2"
		Me.TextBox2.Size = New System.Drawing.Size(260, 20)
		Me.TextBox2.TabIndex = 3
		'
		'Label2
		'
		Me.Label2.AutoSize = True
		Me.Label2.Location = New System.Drawing.Point(9, 48)
		Me.Label2.Name = "Label2"
		Me.Label2.Size = New System.Drawing.Size(180, 13)
		Me.Label2.TabIndex = 2
		Me.Label2.Text = "This textbox will not accept (d e or f):"
		'
		'Form1
		'
		Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!)
		Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
		Me.ClientSize = New System.Drawing.Size(284, 90)
		Me.Controls.Add(Me.TextBox2)
		Me.Controls.Add(Me.Label2)
		Me.Controls.Add(Me.TextBox1)
		Me.Controls.Add(Me.Label1)
		Me.Name = "Form1"
		Me.Text = "Form1"
		Me.ResumeLayout(False)
		Me.PerformLayout()

	End Sub
	Friend WithEvents Label1 As System.Windows.Forms.Label
	Friend WithEvents TextBox1 As System.Windows.Forms.TextBox
	Friend WithEvents TextBox2 As System.Windows.Forms.TextBox
	Friend WithEvents Label2 As System.Windows.Forms.Label

End Class

Open in new window

Produces the following output -Capture.JPG
-saige-
0
 
LVL 1

Expert Comment

by:Mlungisi Ndlela
ID: 41761708
Try this out
Dim Not_Accepted As String = "'" ' The charector not required
    Private Sub TextBox1_TextChanged(sender As System.Object, e As System.EventArgs) Handles TextBox1.TextChanged
        Dim xText As String = TextBox1.Text
        Dim xKeys As String
        Dim xSelectionIndex As Integer = TextBox1.SelectionStart
        Dim xChange As Integer
        ' Loop
        For i As Integer = 0 To TextBox1.Text.Length - 1
            xKeys = TextBox1.Text.Substring(i, 1)
            If Not_Accepted.Contains(xKeys) Then
                xText = xText.Replace(xKeys, String.Empty)
                xChange = 1
            End If
        Next
        TextBox1.Text = xText
        TextBox1.Select(xSelectionIndex - xChange, 0)
    End Sub

Open in new window


Note that a character entered at
Not_Accepted

Open in new window

will not be taken by the TextBox
0
Veeam Task Manager for Hyper-V

Task Manager for Hyper-V provides critical information that allows you to monitor Hyper-V performance by displaying real-time views of CPU and memory at the individual VM-level, so you can quickly identify which VMs are using host resources.

 

Author Comment

by:RIAS
ID: 41761714
Hello,

Need it for all textboxes nearly 50 to 60 textboxes.
Any way to do it for all in the properties of textbox rather than
Adding a keypress or keydown event for all the textboxes

Thanks
0
 

Author Comment

by:RIAS
ID: 41761717
Thanks Saige Sir will try
0
 

Author Comment

by:RIAS
ID: 41761719
Any suggestion on  e.KeyCode for character '
0
 

Author Comment

by:RIAS
ID: 41761722
Saige Sir,

Is it possible to have a similar function for
 TxtPatientName_KeyPress rather than keydown
0
 
LVL 40

Accepted Solution

by:
Kyle Abrahams earned 1332 total points
ID: 41761735
You can have the event one time:

EG:

GenericTextBoxFilter

and then add an event to each textbox.

AddHandler Text1.KeyDown AddressOf GenericTextBoxFiler
AddHandler Text2.KeyDown AddressOf GenericTextBoxFilter

or you can get a little slicker and loop over the controls:
For Each c As Control In Form1.Controls
	If TypeOf c Is TextBox Then
		AddHandler DirectCast(c, TextBox).KeyDown, AddressOf GenericTextBoxFilter
	End If
Next

Open in new window


For the quote (') use OemQuotes
https://msdn.microsoft.com/en-us/library/system.windows.forms.keys(v=vs.110).aspx
1
 

Author Comment

by:RIAS
ID: 41761739
Cheers Kyle ! Will try and get back
0
 

Author Comment

by:RIAS
ID: 41761746
Kyle,
How to pass arguments in the GenericTextBoxFilter
0
 
LVL 12

Expert Comment

by:funwithdotnet
ID: 41761973
Yes, I would do it like Kyle.
0
 
LVL 34

Expert Comment

by:it_saige
ID: 41762586
Understanding that you have already accepted Kyle's answer, there are also other ways to attack this issue:

1.  Using attributes:

Form1.vb -
Imports System.Reflection
Public Class Form1
	Public Sub New()

		' This call is required by the designer.
		InitializeComponent()

		' Add any initialization after the InitializeComponent() call.
		BindKeyDownEvent()
	End Sub

	Private Sub OnKeyDown(sender As Object, e As KeyEventArgs)
		If TypeOf sender Is TextBox Then
			Dim tb = DirectCast(sender, TextBox)
			Dim suppressed = (From [field] In Me.GetType().GetFields(BindingFlags.Instance Or BindingFlags.NonPublic Or BindingFlags.Public Or BindingFlags.Static)
						   Where [field].IsControl() AndAlso [field].GetValue(Me).Equals(tb)
						   From [attribute] As SuppressedKeysAttribute In [field].GetCustomAttributes(GetType(SuppressedKeysAttribute), True)
						   From [key] In [attribute].Keys
						   Select [key])

			If suppressed.Contains(e.KeyCode) Then
				Console.WriteLine("Ah ah ah...  You can't use {0}", e.KeyCode)
				e.SuppressKeyPress = True
				e.Handled = True
			End If
		End If
	End Sub

	Private Sub BindKeyDownEvent()
		Dim bindTo = (From [field] In Me.GetType().GetFields(BindingFlags.Instance Or BindingFlags.NonPublic Or BindingFlags.Public Or BindingFlags.Static)
				    From [attribute] As SuppressedKeysAttribute In [field].GetCustomAttributes(GetType(SuppressedKeysAttribute), True)
				    Where [field].IsControl() AndAlso [attribute] IsNot Nothing
				    Select CType([field].GetValue(Me), Control))
		For Each bind In bindTo
			AddHandler bind.KeyDown, AddressOf OnKeyDown
		Next
	End Sub
End Class

<AttributeUsage(AttributeTargets.All, AllowMultiple:=True)>
Class SuppressedKeysAttribute
	Inherits Attribute
	Public Property Keys() As Keys()
End Class

Module Extensions
	<System.Runtime.CompilerServices.Extension()> _
	Public Function IsControl(member As MemberInfo) As Boolean
		If member Is Nothing Then Return False
		Try
			If TypeOf member Is FieldInfo Then
				Return (DirectCast(member, FieldInfo)).FieldType Is GetType(Control) OrElse (DirectCast(member, FieldInfo)).FieldType.IsSubclassOf(GetType(Control))
			ElseIf TypeOf member Is PropertyInfo Then
				Return (DirectCast(member, PropertyInfo)).PropertyType Is GetType(Control) OrElse (DirectCast(member, PropertyInfo)).PropertyType.IsSubclassOf(GetType(Control))
			Else
				Return False
			End If
		Catch ex As Exception
			Return False
		End Try
	End Function
End Module

Open in new window

Form1.Designer.vb -
<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()> _
Partial Class Form1
    Inherits System.Windows.Forms.Form

    'Form overrides dispose to clean up the component list.
    <System.Diagnostics.DebuggerNonUserCode()> _
    Protected Overrides Sub Dispose(ByVal disposing As Boolean)
        Try
            If disposing AndAlso components IsNot Nothing Then
                components.Dispose()
            End If
        Finally
            MyBase.Dispose(disposing)
        End Try
    End Sub

    'Required by the Windows Form Designer
    Private components As System.ComponentModel.IContainer

    'NOTE: The following procedure is required by the Windows Form Designer
    'It can be modified using the Windows Form Designer.  
    'Do not modify it using the code editor.
    <System.Diagnostics.DebuggerStepThrough()> _
    Private Sub InitializeComponent()
		Me.Label1 = New System.Windows.Forms.Label()
		Me.TextBox1 = New System.Windows.Forms.TextBox()
		Me.TextBox2 = New System.Windows.Forms.TextBox()
		Me.Label2 = New System.Windows.Forms.Label()
		Me.SuspendLayout()
		'
		'Label1
		'
		Me.Label1.AutoSize = True
		Me.Label1.Location = New System.Drawing.Point(9, 9)
		Me.Label1.Name = "Label1"
		Me.Label1.Size = New System.Drawing.Size(183, 13)
		Me.Label1.TabIndex = 0
		Me.Label1.Text = "This textbox will not accept (a b or c):"
		'
		'TextBox1
		'
		Me.TextBox1.Location = New System.Drawing.Point(12, 25)
		Me.TextBox1.Name = "TextBox1"
		Me.TextBox1.Size = New System.Drawing.Size(260, 20)
		Me.TextBox1.TabIndex = 1
		'
		'TextBox2
		'
		Me.TextBox2.Location = New System.Drawing.Point(12, 64)
		Me.TextBox2.Name = "TextBox2"
		Me.TextBox2.Size = New System.Drawing.Size(260, 20)
		Me.TextBox2.TabIndex = 3
		'
		'Label2
		'
		Me.Label2.AutoSize = True
		Me.Label2.Location = New System.Drawing.Point(9, 48)
		Me.Label2.Name = "Label2"
		Me.Label2.Size = New System.Drawing.Size(180, 13)
		Me.Label2.TabIndex = 2
		Me.Label2.Text = "This textbox will not accept (d e or f):"
		'
		'Form1
		'
		Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!)
		Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
		Me.ClientSize = New System.Drawing.Size(284, 90)
		Me.Controls.Add(Me.TextBox2)
		Me.Controls.Add(Me.Label2)
		Me.Controls.Add(Me.TextBox1)
		Me.Controls.Add(Me.Label1)
		Me.Name = "Form1"
		Me.Text = "Form1"
		Me.ResumeLayout(False)
		Me.PerformLayout()

	End Sub
	Friend WithEvents Label1 As System.Windows.Forms.Label
	<SuppressedKeys(Keys:={Keys.A, Keys.B, Keys.C})> _
	Friend WithEvents TextBox1 As System.Windows.Forms.TextBox
	<SuppressedKeys(Keys:={Keys.D, Keys.E, Keys.F})> _
	Friend WithEvents TextBox2 As System.Windows.Forms.TextBox
	Friend WithEvents Label2 As System.Windows.Forms.Label
End Class

Open in new window


2.  Using a list (or dictionary) set at the form level -

Form1.vb -
Public Class Form1
	ReadOnly suppressed As Dictionary(Of Control, Keys())

	Public Sub New()
		' This call is required by the designer.
		InitializeComponent()

		' Add any initialization after the InitializeComponent() call.
		suppressed = New Dictionary(Of Control, Keys()) From
			{
				{TextBox1, New Keys() {Keys.A, Keys.B, Keys.C}},
				{TextBox2, New Keys() {Keys.D, Keys.E, Keys.F}}
			}

		BindKeyDownEvent()
	End Sub

	Private Sub OnKeyDown(sender As Object, e As KeyEventArgs)
		If TypeOf sender Is TextBox Then
			Dim tb = DirectCast(sender, TextBox)
			If suppressed(tb).Contains(e.KeyCode) Then
				Console.WriteLine("Ah ah ah...  You can't use {0}", e.KeyCode)
				e.SuppressKeyPress = True
				e.Handled = True
			End If
		End If
	End Sub

	Private Sub BindKeyDownEvent()
		For Each pair In suppressed
			AddHandler pair.Key.KeyDown, AddressOf OnKeyDown
		Next
	End Sub
End Class

Open in new window


Form1.Designer.vb -
<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()> _
Partial Class Form1
    Inherits System.Windows.Forms.Form

    'Form overrides dispose to clean up the component list.
    <System.Diagnostics.DebuggerNonUserCode()> _
    Protected Overrides Sub Dispose(ByVal disposing As Boolean)
        Try
            If disposing AndAlso components IsNot Nothing Then
                components.Dispose()
            End If
        Finally
            MyBase.Dispose(disposing)
        End Try
    End Sub

    'Required by the Windows Form Designer
    Private components As System.ComponentModel.IContainer

    'NOTE: The following procedure is required by the Windows Form Designer
    'It can be modified using the Windows Form Designer.  
    'Do not modify it using the code editor.
    <System.Diagnostics.DebuggerStepThrough()> _
    Private Sub InitializeComponent()
		Me.Label1 = New System.Windows.Forms.Label()
		Me.TextBox1 = New System.Windows.Forms.TextBox()
		Me.TextBox2 = New System.Windows.Forms.TextBox()
		Me.Label2 = New System.Windows.Forms.Label()
		Me.SuspendLayout()
		'
		'Label1
		'
		Me.Label1.AutoSize = True
		Me.Label1.Location = New System.Drawing.Point(9, 9)
		Me.Label1.Name = "Label1"
		Me.Label1.Size = New System.Drawing.Size(183, 13)
		Me.Label1.TabIndex = 0
		Me.Label1.Text = "This textbox will not accept (a b or c):"
		'
		'TextBox1
		'
		Me.TextBox1.Location = New System.Drawing.Point(12, 25)
		Me.TextBox1.Name = "TextBox1"
		Me.TextBox1.Size = New System.Drawing.Size(260, 20)
		Me.TextBox1.TabIndex = 1
		'
		'TextBox2
		'
		Me.TextBox2.Location = New System.Drawing.Point(12, 64)
		Me.TextBox2.Name = "TextBox2"
		Me.TextBox2.Size = New System.Drawing.Size(260, 20)
		Me.TextBox2.TabIndex = 3
		'
		'Label2
		'
		Me.Label2.AutoSize = True
		Me.Label2.Location = New System.Drawing.Point(9, 48)
		Me.Label2.Name = "Label2"
		Me.Label2.Size = New System.Drawing.Size(180, 13)
		Me.Label2.TabIndex = 2
		Me.Label2.Text = "This textbox will not accept (d e or f):"
		'
		'Form1
		'
		Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!)
		Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
		Me.ClientSize = New System.Drawing.Size(284, 90)
		Me.Controls.Add(Me.TextBox2)
		Me.Controls.Add(Me.Label2)
		Me.Controls.Add(Me.TextBox1)
		Me.Controls.Add(Me.Label1)
		Me.Name = "Form1"
		Me.Text = "Form1"
		Me.ResumeLayout(False)
		Me.PerformLayout()

	End Sub
	Friend WithEvents Label1 As System.Windows.Forms.Label
	Friend WithEvents TextBox1 As System.Windows.Forms.TextBox
	Friend WithEvents TextBox2 As System.Windows.Forms.TextBox
	Friend WithEvents Label2 As System.Windows.Forms.Label
End Class

Open in new window


3.  Creating your own control and overriding the keydown event -

Form1.vb -
Public Class Form1
	Public Sub New()
		' This call is required by the designer.
		InitializeComponent()

		' Add any initialization after the InitializeComponent() call.
		TextBox1.SuppressedKeys.AddRange({Keys.A, Keys.B, Keys.C})
		TextBox2.SuppressedKeys.AddRange({Keys.D, Keys.E, Keys.F})
	End Sub
End Class

Class SuppressedKeysTextBox
	Inherits TextBox
	Public Property SuppressedKeys() As New List(Of Keys)

	Protected Overrides Sub OnKeyDown(e As KeyEventArgs)
		If SuppressedKeys.Contains(e.KeyCode) Then
			Console.WriteLine("Ah ah ah...  You can't use {0}", e.KeyCode)
			e.SuppressKeyPress = True
			e.Handled = True
		End If
		MyBase.OnKeyDown(e)
	End Sub
End Class

Open in new window

Form1.Designer.vb -
<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()> _
Partial Class Form1
	Inherits System.Windows.Forms.Form

	'Form overrides dispose to clean up the component list.
	<System.Diagnostics.DebuggerNonUserCode()> _
	Protected Overrides Sub Dispose(ByVal disposing As Boolean)
		Try
			If disposing AndAlso components IsNot Nothing Then
				components.Dispose()
			End If
		Finally
			MyBase.Dispose(disposing)
		End Try
	End Sub

	'Required by the Windows Form Designer
	Private components As System.ComponentModel.IContainer

	'NOTE: The following procedure is required by the Windows Form Designer
	'It can be modified using the Windows Form Designer.  
	'Do not modify it using the code editor.
	<System.Diagnostics.DebuggerStepThrough()> _
	Private Sub InitializeComponent()
		Me.Label1 = New System.Windows.Forms.Label()
		Me.TextBox1 = New SuppressedKeysTextBox()
		Me.TextBox2 = New SuppressedKeysTextBox()
		Me.Label2 = New System.Windows.Forms.Label()
		Me.SuspendLayout()
		'
		'Label1
		'
		Me.Label1.AutoSize = True
		Me.Label1.Location = New System.Drawing.Point(9, 9)
		Me.Label1.Name = "Label1"
		Me.Label1.Size = New System.Drawing.Size(183, 13)
		Me.Label1.TabIndex = 0
		Me.Label1.Text = "This textbox will not accept (a b or c):"
		'
		'TextBox1
		'
		Me.TextBox1.Location = New System.Drawing.Point(12, 25)
		Me.TextBox1.Name = "TextBox1"
		Me.TextBox1.Size = New System.Drawing.Size(260, 20)
		Me.TextBox1.TabIndex = 1
		'
		'TextBox2
		'
		Me.TextBox2.Location = New System.Drawing.Point(12, 64)
		Me.TextBox2.Name = "TextBox2"
		Me.TextBox2.Size = New System.Drawing.Size(260, 20)
		Me.TextBox2.TabIndex = 3
		'
		'Label2
		'
		Me.Label2.AutoSize = True
		Me.Label2.Location = New System.Drawing.Point(9, 48)
		Me.Label2.Name = "Label2"
		Me.Label2.Size = New System.Drawing.Size(180, 13)
		Me.Label2.TabIndex = 2
		Me.Label2.Text = "This textbox will not accept (d e or f):"
		'
		'Form1
		'
		Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!)
		Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
		Me.ClientSize = New System.Drawing.Size(284, 90)
		Me.Controls.Add(Me.TextBox2)
		Me.Controls.Add(Me.Label2)
		Me.Controls.Add(Me.TextBox1)
		Me.Controls.Add(Me.Label1)
		Me.Name = "Form1"
		Me.Text = "Form1"
		Me.ResumeLayout(False)
		Me.PerformLayout()

	End Sub
	Friend WithEvents Label1 As System.Windows.Forms.Label
	Friend WithEvents TextBox1 As SuppressedKeysTextBox
	Friend WithEvents TextBox2 As SuppressedKeysTextBox
	Friend WithEvents Label2 As System.Windows.Forms.Label
End Class

Open in new window


All three of the preceeding implementations produce the exact same results.

-saige-
1
 

Author Comment

by:RIAS
ID: 41762590
Thank you Saige Sir!
0

Featured Post

Free Tool: IP Lookup

Get more info about an IP address or domain name, such as organization, abuse contacts and geolocation.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Creating an analog clock UserControl seems fairly straight forward.  It is, after all, essentially just a circle with several lines in it!  Two common approaches for rendering an analog clock typically involve either manually calculating points with…
Calculating holidays and working days is a function that is often needed yet it is not one found within the Framework. This article presents one approach to building a working-day calculator for use in .NET.
NetCrunch network monitor is a highly extensive platform for network monitoring and alert generation. In this video you'll see a live demo of NetCrunch with most notable features explained in a walk-through manner. You'll also get to know the philos…
This is my first video review of Microsoft Bookings, I will be doing a part two with a bit more information, but wanted to get this out to you folks.
Suggested Courses

764 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question