Link button to textbox in WPF at runtime - wpf

Hey all i have created a few text boxes and also buttons to go along with them at run-time.
The code for the button is:
Dim updateButton As New Button
updateButton.Name = "button_" & ticketTheRowNum & "_" & ticketRowNum
updateButton.Content = "UPDATE!"
updateButton.Height = 26
Canvas.SetTop(updateButton, 24 * ticketTheRowNum)
Canvas.SetLeft(updateButton, 330 + lblNotes.Width)
updateButton.Width = lblNotes.Width / 2 - 10
updateButton.Background = New SolidColorBrush(Colors.Green)
Grid.SetRow(updateButton, 0)
Grid.SetColumn(updateButton, 0)
Grid.SetZIndex(updateButton, 2500)
cavTicket.Children.Add(updateButton)
And the code for the text box is this:
Dim txtBlock As New TextBox
txtBlock.Name = "txt_" & ticketTheRowNum & "_" & ticketRowNum
txtBlock.Text = theHeader
txtBlock.TextWrapping = TextWrapping.Wrap
txtBlock.Width = lblNotes.Width - 5
txtBlock.BorderThickness = New Thickness(0)
txtBlock.TextAlignment = TextAlignment.Left
txtBlock.VerticalScrollBarVisibility = ScrollBarVisibility.Auto
tmpExpander.Content = txtBlock
Now the button and text box displays just fine on the WPF but I am unsure of how to hook the button up to have it know whats in the text box and save its content. Currently since I am creating these at run-time I don't have access like I would if its was already on the form before it ran (I would simply just call the buttons click event and then within that I would call the text box content and save it).

If both of your code blocks come from the same class then just add a private property txtBlock (by the way why block and not Box?). So when you will create your TextBox control it will then be visible to all the functions in your class including the button event handler.
But as NETscape said. WPF is all about XAML, binding, and WVVM. So if you want to avoid headaches use them ;)

Related

WPF Find Dynamically created grid and its children

I have dynamically created a series of grids and textblocks inside of said grids. However I am having trouble using the .FindName to call the textblock I need. My control heirarchy goes something like this:
Page -> ScrollViewer - > Grid -> Dynamically Created Grids ->
Dynamically Created Controls
This is how I am currently trying to call them and any other ways I attempted have still gotten me no where
Dim grd As Object = FindName("GridLine" + Ri.ToString())
Dim tempgrd As Grid = DirectCast(grd, Grid)
Dim txtID As Object = tempgrd.FindName("txtIDGrid" + Ri.ToString())
Dim tempID As TextBlock = DirectCast(txtID, TextBlock)
sqlID = tempID.Name
In case anyone else is searching for a similar answer I did end up solving it. You must be sure to RegisterName the controls you are creating to ensure that you can call upon it after runtime.

VB.NET Need guide on error checking using MessageBox

Lets say I have a form with 100 textboxes, comboboxes and other controls and I want to check if any of the controls is empty. When I click on 'OK' button, I want the messagebox to show a list of errors example Textbox1 is empty, Textbox30 is empty and such.
I can achieve this by doing the tedious method where I check textbox1 and messagebox is shown, check textbox2 and messagebox is shown again and so on.
I want the messagebox to show only once. How can I achieve this?
What I have did is that I set up an array and store all the error messages to be shown later by selecting (example Msgbox(errMessages(3) + Environment.newline + errMessages(30)) and I know this is not the right way to do it as well.
Please and thank you in advance.
Here is a direct answer to your question:
You can store the empty controls in a list, and at the end create the message like this:
Dim empty_controls = New List(Of Control)
If TextBox1.Text = String.Empty Then
empty_controls.Add(TextBox1)
End If
If TextBox2.Text = String.Empty Then
empty_controls.Add(TextBox2)
End If
Dim result As String = String.Join(
Environment.NewLine,
empty_controls.Select(Function(c As Control) c.Name + " is empty"))
MessageBox.Show(result)
Here is even a better way to detect which text boxes are empty:
Dim empty_controls = New List(Of Control)
//The following line will search through all text boxes on the form
empty_controls.AddRange(
Controls.OfType(Of TextBox).Where(Function(c As Control) c.Text = String.Empty))
//Here you can add other kinds of controls with their own way of determining if they are empty
Dim result As String = String.Join(
Environment.NewLine,
empty_controls.Select(Function(c As Control) c.Name + " is empty"))
MessageBox.Show(result)

How to put all buttons in flowlayoutpanel to array?

I have a code in vb.net to select all buttons in form within flowlayoutpanel, but it returns zero.
I think problem is with flowlayoutpanel.
Dim alphabetButtons() As Button
alphabetButtons = Me.Controls.OfType(Of Button).Except(New Button() {Button1}).ToArray
Can you tell me what am I doing wrong?
I have a code in vb.net to select all buttons in form within flowlayoutpanel, but it returns zero. ... Can you tell me what am I doing wrong?
Yes. You're telling the Form to return all Controls of Type Button:
Dim alphabetButtons() As Button
alphabetButtons = Me.Controls.OfType(Of Button).Except(New Button() {Button1}).ToArray
You need to ask the FlowLayoutPanel this question.
Change Me to the name of your FlowLayoutPanel, such as FlowLayoutPanel1 in the "fixed" code below:
Dim alphabetButtons() As Button
alphabetButtons = FlowLayoutPanel1.Controls.OfType(Of Button).Except(New Button() {Button1}).ToArray
The Controls() collection only returns controls that are directly contained by that container. Each container has its own collection of child controls...

Why does my ColumnHeadersDefaultCellStyle keep being reset in Visual Studio designer?

I am trying to make the column headers of my DataGridView bold, in Visual Studio 2008.
Every time I change my ColumnHeadersDefaultCellStyle to Calibri 9.75pt bold, using the properties box, the next time I reopen the saved form, the ColumnHeadersDefaultCellStyle has reverted to Calibri 9.75 without bold.
My form's font is Calibri 9.75 without bold, as is my default cell style, but I should be able to override the default cell style with my ColumnHeader style right?
I can solve this problem programmatically by setting the style when the form is shown, but we would like to have the Visual Studio designer show the bolded headers, so we can layout the columns appropriately for the space taken up by bold header text.
In addition, the actual designer file specifies that the ColumnHeadersDefaultCellStyle is bold, even though the designer interface says it is not bold.
dataGridViewCellStyle1.Font = new System.Drawing.Font("Calibri", 9.75F,
System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
dataGridViewCellStyle1.ForeColor = System.Drawing.SystemColors.WindowText;
dataGridViewCellStyle1.SelectionBackColor = System.Drawing.SystemColors.Highlight;
dataGridViewCellStyle1.SelectionForeColor = System.Drawing.SystemColors.HighlightText;
dataGridViewCellStyle1.WrapMode = System.Windows.Forms.DataGridViewTriState.True;
this.receiptDetailView.ColumnHeadersDefaultCellStyle = dataGridViewCellStyle1;
Have you tried check EnableHeadersVisualStyles value?
According to MSDN:
If visual styles are enabled and EnableHeadersVisualStyles is set to
true, all header cells except the TopLeftHeaderCell are painted using
the current theme and the ColumnHeadersDefaultCellStyle values are
ignored.
It is a bug, although Microsoft would probably try to call it a feature. The DataGridView header cells are supposed to inherit the current theme only if EnableHeadersVisualStyles is set to TRUE, and use the settings in ColumnHeaderDefaultCellStyles if it is false. But the DGV ignores EnableHeadersVisualStyles and always inherits the font of the parent container it resides in.
Both rutlean's and Nico Engler suggestions will work. Here is what I always do as a standard practice: Put your DGV in a panel (depending on your application, you might want to set the Dock property to fill. Then set the Panel's font to your desired settings. Your DGV will now always inherit that setting.
I found a workaround where just editing the XXXX.Designer.cs with following code does the trick.
this.receiptDetailView.ColumnHeadersDefaultCellStyle = dataGridViewCellStyle1;
this.receiptDetailView.ColumnHeadersDefaultCellStyle.Font = new System.Drawing.Font("Calibri", 9.75F, System.Drawing.FontStyle.Bold);
It seems that this is a bug, though I am not sure why it happens. I have tested it in every possible way and the value is overriden by the parent control value regardless of whether it is set or not. This is the opposite of how every other WinForms (or any other UI framework) control works, and doesn't make any sense. I have also tested various other controls and have not found another case where this happens.
The ColumnHeadersDefaultCellStyle Font only matters if the Font property is not set on the parent control (form in this case).
I am giving the bounty to the most upvoted answer but that is not what's going on here.
The "solution" to this that I've been using is to set the font again in the form load event, however this is not a perfect solution since such code doesn't belong there.
I ran into this same issue. However, my dataGridView is located in a groupbox. On a restart of VS 2010, the dataGridView fonts will always be whatever the groupBox is set to. Definitely a bug I would like.
I resolved this problem by adding a frame. For me, the datagridview was inside a groupbox (although a few other container types did the same).
Resolved by putting a panel inside the groupbox, set the appropriate font to that panel, put the datagridview inside that panel and by default it inherits the fonts.
I am using VS2010
The answer is actually pretty simple.
You set a Font Style to Form1 [Arial; 8,25pt].
Lets see the designer :
private void InitializeComponent()
{
System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle1 = new System.Windows.Forms.DataGridViewCellStyle();
this.dataGridView1 = new System.Windows.Forms.DataGridView();
this.Column1 = new System.Windows.Forms.DataGridViewTextBoxColumn();
this.Column2 = new System.Windows.Forms.DataGridViewTextBoxColumn();
this.Column3 = new System.Windows.Forms.DataGridViewTextBoxColumn();
((System.ComponentModel.ISupportInitialize)(this.dataGridView1)).BeginInit();
this.SuspendLayout();
//
// dataGridView1
//
dataGridViewCellStyle1.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft;
dataGridViewCellStyle1.BackColor = System.Drawing.SystemColors.Control;
dataGridViewCellStyle1.Font = new System.Drawing.Font("Calibri", 9.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(238)));
dataGridViewCellStyle1.ForeColor = System.Drawing.SystemColors.WindowText;
dataGridViewCellStyle1.SelectionBackColor = System.Drawing.SystemColors.Highlight;
dataGridViewCellStyle1.SelectionForeColor = System.Drawing.SystemColors.HighlightText;
dataGridViewCellStyle1.WrapMode = System.Windows.Forms.DataGridViewTriState.True;
this.dataGridView1.ColumnHeadersDefaultCellStyle = dataGridViewCellStyle1;
this.dataGridView1.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
this.dataGridView1.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] {
this.Column1,
this.Column2,
this.Column3});
this.dataGridView1.EnableHeadersVisualStyles = false;
this.dataGridView1.Location = new System.Drawing.Point(49, 62);
this.dataGridView1.Name = "dataGridView1";
this.dataGridView1.Size = new System.Drawing.Size(443, 309);
this.dataGridView1.TabIndex = 0;
//
// Column1
//
this.Column1.HeaderText = "Column1";
this.Column1.Name = "Column1";
//
// Column2
//
this.Column2.HeaderText = "Column2";
this.Column2.Name = "Column2";
//
// Column3
//
this.Column3.HeaderText = "Column3";
this.Column3.Name = "Column3";
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 14F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(546, 457);
this.Controls.Add(this.dataGridView1);
this.Font = new System.Drawing.Font("Arial", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(238)));
this.Name = "Form1";
this.Text = "Form1";
this.Load += new System.EventHandler(this.Form1_Load);
((System.ComponentModel.ISupportInitialize)(this.dataGridView1)).EndInit();
this.ResumeLayout(false);
}
Now as you can see, your font setting for Datagridview header did saved.
But still, font setting for your form appeared after that, which eventually overrides Datagridview font setting.
My advice is return the Form font setting to default.
Use this code
dataGridView1.EnableHeadersVisualStyles = false;
dataGridView1.SelectionBackColor = System.Drawing.SystemColors.Highlight;
Try this:
DataGridView1.ColumnHeadersDefaultCellStyle.Font = new Font("Calibri", 9.75F, FontStyle.Bold);
This is a bug and still there even in .net 4.6, the problem is that the ColumnHeadersDefaultCellStyle font always overwritten by its Parent font so I figured out a fix for this:
First you need to add your DataGridView to an own Panel, the Panel will work here as a shield and I believe you need to set the Dock property of the DataGridView to Fill.
Second you need to add the following code into ColumnHeadersDefaultCellStyleChanged event.
If Parent IsNot Nothing Then
Parent.Font = ColumnHeadersDefaultCellStyle.Font
End If
I had the same issue today and it seemed that the ColumnHeadersDefaultCellStyle of the DataGridView is overwritten by the font style of the form it belongs to.
As a solution I set the GdiCharSet parameter of the form's font to 0. After that beeing done, the font of the ColumnHeadersDefaultCellStyle won't be overwritten.
I'm on VS 2010 and Window 8.
I know this topic is old, however I was having the same issue in VS 2015 with the ColumnDefaultHeadersCellStyle font size always reverting to 10pt (I needed it to be 14pt). I was able to fix this by first changing the font itself, which then allowed me to change the font size.
The font I was originally using was SEGOE UI SEMIBOLD, which I changed to just SEGOE UI and was able to change the size. I haven't looked into why using the semibold version prevented me from changing the size. Further, this method has worked for me with VisualStyles enabled, and EnableHeadersVisualStyles set to true.
If anyone is still having this problem, my suggestion would be try changing to another font.
You can try that;
Private Sub DgvListeFt_CellPainting(sender As Object, e As DataGridViewCellPaintingEventArgs) Handles DgvListeFt.CellPainting
Call KolonBaslikDGV(sender, e)
End Sub
Sub KolonBaslikDGV(ByVal S As Object, ByVal E As DataGridViewCellPaintingEventArgs)
E.PaintBackground(E.CellBounds, True)
If E.RowIndex = -1 Then
If E.Value Is Nothing Then
E.Handled = True
Return
End If
E.Handled = True
Dim headerFont = New Font("Ariel", 9, FontStyle.Regular)
Dim myBounds As Rectangle = E.CellBounds
myBounds.X = E.CellBounds.X + 4
Dim sf = New StringFormat With {.Alignment = StringAlignment.Near,
.LineAlignment = StringAlignment.Center}
E.Graphics.DrawString(E.Value.ToString, headerFont, Brushes.MediumVioletRed, myBounds, sf)
headerFont.Dispose()
sf.Dispose()
End If
End Sub

WPF Tooltip binding not updating

Good afternoon all,
I have to work with a legacy Winforms application but I'd like to start migrating it to WPF. It doesn't have a tooltip control now so I'd like to use a WPF tooltip object.
I create a single global instance of a tooltip object. I've bound the controls within it and my application sets the datacontext of the tooltip. I can manually show and hide the tooltip just fine. The first time I hover over an object it picks up the bound data perfectly and works great. When I move over another control the tooltip datacontext is changed but the displayed data is never reloaded.
I tried implementing a property changed event and use the INotifyPropertyChanged interface in the object I bind to. It appears the wpf tooltip is not listening to the event.
I tried setting the binding mode to Oneway (it's a display only tooltip).
The tooltip is created programmatically:
// build the tooltip window.
System.Windows.Controls.Image img = new System.Windows.Controls.Image();
img.Width = 50;
img.Height = 60;
// bind the image
System.Windows.Data.Binding imageBinding = new System.Windows.Data.Binding("PatientImage.Data");
imageBinding.Mode = System.Windows.Data.BindingMode.OneWay;
imageBinding.Source = bed;
img.SetBinding(System.Windows.Controls.Image.SourceProperty, imageBinding);
// wrap image in a border
System.Windows.Controls.Border brdr = new System.Windows.Controls.Border();
brdr.BorderBrush = System.Windows.Media.Brushes.Blue;
brdr.Margin = new System.Windows.Thickness(6);
brdr.Child = img;
System.Windows.Controls.WrapPanel wp = new System.Windows.Controls.WrapPanel();
System.Windows.Controls.TextBlock tb = new System.Windows.Controls.TextBlock();
tb.Background = System.Windows.Media.Brushes.LightBlue;
tb.Foreground = System.Windows.Media.Brushes.Blue;
// bind the text block
System.Windows.Data.Binding textBlockBinding = new System.Windows.Data.Binding("TooltipText");
textBlockBinding.Mode = System.Windows.Data.BindingMode.OneWay;
textBlockBinding.Source = bed;
tb.SetBinding(System.Windows.Controls.TextBlock.TextProperty, textBlockBinding);
wp.Children.Add(brdr);
wp.Children.Add(tb);
bedTooltip = new System.Windows.Controls.ToolTip();
bedTooltip.Content = wp;
Any idea why this doesn't work? Maybe I need to use a tooltip object for each control instead of a single global one as a workaround?
The bindings specify a Source, because of that they no longer "care" about the DataContext and hence the bindings do not update if anything other than the property itself on the source-object changes.

Resources