WPF Update lines - wpf

I'm trying to replicate in wpf(vb.net) an app that I made some times ago in winform.
Il the old app I basically open a binary file and load it in one array and then draw a 2d lines chart with it. Files are like 2/4MB size, so i put a slider and every time I change it I call the drawing sub with the slider offset.
Now I'm totaly new in wpf, I figure out how to draw the chart, but I don't understand how update it when I move the slider, or(next step) when I change array's values by code.
To make simple tests I load a file when start and when button1 clicked I modify array values and I would see the update chart, but I have not found a way.
<Window x:Class="MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:testwpf2d"
mc:Ignorable="d"
Title="MainWindow" Height="1920" Width="1080">
<Grid x:Name="BaseGrid">
<Canvas Name="paintSurface" >
<Canvas.Background>
<SolidColorBrush Color="Black" Opacity="1"/>
</Canvas.Background>
<Button Content="Button" Canvas.Left="184" Canvas.Top="36" Width="75" Click="Button_Click"/>
</Canvas>
</Grid>
</Window>
Private Sub BaseGrid_Loaded(sender As Object, e As RoutedEventArgs) Handles BaseGrid.Loaded
Dim openFileDialogORI As OpenFileDialog = New OpenFileDialog()
If openFileDialogORI.ShowDialog = True Then
Try
Dim MyFileORIStream As FileStream = New FileStream(openFileDialogORI.FileName, FileMode.Open, FileAccess.Read)
Dim ORIBuffer As BinaryReader = New BinaryReader(MyFileORIStream)
Dim fInfo As New FileInfo(openFileDialogORI.FileName)
Dim numBytes As Long = fInfo.Length
MyORIArray = ORIBuffer.ReadBytes(CInt(numBytes))
ORIBuffer.Close()
MyFileORIStream.Close()
Dim NomeFileOri As String = openFileDialogORI.FileName
Dim info As New FileInfo(openFileDialogORI.FileName)
Dim length As Integer = CInt(info.Length)
Catch ex As Exception
MsgBox(ex.Message)
End Try
End If
MessageBox.Show("File loaded")
For i As Integer = 1 To 2000
Dim Line As New Line
Line.X1 = i
Line.X2 = i + 1
Line.Y1 = MyORIArray(i)
Line.Y2 = MyORIArray(i + 1)
Line.Stroke = Brushes.YellowGreen
Line.StrokeThickness = 0.25
BaseGrid.Children.Add(Line)
Next
End Sub
Private Sub Button_Click(sender As Object, e As RoutedEventArgs)
Dim Rand As New Random
For i As Integer = 1 To 1000
MyORIArray(i) = Rand.NextDouble * 50
Next
MessageBox.Show("new data ")
BaseGrid.UpdateLayout()
paintSurface.UpdateLayout()
End Sub

I solved creating a collection of point from the array and draw a polyline, when arraypoint change(always by user interaction that raise an event(button,mouse etc), I update or recreate point collection and then use update.layout. I understand that is not the best way but for this little application work good

Related

WPF DataGrid when compressed shuffles the values

The problem
WPF Datagrid. A dataset with one table and three columns. Price, Discount, Total. The only editable column is the discount. If I enter the data with the grid fully visible, everything works as it should.
But if I narrow the window and enter the data, they get mixed up. And it just messes up the values that I can't see at the end of editing the current cell. Seems to do it out of spite!
The result when I view the whole grid by enlarging the window is this:
As you can see the totals are mixed!
The code
I've recreated a minimal example that you can test yourself.
XAML
<Window x:Class="DataGrid"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:TestDatagrid"
mc:Ignorable="d"
Title="DataGrid" Height="450" Width="800" Loaded="Window_Loaded">
<Grid>
<DataGrid x:Name="grid" Margin="0,28,0,38"
CanUserDeleteRows="True"
CanUserSortColumns="True"
CanUserAddRows="False"
SelectionUnit="CellOrRowHeader"
CellEditEnding="grid_CellEditEnding"/>
</Grid>
</Window>
VB.NET
Imports System.Data
Imports System.Globalization
Public Class DataGrid
Private Sub Window_Loaded(sender As Object, e As RoutedEventArgs)
Dim ds As New DataSet
Dim tb As New DataTable("Orders")
Dim price As New DataColumn
price.ColumnName = "Price"
price.DataType = System.Type.GetType("System.Decimal")
tb.Columns.Add(price)
Dim discount As New DataColumn
discount.ColumnName = "Discount"
discount.DataType = System.Type.GetType("System.Decimal")
tb.Columns.Add(discount)
Dim total As New DataColumn
total.ColumnName = "Total"
total.DataType = System.Type.GetType("System.Decimal")
tb.Columns.Add(total)
For i As Integer = 0 To 20
Dim dr As DataRow = tb.NewRow()
dr("Price") = CDec((i + 1) * 10)
dr("Discount") = 0
dr("Total") = CDec((i + 1) * 10)
tb.Rows.Add(dr)
Next
ds.Tables.Add(tb)
grid.ItemsSource = ds.Tables(0).DefaultView
For Each c In grid.Columns
If c.Header = "Price" Then c.IsReadOnly = True
If c.Header = "Total" Then c.IsReadOnly = True
Next
End Sub
Private Sub grid_CellEditEnding(sender As Object, e As DataGridCellEditEndingEventArgs)
If e.EditAction = DataGridEditAction.Commit Then
Dim nfi As NumberFormatInfo = New NumberFormatInfo()
nfi.NumberDecimalSeparator = "."
Try
Dim tPrice As TextBlock = TryCast(grid.Columns(0).GetCellContent(e.Row), TextBlock)
Dim Price As Double = CDbl("0" & Replace(tPrice.Text, ".", ","))
Dim Discount As Double = CDbl("0" & Replace(TryCast(e.EditingElement, TextBox).Text, ".", ","))
Dim Total As Double = Price * (1 - (Discount / 100))
' Format the discount value
e.EditingElement.SetValue(TextBox.TextProperty, String.Format(nfi, "{0:0.00#}", Discount))
' Format and show the value on datagrid
TryCast(grid.Columns(2).GetCellContent(e.Row), TextBlock).Text = String.Format(nfi, "{0:0.00#}", Total)
' Update the value on grid
TryCast(grid.CurrentItem, DataRowView).Item(2) = Total
Catch ex As Exception
End Try
End If
End Sub
End Class
I really have no idea what's going on!
Thanks for any hints or help you will give me.
I really have no idea what's going on!
Virtualization, i.e. the elements that you wrongfully edit are resued for for performance reasons.
The obvious and recommended solution is to avoid editing the visual elemens directly and instead edit the columns of the underlying DataRowView.
The other solution is to disable the virtualization:
<DataGrid VirtualizingPanel.IsVirtualizing="False" EnableRowVirtualization="False" ... />

TextBlock1.Background = "myBrush" & 1 is not working

xaml codes are here;
<Window x:Class="MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<TextBlock x:Name="TextBlock1" Width="100" Height="20" Background="Blue"/>
</Grid>
</Window>
vb.net codes are here;
Class MainWindow
Private Sub MainWindow_Loaded(sender As Object, e As RoutedEventArgs) Handles Me.Loaded
Dim myBrush1 As New SolidColorBrush(CType(ColorConverter.ConvertFromString("#FF0000"), Color))
TextBlock1.Background = myBrush1
End Sub
End Class
The codes above are okey.
My question is here;
I want to use
TextBlock1.Background = "myBrush" & 1
instead of
TextBlock1.Background = myBrush1
TextBlock1.Background = "myBrush" & 1 is not working.
So, how can I make TextBlock1.Background = "myBrush" & 1 is working?
You can't use a string as a variable name in that way.
What you can do instead is have some kind of collection which associates an object (in this case a Brush) with a string. A Dictionary will serve this purpose well here.
You could have something like:
Class MainWindow
Private myBrushes As New Dictionary(Of String, Brush)
Private Sub Window_Loaded(sender As Object, e As RoutedEventArgs)
Dim myBrush1 As New SolidColorBrush(DirectCast(ColorConverter.ConvertFromString("#FF0000"), Color))
myBrushes.Add("myBrush1", myBrush1)
TextBlock1.Background = myBrushes("myBrush" & "1")
End Sub
End Class
The value of myBrushes("myBrush1") is the SolidColorBrush myBrush1. You can add as many brushes as you want to the dictionary.

TextBlock.Inlines - add horizontal line

Below I am adding log entries divided by a horizontal line
Dim vLogText = vLog.Split("^")
Dim vRows As Integer = vLogText.Length - 1
For i As Integer = 0 To vRows
Dim Subrow As String = vLogText(i)
LogTB.Inlines.Add(Subrow)
LogTB.Inlines.Add(New Line With {.X1 = 0, .Y1 = 0, .X2 = 300, .Y2 = 0, .Stroke = New SolidColorBrush(Colors.Gray), .StrokeThickness = 4.0})
Next
This is OK if I want a preset length (say 300 in the above example) - but if it needs to stretch to the entire width of the container how is that accomplished?
Thanks
Added in reply to answer supplied by Anjum
Here is how the grid is added...
#Region "Right Grid"
Private Function RightGrid() As Grid
Try
Dim MainGrid As New Grid
Dim vGrid As New Grid
Dim SV As New ScrollViewer
With SV
.Name = "RightGrid_SV"
.Content = vGrid
.VerticalScrollBarVisibility = ScrollBarVisibility.Auto
End With
RegisterControl(WorkOrder_Grid, SV)
MainGrid.Children.Add(SV)
'Add in the status and log
Dim LogLB As New Label
With LogLB
.Name = "WorkOrder_LogLB"
End With
RegisterControl(WorkOrder_Grid, LogLB)
vGrid.Children.Add(LogLB)
If IsNewRecord = True Then
'Add some help data
Dim SP As New StackPanel
Dim HeaderTB As New TextBlock
With HeaderTB
.Text = "ADDING A NEW WORK ORDER" & Environment.NewLine
.HorizontalAlignment = HorizontalAlignment.Center
.FontWeight = FontWeights.Bold
End With
Dim DatesHeaderTB As New TextBlock
With DatesHeaderTB
.Text = "Dates"
.TextDecorations = TextDecorations.Underline
End With
Dim DatesContentTB As New TextBlock
With DatesContentTB
.Text = "Enter the Work Order date and the date the Work needs to be completed by." & Environment.NewLine
.TextWrapping = TextWrapping.Wrap
End With
Dim UnitHeaderTB As New TextBlock
With UnitHeaderTB
.Text = "Unit/Common Area"
.TextDecorations = TextDecorations.Underline
End With
Dim vUnit As String = "If the Work Order relates to a homeowners property, insert the details using the button. "
vUnit += "If the homeowners have a registered account they will be updated by email each time the Work Order status is changed!" & Environment.NewLine & Environment.NewLine
vUnit += "If the Work Order relates to a common area (e.g. Recreation grounds, Clubhouse...) just enter a short description of that area." & Environment.NewLine
Dim UnitContentTB As New TextBlock
With UnitContentTB
.Text = vUnit
.TextWrapping = TextWrapping.Wrap
End With
Dim TypeHeaderTB As New TextBlock
With TypeHeaderTB
.Text = "Work Type"
.TextDecorations = TextDecorations.Underline
End With
Dim TypeContentTB As New TextBlock
With TypeContentTB
.Text = "A short description of the type of work (e.g. Spinklers, Lights not working...)" & Environment.NewLine
.TextWrapping = TextWrapping.Wrap
End With
Dim DetailsHeaderTB As New TextBlock
With DetailsHeaderTB
.Text = "Details/Instructions"
.TextDecorations = TextDecorations.Underline
End With
Dim DetailsContentTB As New TextBlock
With DetailsContentTB
.Text = "Add any more details or instructions to help the supplier." & Environment.NewLine
.TextWrapping = TextWrapping.Wrap
End With
Dim SupplierHeaderTB As New TextBlock
With SupplierHeaderTB
.Text = "Supplier"
.TextDecorations = TextDecorations.Underline
End With
Dim SupplierContentTB As New TextBlock
With SupplierContentTB
.Text = "Insert the supplier using the button." & Environment.NewLine & Environment.NewLine & "You can still save the Work Order without entering a supplier, but the Work Order document will not be generated!" & Environment.NewLine
.TextWrapping = TextWrapping.Wrap
End With
Dim EmailHeaderTB As New TextBlock
With EmailHeaderTB
.Text = "Supplier Email"
.TextDecorations = TextDecorations.Underline
End With
Dim EmailContentTB As New TextBlock
With EmailContentTB
.Text = "The default email address will be loaded when you insert the supplier (this can be overridden) " & Environment.NewLine & Environment.NewLine & "If the email address is blank, or not valid, the Work Order document will not be emailed, but generated as a PDF to print locally and mail!" & Environment.NewLine
.TextWrapping = TextWrapping.Wrap
End With
Dim ImageHeaderTB As New TextBlock
With ImageHeaderTB
.Text = "Upload Image"
.TextDecorations = TextDecorations.Underline
End With
Dim ImageContentTB As New TextBlock
With ImageContentTB
.Text = "If you have a photograph of the work required, browse to the image. It will be included in the Work Order document." & Environment.NewLine
.TextWrapping = TextWrapping.Wrap
End With
Dim CostHeaderTB As New TextBlock
With CostHeaderTB
.Text = "Estimated Cost"
.TextDecorations = TextDecorations.Underline
End With
Dim vCost As String = "If you enter an estimated cost the Work Order will be authorised up to that amount" & Environment.NewLine & Environment.NewLine
vCost += "If the supplier is unable to carry out the work for this amount or less (or the field is left at zero) the work will not be authorised and they must revert back to the sender with a quote!" & Environment.NewLine & Environment.NewLine
vCost += "When estimated costs are used a lot it is a good idea to check the supplier invoices do not regularly equal (or a dollar or two less) than the estimated amount!!" & Environment.NewLine
Dim CostContentTB As New TextBlock
With CostContentTB
.Text = vCost
.TextWrapping = TextWrapping.Wrap
End With
Dim SiteHeaderTB As New TextBlock
With SiteHeaderTB
.Text = "Smart Manager"
.TextDecorations = TextDecorations.Underline
.Foreground = New SolidColorBrush(Colors.Blue)
End With
Dim SiteContentTB As New TextBlock
With SiteContentTB
.Text = "You can also enter Work Orders, whilst on-site, with a Smart Phone or Tablet using Smart Manager!" & Environment.NewLine
.TextWrapping = TextWrapping.Wrap
.Foreground = New SolidColorBrush(Colors.Blue)
End With
With SP.Children
.Add(HeaderTB)
.Add(DatesHeaderTB)
.Add(DatesContentTB)
.Add(UnitHeaderTB)
.Add(UnitContentTB)
.Add(TypeHeaderTB)
.Add(TypeContentTB)
.Add(DetailsHeaderTB)
.Add(DetailsContentTB)
.Add(SupplierHeaderTB)
.Add(SupplierContentTB)
.Add(EmailHeaderTB)
.Add(EmailContentTB)
.Add(ImageHeaderTB)
.Add(ImageContentTB)
.Add(CostHeaderTB)
.Add(CostContentTB)
.Add(SiteHeaderTB)
.Add(SiteContentTB)
End With
LogLB.Content = SP
End If
Return MainGrid
Catch ex As Exception
EmailError(ex)
Return Nothing
End Try
End Function
..and that is part of the main grid...
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
When the page is opened this is what the horizontal line looks like (the one in blue)
..and this is what happens when the GridSplitter is moved to the left (same thing if the window is made larger)
Best would be to set a Binding for the X2 property and set it to ActualWidth of the TextBlock.
Below is C# code, you can change it to VB.net :
Line line = new Line() { Stroke = Brushes.Blue};
Binding binding = new Binding("ActualWidth");
binding.RelativeSource = new RelativeSource() { Mode=RelativeSourceMode.FindAncestor, AncestorType=typeof(TextBlock) };
BindingOperations.SetBinding(line, Line.X2Property, binding);
LogTB.Inlines.Add(line);
I would not use code-behind for something like this. Absolutely painful. You'll find WPF much easier to work with if you confine the majority of UI development to an XAML front-end. Try something like this
<Window x:Class="WpfApplication3.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApplication3"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.Resources>
<DataTemplate x:Key="MyTemplate">
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding}" />
<Line X1="0" X2="{Binding ActualWidth, RelativeSource={RelativeSource Self}}" Stroke="Black" />
</StackPanel>
</DataTemplate>
</Grid.Resources>
<ItemsControl ItemTemplate="{StaticResource MyTemplate}">
<ItemsControl.Items>
<sys:String>One</sys:String>
<sys:String>Two</sys:String>
<sys:String>Three</sys:String>
</ItemsControl.Items>
</ItemsControl>
</Grid>
</Window>

Preserving indenting when wrapping in a wpf textblock control

I have a WPF textblock set up with the property TextWrapping="Wrap".
When I pass in a long string with a tab character (vbTab in my case) at the start, I would like the wrapping to honour this and keep the wrapped parts of the string indented.
For example, instead of:
[vbTab]thisisreallylong
andwrapped
I want
[vbTab]thisisreallylong
[vbTab]andwrapped
and ideally for multiple tabs, etc. too.
[edit - additional details]
Because the textblock will be of variable size and contain multiple lines of text with various amounts of indenting, I can't just have a margin or manually split the strings and add tabs.
Essentially what I want is for it to treat lines of text like paragraphs, that keep their indenting when they wrap.
Based on your idea, I am able to come up with this solution
I'll convert all the tabs in the beginning of every line to .5 inch margin each and will add the same text in a paragraph and apply the calculated margin to the same
A TextBlock was not feasible for the same as it is useful for basic text inlines like run bold, inline ui container etc. adding paragraph was more complicated in a TextBlock so I made the solution based on FlowDocument.
Result
below example demonstrate the same using FlowDocumentScrollViewer or RichTextBox or FlowDocumentReader or plain FlowDocument
I have created the solution using attached properties, so you can attach the same to any of the mentioned or even add your own host for the document. you simply have to set IndentationProvider.Text to the desired host.
XAML
<Window x:Class="MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:l="clr-namespace:PreservingIndentationDemo"
Title="MainWindow"
Height="350"
Width="525">
<Window.Resources>
<sys:String x:Key="longString"
xml:space="preserve"> this is really long and wrapped
another line this is also really long and wrapped
one more line this is also really long and wrapped
another line this is also really long and wrapped
another line this is also really long and wrapped
</sys:String>
</Window.Resources>
<Grid>
<FlowDocumentScrollViewer l:IndentationProvider.Text="{StaticResource longString}" />
<!--<RichTextBox l:TextToParaHelper.Text="{StaticResource longString}" IsReadOnly="True"/>-->
<!--<FlowDocumentReader l:TextToParaHelper.Text="{StaticResource longString}" />-->
<!--<FlowDocument l:TextToParaHelper.Text="{StaticResource longString}" />-->
</Grid>
</Window>
refers to tab char
IndentationProvider
Class IndentationProvider
Public Shared Function GetText(obj As DependencyObject) As String
Return DirectCast(obj.GetValue(TextProperty), String)
End Function
Public Shared Sub SetText(obj As DependencyObject, value As String)
obj.SetValue(TextProperty, value)
End Sub
' Using a DependencyProperty as the backing store for Text. This enables animation, styling, binding, etc...
Public Shared ReadOnly TextProperty As DependencyProperty = DependencyProperty.RegisterAttached("Text", GetType(String), GetType(IndentationProvider), New PropertyMetadata(Nothing, AddressOf OnTextChanged))
Private Shared Sub OnTextChanged(d As DependencyObject, e As DependencyPropertyChangedEventArgs)
Dim blocks As BlockCollection = Nothing
Dim rtb As RichTextBox = TryCast(d, RichTextBox)
If rtb IsNot Nothing Then
rtb.Document.Blocks.Clear()
blocks = rtb.Document.Blocks
End If
If blocks Is Nothing Then
Dim fd As FlowDocument = TryCast(d, FlowDocument)
If fd IsNot Nothing Then
fd.Blocks.Clear()
blocks = fd.Blocks
End If
End If
If blocks Is Nothing Then
Dim fdr As FlowDocumentReader = TryCast(d, FlowDocumentReader)
If fdr IsNot Nothing Then
fdr.Document = New FlowDocument()
blocks = fdr.Document.Blocks
End If
End If
If blocks Is Nothing Then
Dim fdr As FlowDocumentScrollViewer = TryCast(d, FlowDocumentScrollViewer)
If fdr IsNot Nothing Then
fdr.Document = New FlowDocument()
blocks = fdr.Document.Blocks
End If
End If
Dim newValue As String = TryCast(e.NewValue, String)
If Not String.IsNullOrWhiteSpace(newValue) Then
For Each line As String In newValue.Split(ControlChars.Lf)
Dim leftMargin As Double = 0
Dim newLine As String = line
While newLine.Length > 0 AndAlso newLine(0) = ControlChars.Tab
leftMargin += 0.5
newLine = newLine.Remove(0, 1)
End While
Dim marginInch As String = leftMargin & "in"
Dim marginDip As Double = CDbl(New LengthConverter().ConvertFromString(marginInch))
Dim para As New Paragraph(New Run(newLine)) With {.Margin = New Thickness(marginDip, 0, 0, 0)}
blocks.Add(para)
Next
End If
End Sub
End Class
Demo
try demo project

Grid.GetRow() always returns 0

I am having trouble getting the row of a WPF grid that a textbox is in.
I have a grid that starts off with one RowDefinition. That row contains an "add" button that adds another rowdefinition to the grid below that row. This new row also contains an "add" button that performs the same function.
The problem I am having is that the function GetRow() always returns 0.
If I declare a button in the XAML that calls the same function, GetRow() returns the correct value. The problem seems to stem from the face that the buttons are created in codebehind.
This is the function that handles the click event of the "add" buttons:
Private Sub btnAddRow_Click(ByVal sender As System.Object, _
ByVal e As System.Windows.RoutedEventArgs)
Dim btnSender As Button = sender
Dim row As Integer
row = Grid.GetRow(btnSender)
AddRow(row)
End Sub
The function "AddRow" adds a new RowDefinition to the grid, the "add" button for that row, and a few other controls (label, textbox, etc).
Private Sub AddRow(ByVal position As Integer)
Dim rd As New RowDefinition()
rd.Height = New GridLength(35, GridUnitType.Pixel)
Me.Height += 35
myGrid.RowDefinitions.Insert(position, rd)
Dim add As New Button
add.Content = "Add Row"
add.HorizontalAlignment = Windows.HorizontalAlignment.Center
add.VerticalAlignment = Windows.VerticalAlignment.Center
AddHandler add.Click, AddressOf btnAddRow_Click
Grid.SetColumn(add, 2)
Grid.SetRow(add, position)
myGrid.Children.Add(add)
End Sub
I found this thread, but using "e.Source" or "e.OriginalSource" did not solve the problem.
Grid.GetRow and Grid.GetColumn keep returning 0
EDIT:
Here is my code. I pulled it out of the project it was in and created a new project for testing.
Class MainWindow
Private Sub btnAddRow_Click(ByVal sender As System.Object, _
ByVal e As System.Windows.RoutedEventArgs)
Dim btnSender As Button = sender
Dim row As Integer
row = Grid.GetRow(btnSender)
row = row + 1
AddRow(row)
End Sub
Private Sub AddRow(ByVal position As Integer)
If (myGrid.RowDefinitions.Count < position) Then
position = myGrid.RowDefinitions.Count
End If
For Each element In (From i As UIElement In myWaypointGrid.Children Where Grid.GetRow(i) >= position Select i).ToList()
Grid.SetRow(element, Grid.GetRow(element) + 1)
Next
Dim rd As New RowDefinition()
rd.Height = New GridLength(35, GridUnitType.Pixel)
Me.Height += 35
myGrid.RowDefinitions.Insert(position, rd)
Dim add As New Button
add.Content = "Add Row " & position
add.HorizontalAlignment = Windows.HorizontalAlignment.Center
add.VerticalAlignment = Windows.VerticalAlignment.Center
AddHandler add.Click, AddressOf btnAddRow_Click
Grid.SetColumn(add, 2)
Grid.SetRow(add, position)
myGrid.Children.Add(add)
End Sub
Private Sub MainWindow_Loaded(ByVal sender As Object, _
ByVal e As System.Windows.RoutedEventArgs) Handles Me.Loaded
AddRow(0)
End Sub
End Class
<Window x:Class="MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid Name="myGrid">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="75" />
</Grid.ColumnDefinitions>
</Grid>
Thanks for your help.
Are you ever calling the AddRow function prior to the first "Add" button click? Without more code, it's hard to say why this is not working.
Update to reflect the true issue:
You don't do an increment on the position variable which gets passed into this function so all your buttons are being added to row 0. That is why they all return 0 when you call GetRow

Resources