I am using this function to recurse thru all the controls inside a ListBoxItem and I have both a Button and a TextBlock inside the DataTemplate. It always picks the Button instead of the TextBlock. Can anyone see whats wrong with my function?
Private Function FindVisualChild(ByVal obj As DependencyObject) As TextBlock
Dim result As TextBlock = Nothing
For i As Integer = 0 To VisualTreeHelper.GetChildrenCount(obj) - 1
Dim child As DependencyObject = TryCast(VisualTreeHelper.GetChild(obj, i), DependencyObject)
If Not child Is Nothing AndAlso TypeOf child Is DependencyObject Then
If TypeOf child Is TextBlock Then
Dim tbl As TextBlock = TryCast(child, TextBlock)
If Not tbl Is Nothing Then result = tbl
Else
Dim tbl As TextBlock = FindVisualChild(child)
If Not tbl Is Nothing Then result = tbl : Exit For
End If
End If
Next
Return result
End Function
Seems simple, but it works! Does not explain why it was confused with types below this line
Private Function FindVisualChild(ByVal obj As DependencyObject) As TextBlock
Dim result As TextBlock = Nothing
For i As Integer = 0 To VisualTreeHelper.GetChildrenCount(obj) - 1
Dim child As DependencyObject = TryCast(VisualTreeHelper.GetChild(obj, i), DependencyObject)
If TypeOf child Is Button Then Continue For 'fixes it
If Not child Is Nothing AndAlso TypeOf child Is DependencyObject Then
If TypeOf child Is TextBlock Then
Dim tbl As TextBlock = TryCast(child, TextBlock)
If Not tbl Is Nothing Then result = tbl
Else
Dim tbl As TextBlock = FindVisualChild(child)
If Not tbl Is Nothing Then result = tbl : Exit For
End If
End If
Next
Return result
End Function
Related
With this code i can get control only on MainWindow:
Public Shared Function FindChild(Of T As DependencyObject)(ByVal parent As DependencyObject, ByVal childName As String) As T
If parent Is Nothing Then Return Nothing
Dim foundChild As T = Nothing
Dim childrenCount As Integer = VisualTreeHelper.GetChildrenCount(parent)
For i As Integer = 0 To childrenCount - 1
Dim child = VisualTreeHelper.GetChild(parent, i)
Dim childType As T = TryCast(child, T)
If childType Is Nothing Then
foundChild = FindChild(Of T)(child, childName)
If foundChild IsNot Nothing Then Exit For
ElseIf Not String.IsNullOrEmpty(childName) Then
Dim frameworkElement = TryCast(child, FrameworkElement)
If frameworkElement IsNot Nothing AndAlso frameworkElement.Name = childName Then
foundChild = CType(child, T)
Exit For
End If
Else
foundChild = CType(child, T)
Exit For
End If
Next
Return foundChild
End Function
Public sub findControl()
Dim foundTKU As TextBox = FindChild(Of TextBox)(Application.Current.MainWindow, "TKU_" & row("gorivo"))
End sub
How would I implement the same thing but instead MainWindow to look in active window or inside WPF grid which is called "controlGrid"
Just pass an instance of the active window or the control to the method instead of passing Application.Current.MainWindow:
Public sub findControl()
Dim foundTKU As TextBox = FindChild(Of TextBox)(controlGrid, "TKU_" & row("gorivo"))
End sub
I have a function which querys the database for Strings (which are x:Name="" in my application)
Following is the code:
Try
For Each s In output
Dim nameOfControl = s
Dim window = Windows.Application.Current.Windows(0)
Dim visuals = GetVisualChildren(Of FrameworkElement)(window)
Dim child = visuals.OfType(Of FrameworkElement)().FirstOrDefault(Function(x) x.Name = nameOfControl)
child.Visibility = Visibility.Collapsed
Next
Public Iterator Function GetVisualChildren(Of T As Visual)(parent As DependencyObject) As IEnumerable(Of T)
Dim child As T = Nothing
Dim numVisuals As Integer = VisualTreeHelper.GetChildrenCount(parent)
For i As Integer = 0 To numVisuals - 1
Dim v As Visual = DirectCast(VisualTreeHelper.GetChild(parent, i), Visual)
child = TryCast(v, T)
If v IsNot Nothing Then
For Each item In GetVisualChildren(Of T)(v)
Yield item
Next
End If
If child IsNot Nothing Then
Yield child
End If
Next
End Function
I cannot seem to figure out why this does not work for all elements, ie. my window consists of a TabControl which i can call by "x name", same goes for toolBar, everything works well even with TabItem's but i cannot reference to <Button x:Name="buttonRefresh" which is inside one of TabItem's grids.
I recieve a error NullReferenceException on line bellow:
child.Visibility = Visibility.Collapsed
If i insert a breakpoint at that line i get this {System.Windows.Controls.TabItem Header:FirstTab Content:} for child so i'm asuming i need to change something about this piece of code
Dim window = Windows.Application.Current.Windows(0)
Your problem is here:
Dim child = visuals.OfType(Of FrameworkElement)().FirstOrDefault(Function(x) x.Name = nameOfControl)
The FirstOrDefault method will return Nothing if the predicate results in False. In your case, it has done so because on the next line, child is null, hence the NRE:
child.Visibility = Visibility.Collapsed
You can't assign to the Visibility property on child because it's Nothing.
Your predicate is Function(x) x.Name = nameOfControl, so there must not be a value in the collection returned by visuals.OfType(Of FrameworkElement)() whose Name property equals nameOfControl.
To address this, you need to debug it and see what's really going on. I would break your statement into two lines:
Dim child = visuals.OfType(Of FrameworkElement)()
Dim match = child.FirstOrDefault(Function(x) x.Name = nameOfControl)
Put a break point on the second line so it breaks before that statement runs. Then look in your locals/autos window (assuming Visual Studio), and see what's actually in the collection.
One other thing to note here: when you compare x.Name to nameOfControl with the equals sign =, it does so in case sensitive manner, so if you have MyName and myname, those two are not equal. You can use this instead if you want it to be compare in a case-insensitive manner:
Function(x) x.Name.Equals(nameOfControl, StringComparison.CurrentCultureIgnoreCase)
With Winforms' DataGridView, one could use HitTest to determine the column and row index of the mouse down (and other events).
Dim hti As DataGridView.HitTestInfo = sender.HitTest(e.X, e.Y)
Is there something similar with WPF's DataGrid? I need to get the row and column indexes for the MouseLeftButtonDown event.
It's a bit more complicated than this but the following links should be helpful in getting the index of the row and column.
WPF DataGrid - detecting the column, cell and row that has been clicked: http://blog.scottlogic.com/2008/12/02/wpf-datagrid-detecting-clicked-cell-and-row.html
WPF DataGrid - get row number which mouse cursor is on
You will have to use the VisualTreeHelper class to traverse the Visual elements that make up the DataGrid as explained above.
For those that may wish to avoid my search here is the total code I ended up puzzling together that is able to deliver:
Current row index
Current Column index
Current Column header And
is able to expose the value/s of columns on the row.
The code goes into MouseLeftButtonup event and DGrid1 is the name of the grid
Dim currentRowIndex As Integer = -1
Dim CurrentColumnIndex As Integer = -1
Dim CurrentColumnHeader As String = ""
Dim Myrow As DataRowView = Nothing
Dim dep As DependencyObject = DirectCast(e.OriginalSource, DependencyObject)
While dep IsNot Nothing And Not TypeOf dep Is DataGridCell And Not TypeOf dep Is Primitives.DataGridColumnHeader
dep = VisualTreeHelper.GetParent(dep)
If dep IsNot Nothing Then
If TypeOf dep Is DataGridCell Then
Dim cell As DataGridCell = DirectCast(dep, DataGridCell)
Dim col As DataGridBoundColumn = DirectCast(cell.Column, DataGridBoundColumn)
Myrow = DGrid1.SelectedItem
CurrentColumnHeader = col.Header.ToString
CurrentColumnIndex = col.DisplayIndex
currentRowIndex = DGrid1.Items.IndexOf(DGrid1.CurrentItem)
Exit While
End If
End If
End While
If currentRowIndex = -1 OrElse CurrentColumnIndex = -1 OrElse CurrentColumnHeader = "" OrElse Myrow Is Nothing Then Exit Sub
'code to consume the variables from here
Dim strinwar As String = Myrow.Item("header name or index").ToString()
I want to search a text in the datagrid, A code written like below gives error
For i As Integer = 0 To _dt.Items.Count - 1
Dim row As DataGridRow = DirectCast(_dt.ItemContainerGenerator.ContainerFromIndex(i), DataGridRow)
For j As Integer = 0 To _dt.Columns.Count - 1
If row IsNot Nothing Then
Dim cellContent As TextBlock = TryCast(_dt.Columns(j).GetCellContent(row), TextBlock)
If cellContent IsNot Nothing AndAlso cellContent.Text.Equals(txtfind.Text) Then
_dt.ScrollIntoView(row, _dt.Columns(j))
Dim presenter As DataGridCellsPresenter = GetVisualChild(Of DataGridCellsPresenter(row))
Dim cell As DataGridCell = DirectCast(presenter.ItemContainerGenerator.ContainerFromIndex(j), DataGridCell)
_dt.SelectedItem = cell
cell.IsSelected = True
row.MoveFocus(New TraversalRequest(FocusNavigationDirection.[Next]))
Exit For
End If
End If
Next
Next
Error is for row : Array bounds cannot appear in type specifiers.
Statement: Dim presenter As DataGridCellsPresenter = GetVisualChild(Of DataGridCellsPresenter(row))
Help appreciated
abhimoh
Change:
Dim presenter As DataGridCellsPresenter = GetVisualChild(Of DataGridCellsPresenter(row))
'you have created an array with row number of values.
to:
Dim presenter As DataGridCellsPresenter = GetVisualChild(Of DataGridCellsPresenter)(row)
First off here is what i am trying to do: I need to dynamically reverse the order of the items in one stack panel and add them in the reverse order in a second. Here is the code that i am using:
Dim cp As ContentPresenter = TryCast(Utilities.GetDescendantFromName(TitleLegend, "ContentPresenter"), ContentPresenter)
If cp IsNot Nothing Then
Dim sp As StackPanel = TryCast(cp.Content, StackPanel)
If sp IsNot Nothing Then
Dim nsp As New StackPanel() With {.Orientation = System.Windows.Controls.Orientation.Vertical}
Dim count As Integer = sp.Children.Count
For i As Integer = count - 1 To 0 Step -1
Dim cc As ContentControl = TryCast(sp.Children(i), ContentControl)
If cc IsNot Nothing Then
sp.Children.Remove(cc)
nsp.Children.Add(cc)
End If
Next
cp.Content = Nothing
cp.Content = nsp
End If
End If
it runs through this code fine but right before the User Control loads i receive the error. I have looked around here and the solution that seems to work is removing the child from the first collection which i already do. Any help would be appreciated. Thank you
this is the solution that i used to solve my problem in case anyone else runs into this situation
Dim cp As ContentPresenter = TryCast(Utilities.GetDescendantFromName(TitleLegend, "ContentPresenter"), ContentPresenter)
If cp IsNot Nothing Then
Dim sp As StackPanel = TryCast(cp.Content, StackPanel)
If sp IsNot Nothing Then
If tempList Is Nothing Then
tempList = New List(Of ContentControl)
End If
Dispatcher.BeginInvoke(New Action(Function()
Dim count As Integer = sp.Children.Count
For i As Integer = count - 1 To 0 Step -1
Dim cc As ContentControl = TryCast(sp.Children(i), ContentControl)
sp.Children.Remove(TryCast(sp.Children(i), ContentControl))
If cc IsNot Nothing Then
tempList.Add(cc)
End If
Next
For i As Integer = count - 1 To 0 Step -1
Dim cc As ContentControl = TryCast(tempList(0), ContentControl)
tempList.Remove(TryCast(tempList(0), ContentControl))
If cc IsNot Nothing Then
sp.Children.Add(cc)
End If
Next
End Function), System.Windows.Threading.DispatcherPriority.Background, Nothing)
End If
End If