Grid.GetRow() always returns 0 - wpf

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

Related

NotifyCollectionChangedAction.Reset Empties ComboBox Text

I have a ComboBox, which its ItemsSource is set to an object which inherits ObservableCollection.
The object gets refreshed with new data on a timer.
Since sometimes there is a large set of new data, I don't use the Add method on the ObservableCollection, but rather I use the following code:
For Each itm In MyNewItems
Items.Add(itm)
Next
MyBase.OnPropertyChanged(New PropertyChangedEventArgs("Count"))
OnPropertyChanged(New PropertyChangedEventArgs("Items[]"))
'NEXT LINE CAUSES ISSUE
OnCollectionChanged(New NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset))
The problem is that when the last line runs, the Text of the ComboBox gets reset to an empty string.
If I remove that line, then the issue is resolved, but the Items show old data, since the ComboBox doesn't know that new data came in
Please advise
With appreciation
UPDATE
Hi, as requested, I'm posting the relevant code here
1: The Xaml, Pretty Simple:
<Window x:Class="dlgTest"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mch="clr-namespace:Machshevet.Windows;assembly=Machshevet" >
<StackPanel>
<TextBlock Text="{Binding CaseID}"/>
<mch:TestPick Name="cmbTest" SelectedValuePath="ID" DisplayMemberPath="Name" SelectedValue="{Binding CaseID}" IsEditable="True" IsTextSearchEnabled="False" />
</StackPanel>
</Window>
2: The TestPick class, not too complex either:
Public Class TestPick
Inherits ComboBox
Dim usertyped As Boolean
Function Query() As IQueryable
Dim txt = ""
Dispatcher.Invoke(Sub() txt = Text)
Dim ret = GetSlimContext.Query("viwCase").Select("new (ID,Name,ClientName,SubjectName)")
If txt <> "" AndAlso usertyped Then ret = ret.TextFiltered(txt)
Return ret
End Function
Private Sub EntityPick_Loaded(sender As Object, e As RoutedEventArgs) Handles Me.Loaded
Dim qs = New QuerySource(Function() Query())
Me.ItemsSource = qs
qs.Control = Me
qs.ShouldRefresh = Function() True
End Sub
Private Sub EntityPick_PreviewTextInput(sender As Object, e As TextCompositionEventArgs) Handles Me.PreviewTextInput
usertyped = True
End Sub
Private Sub TestPick_SelectionChanged(sender As Object, e As SelectionChangedEventArgs) Handles Me.SelectionChanged
If e.AddedItems.None Then
Dim a = 1
End If
End Sub
End Class
3: The QuerySource class which does all the heavy lifting
Public Class QuerySource
Inherits ObjectModel.ObservableCollection(Of Object)
Event Refreshed(sender As QuerySource, e As EventArgs)
Property RefreshSpan As TimeSpan = TimeSpan.FromSeconds(3)
Property CheckProperties As Boolean = True
Property Control As ItemsControl
Dim Timer As Threading.Timer = New Threading.Timer(Sub() TimerTick(), Nothing, 0, 600)
Dim _lastRefresh As Date?
Dim Query As Func(Of IQueryable)
Dim workingon As Date?
Sub New(Query As Func(Of IQueryable), Control As ItemsControl)
Me.Control = Control
Me.Query = Query
End Sub
Async Sub TimerTick()
Try
If Now - _lastRefresh.GetValueOrDefault < RefreshSpan Then Exit Sub
If GetLastInputTime() > 60 * 15 Then Exit Sub
Dim isvis = False
Await Control.Dispatcher.BeginInvoke(Sub() isvis = Control.IsUserVisible())
If Not isvis Then Exit Sub
If workingon.HasValue AndAlso workingon.Value > Now.AddSeconds(-15) Then Exit Sub 'if wasnt working for 15 seconds, probaly err or something
workingon = Now
Dim fq = Query.Invoke
Dim itmtype = fq.ElementType
Dim props = itmtype.CachedProperties.Where(Function(x) x.CanWrite AndAlso x.IsScalar(True)).ToList
Dim keyprops = itmtype.CachedKeyProperties.ToList
Dim newData = fq.ToObjectList
If newData Is Nothing Then Exit Sub
Dim keySelector As Func(Of Object, Object)
Dim diff As CollectionDiff(Of Object)
If itmtype.IsScalar Then 'list of strings..
keySelector = Function(x) x
Else
If keyprops.Count <> 1 Then DevError("?")
Dim kp = keyprops.FirstOrDefault
keySelector = Function(x) kp.GetValue(x)
End If
diff = CollectionDiff(Me, newData, keySelector, props, CheckProperties)
Dim toPreserve As Object
ExecIfType(Of Primitives.Selector)(Control, Sub(x) toPreserve = x.Dispatcher.Invoke(Function() x.SelectedItem))
If toPreserve IsNot Nothing Then diff.ToPreserve = {toPreserve}.ToDictionary(Function(x) x, Function(x) Nothing)
diff.PreserveOnDelete = True
If diff.ModificationCount > 400 Or diff.ClearOld Then
CheckReentrancy()
If diff.ClearOld Then
Items.Clear()
Else
For Each pair In diff.ToReplaceByIndex
Control.Dispatcher.Invoke(Sub() Items(pair.Key) = pair.Value)
Next
For Each idx In diff.GetIndexesToDelete
Items.RemoveAt(idx)
Next
End If
For Each itm In diff.ToAdd 'for mem optimization im not using addrange
Items.Add(itm)
Next
MyBase.OnPropertyChanged(New PropertyChangedEventArgs("Count"))
OnPropertyChanged(New PropertyChangedEventArgs("Items[]"))
Control.Dispatcher.Invoke(Sub() OnCollectionChanged(New NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)))
Else
Dim preservIdx = diff.ToPreserve?.Select(Function(x) Items.IndexOf(x.Key))?.ToHashSet
For Each pair In diff.ToReplaceByIndex
Control.Dispatcher.Invoke(Sub() Me(pair.Key) = pair.Value)
Next
For Each idx In diff.GetIndexesToDelete
If diff.PreserveOnDelete AndAlso preservIdx IsNot Nothing AndAlso preservIdx.Contains(idx) Then Continue For
Control.Dispatcher.Invoke(Sub() RemoveAt(idx))
Next
'don't use addrange - will cause a reset
Await Control.Dispatcher.BeginInvoke(Sub() diff.ToAdd.ForEach(Sub(x) Add(x)))
End If
_lastRefresh = Now
workingon = Nothing
Control.Dispatcher.Invoke(Sub()
Dim cvs = System.Windows.Data.CollectionViewSource.GetDefaultView(Me)
If cvs.SortDescriptions.None Then
Dim defsorts = {KVP("Name", False), KVP(NameOf(RecordBase.LastEditedOn), True), KVP(NameOf(LiteRecordBase.ID), True)}
For Each defsort In defsorts
If itmtype.HasProperty(defsort.Key) Then
cvs.SortDescriptions.Add(New SortDescription(defsort.Key, If(defsort.Value, ListSortDirection.Descending, ListSortDirection.Ascending)))
Exit For
End If
Next
End If
End Sub)
RaiseEvent Refreshed(Me, Nothing)
Catch ex As Exception
Control.Dispatcher.BeginInvoke(Sub() ex.Rethrow)
End Try
End Sub
End Class
Okay
Thanks all for chipping in, in the end it seems like my answer is actually here
ObservableCollection : calling OnCollectionChanged with multiple new items
Works like a charm, and thank you all again for your time and patience

Event not firing after item updated, even after re-adding the handler

In my Program Cyrus-Beck algorithm, I have to clip the points. The points inside the clipping window have to be red. The outside is still black.
I represent point in program as rectangle and I give the event handler for delete the point. when I wanted to delete points, points outside the window is working, but points that inside polygon didn't work, event the right-click event not call.
Here is my Point class.
Ignore the Component class, because it just nothing than handler to canvas in the main window
Public Class Points
Inherits Component
Public items As List(Of Point) = New List(Of Point)()
Public rects As List(Of Rectangle) = New List(Of Rectangle)
'add element
Public Overrides Sub Canvas1_MouseMove(sender As Object, e As MouseEventArgs)
canvas.Cursor = Cursors.Pen
End Sub
Public Overrides Sub Canvas1_MouseDown(sender As Object, e As MouseButtonEventArgs)
canvas.Cursor = Cursors.Pen
If e.LeftButton = MouseButtonState.Pressed Then
items.Add(e.GetPosition(canvas))
Dim p As Rectangle = New Rectangle()
p.Width = 3
p.Height = 3
canvas.SetLeft(p, e.GetPosition(canvas).X)
canvas.SetTop(p, e.GetPosition(canvas).Y)
p.Stroke = Brushes.Black
p.Fill = Brushes.Black
rects.Add(p)
End If
End Sub
'deleting element
'this method not calling when the element has updated
Sub point_rightClick(sender As Object, e As MouseButtonEventArgs)
Dim temp As Rectangle = New Rectangle()
temp = DirectCast(sender, Rectangle)
Dim pt As Point = New Point(Controls.Canvas.GetLeft(temp), Controls.Canvas.GetTop(temp))
canvas.Children.Remove(temp)
items.Remove(pt)
rects.Remove(temp)
End Sub
Public Shared Function samePoint(one As Rectangle, two As Rectangle) As Boolean
Return ((Controls.Canvas.GetLeft(one) = Controls.Canvas.GetLeft(two)) And (Controls.Canvas.GetTop(one) = Controls.Canvas.GetTop(two)))
End Function
Public Shared Function samePoint(one As Point, two As Rectangle) As Boolean
Return (one.X = Controls.Canvas.GetLeft(two)) And (one.Y = Controls.Canvas.GetTop(two))
End Function
End Class
To able to delete, I have deleting that represents the status, if deleting is true and currentState = MouseState.Pointer. the code will add handler to all the points (rectangles).
Private Sub chge_pointer_Click(sender As Object, e As RoutedEventArgs) Handles chge_pointer.Click
currentState = MouseState.Pointer
deleting = True
chooseHandler()
End Sub
Private Sub chooseHandler()
If deleting Then
For Each r As Rectangle In points.rects
AddHandler r.MouseRightButtonDown, AddressOf points.point_rightClick
Next
Else
For Each r As Rectangle In points.rects
RemoveHandler r.MouseRightButtonDown, AddressOf points.point_rightClick
Next
End If
End Sub
Before I modified the points to be red, I have to have a loop to check if the position is same, if the position same so edit the points
Dim z As CyrusBeck = New CyrusBeck(clippingWindow)
z.Clip(points.items)
'CyrusBeck has a properties 'points'
'CyrusBeck.points saves the all the point that inside the clipping window
For i As Integer = 0 To points.rects.Count - 1
For Each p As Point In z.points
If CGAProject.Points.samePoint(p, points.rects.Item(i)) Then
Dim temp_r As Rectangle = New Rectangle()
temp_r = points.rects.Item(i)
temp_r.Stroke = Brushes.Red
temp_r.Fill = Brushes.Red
points.rects.Add(temp_r)
points.rects.RemoveAt(i)
End If
Next
Next
when the program reaches this, currentState would Never to be MouseState.Pointer. so if user want to delete a point, user have to be press button chge_pointer so my chge_pointer_Click is called and all my handler would be re-setted again.
Why Rectangle.MouseRightButtonDown is not call when the rectangle has updated?
the rectangles that haven't update call the Rectangle.MouseRightButtonDown event, so I have re-set the handler.
What's worng?
Is there any alternative way so user can delete rectangle inside and outside the window?
Note :
I have resetted the handler just after I assigned back my Rectangle to the list, but it still didn't work.
I also create AddHandler temp_r.MouseRightButtonDown, AddressOf points.point_rightClick just after I assigned back my Rectangle to the list, but it didn't work either.
At the end of your events for clicking, like:
Sub point_rightClick(sender As Object, e As MouseButtonEventArgs)
I think you should have a "handles".
E.g.
Sub point_rightClick(sender As Object, e As MouseButtonEventArgs) Handles point.MouseClick
Without this, the sub will never be called (as it seems is happening).
This method also has no "handles"
Public Overrides Sub Canvas1_MouseDown(sender As Object, e As MouseButtonEventArgs)
and it could be:
Public Overrides Sub Canvas1_MouseDown(sender As Object, e As MouseButtonEventArgs) Handles Canvas1.MouseDown

Is there a way to prevent a user selecting another row when DataGrid is in edit mode?

I want, that if a cell/row goes to edit mode, then, if the user attempts to select a different row, it should try to commit that row, if the row is not committed sucessfully, it should decline the selection request and the editing row should remain selected and in edit mode.
Do you have experience with a good helper for it? any good workaround?
NOTE: I've been struggling with this issue for a long time and already got some experience, so please post only working examples, not random thoughts.
The code bellow is includes extension from here (code normalized to fit StackOverflow screen witdh, sorry).
Imports System.ComponentModel
Imports System.Windows.Threading
Namespace Components
Public NotInheritable Class DataGridSelectionChangingBehavior
Public Shared Function GetEnableSelectionChanging(
ByVal element As DataGrid) As Boolean
If element Is Nothing Then Throw New ArgumentNullException("element")
Return element.GetValue(EnableSelectionChangingProperty)
End Function
Public Shared Sub SetEnableSelectionChanging(
ByVal element As DataGrid, ByVal value As Boolean)
If element Is Nothing Then Throw New ArgumentNullException("element")
element.SetValue(EnableSelectionChangingProperty, value)
End Sub
Public Shared ReadOnly EnableSelectionChangingProperty As _
DependencyProperty =
DependencyProperty.RegisterAttached("EnableSelectionChanging",
GetType(Boolean),
GetType(DataGridSelectionChangingBehavior),
New FrameworkPropertyMetadata(False,
New PropertyChangedCallback(
AddressOf EnableSelectionChanging_PropertyChanged)))
Public Shared Sub AddSelectionChangingHandler(
ByVal element As DataGrid, handler As SelectionChangingEventHandler)
If element IsNot Nothing Then _
element.AddHandler(
DataGridSelectionChangingBehavior.SelectionChangingEvent, handler)
End Sub
Public Shared Sub RemoveSelectionChangingHandler(
ByVal element As DataGrid, handler As SelectionChangingEventHandler)
If element IsNot Nothing Then _
element.RemoveHandler(
DataGridSelectionChangingBehavior.SelectionChangingEvent, handler)
End Sub
Public Shared ReadOnly SelectionChangingEvent As RoutedEvent =
EventManager.RegisterRoutedEvent("SelectionChanging",
RoutingStrategy.Bubble,
GetType(SelectionChangingEventHandler),
GetType(DataGridSelectionChangingBehavior))
Private Shared Sub EnableSelectionChanging_PropertyChanged(
ByVal sender As Object, ByVal e As DependencyPropertyChangedEventArgs)
Dim dataGrid = DirectCast(sender, DataGrid)
If CBool(e.NewValue) Then
AddHandler dataGrid.PreparingCellForEdit,
AddressOf DataGrid_PreparingCellForEdit
AddHandler dataGrid.SelectionChanged,
AddressOf DataGrid_SelectionChanged
Else
RemoveHandler dataGrid.PreparingCellForEdit,
AddressOf DataGrid_PreparingCellForEdit
RemoveHandler dataGrid.SelectionChanged,
AddressOf DataGrid_SelectionChanged
RecentColumn.Remove(dataGrid)
End If
End Sub
Private Shared Sub DataGrid_SelectionChanged(
ByVal sender As Object, ByVal e As SelectionChangedEventArgs)
If e.RemovedItems.Count = 0 Then Exit Sub
Dim dataGrid = DirectCast(sender, DataGrid)
Dim removed = e.RemovedItems(0)
Dim row = dataGrid.GetContainerFromItem(Of DataGridRow)(removed)
Dim scea As New SelectionChangingEventArgs(row,
DataGridSelectionChangingBehavior.SelectionChangingEvent, dataGrid)
dataGrid.RaiseEvent(scea)
If scea.Cancel Then
RemoveHandler dataGrid.SelectionChanged,
AddressOf DataGrid_SelectionChanged
Dim operation = dataGrid.Dispatcher.BeginInvoke(
Sub()
dataGrid.SelectedItem = removed
Dim column As DataGridColumn = Nothing
If RecentColumn.TryGetValue(dataGrid, column) Then
Dim cellsPanel =
row.GetVisualDescendant(Of DataGridCellsPanel)().
Children.Cast(Of DataGridCell)()
Dim recentCell =
If(cellsPanel.SingleOrDefault(
Function(cell) cell.Column Is column),
cellsPanel.FirstOrDefault)
If recentCell IsNot Nothing Then
recentCell.IsEditing = True
Keyboard.Focus(recentCell)
End If
End If
End Sub,
DispatcherPriority.ContextIdle)
AddHandler operation.Completed,
Sub(s, ea) AddHandler dataGrid.SelectionChanged,
AddressOf DataGrid_SelectionChanged
End If
End Sub
Private Shared m_RecentColumn As Dictionary(Of DataGrid, DataGridColumn)
Public Shared ReadOnly Property RecentColumn() As Dictionary(Of DataGrid,
DataGridColumn)
Get
If m_RecentColumn Is Nothing Then m_RecentColumn =
New Dictionary(Of DataGrid, DataGridColumn)()
Return m_RecentColumn
End Get
End Property
Private Shared Sub DataGrid_PreparingCellForEdit(
ByVal sender As Object, e As DataGridPreparingCellForEditEventArgs)
Dim dataGrid = DirectCast(sender, DataGrid)
RecentColumn(dataGrid) = e.Column
End Sub
End Class
Public Delegate Sub SelectionChangingEventHandler(
ByVal sender As Object, ByVal e As SelectionChangingEventArgs)
Public Class SelectionChangingEventArgs : Inherits RoutedEventArgs
Public Sub New(ByVal row As DataGridRow, routedEvent As RoutedEvent)
MyBase.New(routedEvent)
m_CurrentRow = row
End Sub
Public Sub New(ByVal row As DataGridRow,
ByVal routedEvent As RoutedEvent,
ByVal source As Object)
MyBase.New(routedEvent, source)
m_CurrentRow = row
End Sub
Private m_CurrentRow As DataGridRow
Public ReadOnly Property CurrentRow() As DataGridRow
Get
Return m_CurrentRow
End Get
End Property
Public ReadOnly Property Item() As Object
Get
If CurrentRow IsNot Nothing Then Return CurrentRow.Item
Return Nothing
End Get
End Property
Public Property Cancel As Boolean
End Class
End Namespace
Usage:
<DataGrid Name="dg"
src:DataGridSelectionChangingBehavior.EnableSelectionChanging="True"
src:DataGridSelectionChangingBehavior.SelectionChanging="dg_SelectionChanging">
Code behind (pseudu):
Private Sub dg_SelectionChanging(ByVal sender As Object,
ByVal e As SelectionChangingEventArgs)
If e.CurrentRow.IsEditing Then
Dim item = TryCast(e.CurrentRow.Item, MyEntityType)
If item IsNot Nothing AndAlso item.IsValid Then
Dim dataGrid = DirectCast(sender, DataGrid)
Dim committed = dataGrid.CommitEdit(DataGridEditingUnit.Row, True)
If committed Then Exit Sub
End If
e.Cancel = True
End If
End Sub
Note: visual studio might not show the event in the intellisense and might even generate a design-time error, but it should compile and work perfect.
FYI: code formatted modified to fit SO screen.

How to populate and access a list of checkboxes? VB.NET WPF

(This a follow-up to a previous question. VB.NET WPF NullReference Exception)
I have a TreeView with a parent node and two children node. Each of the nodes contain a checkbox stored in a TreeViewItem. I want the two children node checkboxes to be set to IsChecked=true when the user checks the parent node and I want the two children node checkboxes to be IsChecked=false when the user unchecks the parent node.
I have a for loop in which the child node checkboxes are stored in a list. The parent node's checkbox check/uncheck event should iterate through the child node checkbox list but I am having a problem with the childCheckboxes list in the chkbox_AllChecked function (the parent node's checkbox check/uncheck event). For some reason the list is empty. I think the problem is how I try to populate the list while inside a For loop. Can anyone explain what I am doing wrong?
Here's My Code:
Public Class Question
Dim childCheckbox As CheckBox
Dim childCheckboxes As New List(Of CheckBox)
Public Sub Window_Loaded(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles MyBase.Loaded
Dim parentCheckbox = New CheckBox
Dim parentNode = New TreeViewItem
parentCheckbox.Uid = "All Sites"
AddHandler parentCheckbox.Checked, AddressOf chkbox_AllChecked
AddHandler parentCheckbox.Unchecked, AddressOf chkbox_AllUnchecked
parentCheckbox.Content = "All Sites"
parentNode.Header = parentCheckbox
Dim i As Integer = 0
Dim childCheckboxes(sites.Length) As CheckBox
For Each osite In sites
Dim childNode = New TreeViewItem
Dim childCheckbox = New CheckBox
AddHandler childCheckbox.Checked, AddressOf chkbox_Checked
AddHandler childCheckbox.Unchecked, AddressOf chkbox_Unchecked
childCheckbox.Uid = osite.SiteName.ToString
childCheckbox.Content = osite.SiteName.ToString
childNode.Header = childCheckbox
parentNode.Items.Add(childNode)
'Add all childCheckbox to an array for use by parentChildbox methods to check/uncheck all
childCheckboxes(i) = childCheckbox
i += 1
Next
TreeView1.Items.Add(parentNode)
End Sub
Private Sub chkbox_AllChecked(ByVal sender As Object, ByVal e As RoutedEventArgs)
Dim chk = DirectCast(sender, CheckBox)
'MessageBox.Show(chk.Uid.ToString)
'This part doesn't work.
For Each c In childCheckboxes
c.IsChecked = True
Next
End Sub
Private Sub chkbox_Checked(ByVal sender As Object, ByVal e As RoutedEventArgs)
Dim chk = DirectCast(sender, CheckBox)
'MessageBox.Show("Check!")
MessageBox.Show(chk.Uid.ToString)
End Sub
Private Sub chkbox_Unchecked(ByVal sender As Object, ByVal e As RoutedEventArgs)
Dim chk = DirectCast(sender, CheckBox)
'MessageBox.Show("Uncheck!")
MessageBox.Show(chk.Uid.ToString)
End Sub
End Class
Thanks for the help!
Ok I figured this out.
1) I didn't want this line: Dim childCheckboxes(sites.Length) As CheckBox
because that's an array not a list.
2) Once that first line is deleted I needed to change: childCheckboxes(i) = childCheckbox
to this: childCheckboxes.Add(childCheckbox)
That's it! Done. The rest works.

(WPF VB.Net) How to get the state of a Checkbox that is nested inside a TreeView?

I have a WPF window with a TreeView that contains a checkbox at each node. I want to be able to capture the state of the checkboxes but I don't know how. (I am trying to do this without writing much of the code in XML)
Here is what I have in the XML:
<TreeView Grid.Column="1" Grid.ColumnSpan="3" Grid.Row="1" Height="200" HorizontalAlignment="Left" Margin="126,299,0,0" Name="TreeView1" VerticalAlignment="Top" Width="220" ItemsSource="{Binding}" DataContext="{Binding}">
</TreeView>
And in the VB Code:
Dim site As ELSite
Dim sites() As ELSite
Dim parentCheckbox = New CheckBox
Dim parentNode = New TreeViewItem
parentCheckbox.Content = "All Sites"
parentNode.Header = parentCheckbox
For Each osite In sites
Dim childNode = New TreeViewItem
Dim childCheckbox = New CheckBox
childCheckbox.Content = osite.SiteName.ToString
childNode.Header = childCheckbox
parentNode.Items.Add(childNode)
Next
TreeView1.Items.Add(parentNode)
Private Sub TreeView1_SelectedItemChanged(ByVal sender As System.Object, ByVal e As System.Windows.RoutedPropertyChangedEventArgs(Of System.Object)) Handles TreeView1.SelectedItemChanged
'This event doesn't seem to occur when I check or uncheck a checkbox
End Sub
Thanks for the help!
...
For Each osite In sites
Dim childNode = New TreeViewItem
Dim childCheckbox = New CheckBox
' add this to your code '
AddHandler childCheckBox.Checked, AddressOf chkbox_Checked
AddHandler childCheckBox.Unchecked, AddressOf chkbox_Unchecked
'-----------------------'
childCheckbox.Content = osite.SiteName.ToString
childNode.Header = childCheckbox
parentNode.Items.Add(childNode)
Next
...
Private Sub chkbox_Checked(ByVal sender As Object, ByVal e As RoutedEventArgs)
Dim chk = DirectCast(sender, CheckBox)
' Do whatever needs to be done when chk has been checked '
End Sub
Private Sub chkbox_Unchecked(ByVal sender As Object, ByVal e As RoutedEventArgs)
Dim chk = DirectCast(sender, CheckBox)
' Do whatever needs to be done when chk has been unchecked '
End Sub

Resources