This is my first question ever, so please spare me if I did something wrong.
I have a small survey form that automatically draw questions and answers from a SQL server table, and create a question label (Label_Questionnaire(i)), a panel to nest all radiobuttons for the answer of each question (Panel_Response(i)), and 3 radiobuttons(yes, no, n/a), named RadioButton_Answers(i)_1 . All questions and answers are inside a big panel (Panel_Survey) to allow user to scroll up and down (around 50 questions).
When I run the program, I can only see questions but none of the radiobuttons are showing. What I did try are:
Use .BringToFront to bring the Panel_Response and all radiobuttons to front.
Change .Parent to Controls.Add . Instead of using .Parent, I use Panel_Survey.Controls.Add(Panel_Response) and Panel_Response.Controls.Add(RadioButton_Answers_1)
Force Panel_Response.Visible = True and all radiobuttons visible = true
(I know it might sound stupid, but I'm out of trick)
How do I make those radiobuttons show up? If not, are there any better designs for this kind of survey form? Thank you for any advice, in advance!
Below is my code:
Protected Overrides Sub OnLoad(e As EventArgs)
Dim PanelCount As Integer
Dim QuestionName As String
Dim Response1 As String
Dim Response2 As String
Dim Response3 As String
Dim InitialX As Integer = Panel_Survey.Left
Dim InitialY As Integer = Panel_Survey.Top
Dim SizeX As Integer = 1000
Dim SizeY As Integer = 25
'Load the survey
Try
'Get a list of questions and answers into array of list
Dim ListofQuestionandAnswers As New List(Of List(Of String))
Dim conn As New SqlClient.SqlConnection
conn.ConnectionString = ConnectionString
Dim CommandString As String = "SELECT [QuestionID], [QuestionName] ,[Response1],[Response2],[Response3] FROM [Question_List] ORDER BY [QuestionID]"
Dim Command As New SqlClient.SqlCommand
Command.CommandText = CommandString
Command.Connection = conn
Dim dr As SqlClient.SqlDataReader
conn.Open()
dr = Command.ExecuteReader
While dr.Read
Dim ls As New List(Of String)
ls.Add(dr.GetValue(0).ToString)
ls.Add(dr.GetValue(1).ToString)
ls.Add(dr.GetValue(2).ToString)
ls.Add(dr.GetValue(3).ToString)
ls.Add(dr.GetValue(4).ToString)
ListofQuestionandAnswers.Add(ls)
End While
conn.Close()
PanelCount = ListofQuestionandAnswers.Count
For i = 0 To ListofQuestionandAnswers.Count - 1
QuestionName = ListofQuestionandAnswers(i)(1)
Response1 = ListofQuestionandAnswers(i)(2)
Response2 = ListofQuestionandAnswers(i)(3)
Response3 = ListofQuestionandAnswers(i)(4)
Dim Label_Questionnaire As New Label
Dim Panel_Response As New Panel
Dim RadioButton_Answers_1 As New RadioButton
Dim RadioButton_Answers_2 As New RadioButton
Dim RadioButton_Answers_3 As New RadioButton
'Condition the label
With Label_Questionnaire
.Parent = Panel_Survey
.Name = "Label_Questionnaire" + i.ToString
.Font = New Font("Calibri", 11, FontStyle.Regular)
.Text = QuestionName
.ForeColor = Color.Black
.Location = New Point(InitialX, InitialY)
.AutoSize = True
End With
'Condition the panel
With Panel_Response
'Panel_Survey.Controls.Add(Panel_Response)
.Parent = Panel_Survey
.Name = "Panel_Questionnaire" + i.ToString
.Location = New Point(InitialX + 880, InitialY)
.Width = 250
.Height = 25
.BringToFront()
End With
Dim j As Integer
Dim h As Integer
j = Panel_Response.Left
h = Panel_Response.Top
'Condition the radiobuttons for answers
With RadioButton_Answers_1
.Parent = Panel_Response
.Name = "RadioButton_Answers" + i.ToString + "_1"
.Font = New Font("Calibri", 11, FontStyle.Regular)
.Text = Response1
.ForeColor = Color.Black
.Location = New Point(j, h)
.AutoSize = True
h += RadioButton_Answers_1.Height
End With
With RadioButton_Answers_2
.Parent = Panel_Response
.Name = "RadioButton_Answers" + i.ToString + "_2"
.Font = New Font("Calibri", 11, FontStyle.Regular)
.Text = Response2
.ForeColor = Color.Black
.Location = New Point(RadioButton_Answers_1.Right, h)
.AutoSize = True
End With
With RadioButton_Answers_3
.Parent = Panel_Response
.Name = "RadioButton_Answers" + i.ToString + "_3"
.Font = New Font("Calibri", 11, FontStyle.Regular)
.Text = Response3
.ForeColor = Color.Black
.Location = New Point(RadioButton_Answers_2.Right, h)
.AutoSize = True
End With
InitialY = InitialY + SizeY + 10
Next
Catch ex As Exception
MessageBox.Show(String.Format("Error: {0}", ex.Message), "Error while creating questions and answers", MessageBoxButtons.OK, MessageBoxIcon.Error)
End Try
End Sub
Few basic problems here:
You seem to assume that when a control is placed inside a panel, it must be placed at a location relative to the form. It doesn't; it places relative to the Panel which has its own coordinate system starting at 0,0 in the top left of the panel - you initialize j and h (for locations of the radio buttons) to the Left and Top of the panel they're in, but they should be inited to 0,0 if you want the radiobuttons to start at the top left of the panel. If the Panel is placed at 300,300 on a form, and you place a radiobutton inside the panel also at 300,300 (because you copied its left and top) then the radio button will look like it's at 600,600 on the form because its at 300,300 inside a panel that is at 300,300
You only make your panel 250 wide - it's barely wide enough to show a single radio button
You increment h once, by an amount that means the next radiobutton disappears off the bottom of the panel (which is 25 pixels high)
Here:
With Panel_Response
'Panel_Survey.Controls.Add(Panel_Response)
.Parent = Panel_Survey
.Name = "Panel_Questionnaire" + i.ToString
.Location = New Point(InitialX + 880, InitialY)
.Width = 2500
.Height = 25
.BringToFront()
.BackColor = Color.Red
End With
Dim j As Integer
Dim h As Integer
j = 0
h = 0
Paste that over your app code and run it again. I made the panel BackColor red so you can more easily see where the panel is
I guess you need to decide how you want your UI to look. If the radiobuttons are laid out vertically, don't increment X when you add them to the panel (by setting the parent property). Make the panel tall enough to accommodate them (25 px not enough)
Use a FlowLayoutPaanel or TableLayoutPanel instead
In an application I'm developing, the user can select a number of items (max. 6) in a datagrid. These items should then be printed in a matrix style on pre-printed forms (see it like CD labels, 6 on a page).
I'm generating these images dynamically containing the selected content from a database. I then put these in a grid so they can be printed on the pre-printed forms.
I have the following code that creates the grid, generates the images from a user control and adds them to the grid and then prints these images.
I'm not following the MVVM pattern for the printing action. I created a reference to my view model in my code-behind.
Private Sub PrintButton_Click(sender As Object, e As RoutedEventArgs) Handles ButtonPrint.Click
Dim dlg As New PrintDialog
dlg.PrintTicket.PageMediaSize = New PageMediaSize(PageMediaSizeName.ISOA4)
Dim pageWidth As Double = GetPageWidth(dlg)
'Since the label is a perfect square: labelWidth = labelHeight
Dim labelWidthInPx As Integer = Utilities.ConvertMmToPixels(My.Settings.LabelWidthInMm)
'Set spacing distances in pixels
Dim horizontalLabelSpacing As Integer = Utilities.ConvertMmToPixels(My.Settings.HorizontalLabelSpacinginMm)
Dim verticalLabelSpacing As Integer = Utilities.ConvertMmToPixels(My.Settings.VerticalLabelSpacingInMm)
Dim topMargin As Integer = Utilities.ConvertMmToPixels(My.Settings.TopMarginInMm)
Dim leftMargin As Integer = Utilities.ConvertMmToPixels(My.Settings.LeftMarginInMm)
Dim bottomMargin As Integer = Utilities.ConvertMmToPixels(My.Settings.BottomMarginInMm)
'Create the table/grid
Dim tbl As New Grid
If CheckBoxPrintGridLines.IsChecked Then
tbl.ShowGridLines = True
Else
tbl.ShowGridLines = False
End If
'Add 3 columns (2 for the labels, 1 for spacing)
Dim col1 As New ColumnDefinition With {
.Width = New GridLength(labelWidthInPx, GridUnitType.Pixel)
}
Dim col2 As New ColumnDefinition With {
.Width = New GridLength(horizontalLabelSpacing, GridUnitType.Pixel)
}
Dim col3 As New ColumnDefinition With {
.Width = New GridLength(labelWidthInPx, GridUnitType.Pixel)
}
tbl.ColumnDefinitions.Add(col1)
tbl.ColumnDefinitions.Add(col2)
tbl.ColumnDefinitions.Add(col3)
'Add 5 Rows (3 for labels, 2 for spacing)
Dim row1 As New RowDefinition With {
.Height = New GridLength(labelWidthInPx, GridUnitType.Pixel)
}
Dim row2 As New RowDefinition With {
.Height = New GridLength(verticalLabelSpacing, GridUnitType.Pixel)
}
Dim row3 As New RowDefinition With {
.Height = New GridLength(labelWidthInPx, GridUnitType.Pixel)
}
Dim row4 As New RowDefinition With {
.Height = New GridLength(verticalLabelSpacing, GridUnitType.Pixel)
}
Dim row5 As New RowDefinition With {
.Height = New GridLength(labelWidthInPx, GridUnitType.Pixel)
}
tbl.RowDefinitions.Add(row1)
tbl.RowDefinitions.Add(row2)
tbl.RowDefinitions.Add(row3)
tbl.RowDefinitions.Add(row4)
tbl.RowDefinitions.Add(row5)
'Add label images
Dim reelData = CType(DataGridReels.ItemsSource, List(Of ReelInfo))
Dim rowIndex As Integer = 0
Dim colIndex As Integer = 0
For Each reel In reelData.Where(Function(r) r.IsSelected = True)
Dim partNumberData = ViewModel.DataService.GetPartNumberDataAsync(reel.PartNumber)
Dim batchData = ViewModel.DataService.GetBatchDataAsync(reel.PartNumber, reel.HENBatchNumber)
LabelImageControl.IsPrinting = True
LabelImageControl.PartNumberData = partNumberData.Result
LabelImageControl.BatchData = batchData.Result
LabelImageControl.ReelData = reel
LabelImageControl.Refresh
UpdateUI()
Dim labelImage As New Image
labelImage = GetImageFromLabel(LabelImageControl)
labelImage.Width = labelWidthInPx
labelImage.Height = labelWidthInPx
Grid.SetRow(labelImage, rowIndex)
Grid.SetColumn(labelImage, colIndex)
tbl.Children.Add(labelImage)
tbl.Refresh
colIndex += 1
If colIndex > 1 Then
colIndex = 0
rowIndex += 1
End If
Next
Dim iuc As New InlineUIContainer(tbl)
Dim p As New Paragraph(iuc)
'Create print dialog
If dlg.ShowDialog.GetValueOrDefault Then
'Create a flow document
Dim doc As New FlowDocument With {
.Name = "LabelPage",
.ColumnWidth = pageWidth,
.PagePadding = New Thickness(leftMargin, topMargin, 0, bottomMargin)
}
doc.Blocks.Add(p)
'Create IDocumentPagniatorSource from FlowDocument
Dim idpSource As IDocumentPaginatorSource = doc
Try
Me.Cursor = Cursors.Wait
dlg.PrintDocument(idpSource.DocumentPaginator, "Label Page")
Catch ex As Exception
Me.Cursor = Cursors.Arrow
MessageBox.Show("An error occurred during printing: " & ex.Message, "Print error")
Finally
Me.Cursor = Cursors.Arrow
End Try
End If
End Sub
When I send the output to the PDF printer I only get one image in the top left corner of the page/grid.
Since the user control (LabelImageControl) is in the XAML, I can see it changing while debugging. So the data is coming into the user control correctly.
When I check the grid with the XML Visualiser I see it has the same number of children as the items I selected in the datagrid.
Can anyone point me in the right direction on how to get the grid printing correctly?
In a WPF application the user can double click a line in a DataGrid to open a new page that contain tabs with grids - some of these have GridSplitters like this
Private Function CentreGrid() As Grid
Try
Dim vGrid As New Grid
For i As Integer = 0 To 2
Dim vCol As New ColumnDefinition
If i = 1 Then
vCol.Width = New GridLength(5, GridUnitType.Auto)
End If
vGrid.ColumnDefinitions.Add(vCol)
Next
Dim vLeftGrid As Grid = LeftGrid()
Grid.SetColumn(vLeftGrid, 0)
vGrid.Children.Add(vLeftGrid)
Dim vGridSplitter As New GridSplitter
With vGridSplitter
.VerticalAlignment = Windows.VerticalAlignment.Stretch
.HorizontalAlignment = Windows.HorizontalAlignment.Center
.ResizeBehavior = GridResizeBehavior.PreviousAndNext
.Background = New SolidColorBrush(Colors.Blue)
.Width = 5
.Margin = New Thickness(5)
End With
Grid.SetColumn(vGridSplitter, 1)
vGrid.Children.Add(vGridSplitter)
Dim vRightGrid As Grid = RightGrid()
Grid.SetColumn(vRightGrid, 2)
vGrid.Children.Add(vRightGrid)
Return vGrid
Catch ex As Exception
EmailError(ex)
Return Nothing
End Try
End Function
As everything is generated dynamically from code-behind is there any method to get a handle on the relative grid position that has been changed by the user so that when the page is closed and another instance opened the GridSplitter can be in the same relative position that the user selected beforehand?
Thanks
Here is my code to add a combobox array to a groupbox array
Dim gbQuoteProduct(5) As GroupBox
Dim cmboBoxQuoteProduct(5) As ComboBox
gbQuoteProduct(n) = New GroupBox
With gbQuoteProduct(n)
.Text = ""
.Location = New Point(10, 5 + n * 70)
.Width = 300
.Height = 70
End With
pnlQuoteProducts.Controls.Add(gbQuoteProduct(n))
cmboBoxQuoteProduct(n) = New ComboBox
With cmboBoxQuoteProduct(n)
.Items.Add("A")
.Items.Add("B")
.Items.Add("C")
.Items.Add("D")
.Text = ""
.Location = New Point(60, 15)
End With
gbQuoteProduct(n).Controls.Add(cmboBoxQuoteProduct(n))
This works fine but I want to add another combobox array to the groupbox array when something is selected from the existing combobox array.
When I try the following:
Private Sub cmboBoxQuoteProduct_SelectedIndexChanged(ByVal sender A
_ Object, ByVal e As System.EventArgs) Handles
_cmboBoxQuoteProduct().SelectedIndexChanged
End Sub
I get the error: "Expected "."" where I have the "()" after cmboBoxQuoteProduct
Any help is much appreciated.
Thanks in advance
I have been searching for this but I am not able to find anything related to how to iterate through all dynamically created controls on the grid. I'm basically only looking to grab data from a dynamically created textbox, I have tried the following but it is not pulling up any children
Dim ctl As FrameworkElement = Me
Dim children As Integer = VisualTreeHelper.GetChildrenCount(ctl)
For i = 0 To children - 1
Dim Child As FrameworkElement = VisualTreeHelper.GetChild(ctl, i)
Next
Code used to add a textbox onto the form
For i = 0 To tb - 1
Dim t As New TextBox
t.Width = 75
t.Height = 25
t.Focus()
Grid.SetColumn(t, columns)
MyGrid.Children.Add(t)
t.Focus()
Next