Silverlight:在 DataTemplate 中获取第一个 TextBox
Silverlight: Get first TextBox in DataTemplate
到目前为止,我已经查看了几个有关如何在 DataTemplate 中获取文本框的问题和答案,但是 none 对我有用。
我有 xaml 这样的(最小示例)。数据模板在我的静态资源部分,ItemsControl在内容部分:
<DataTemplate x:Key="GridTemplate">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="140" />
</Grid.ColumnDefinitions>
<sdk:IntegerTextBox DataField="Model.DataField" Width="90" SelectAllOnFocus="True" />
</Grid>
</DataTemplate>
<ItemsControl x:Name="MyControl" ItemsSource="{Binding MyList}" ItemTemplate="{StaticResource GridTemplate}" />
我需要能够在后面的代码中将焦点设置到网格中的第一个 IntegerTextBox。 IntegerTextBox继承TextBox class.
我首先尝试编写自己的方法来递归搜索所有 UIElement 以查找第一个 TextBox,但我发现 DataTemplate 中的内容无法以这种方式搜索。 ItemsControl 的子项始终 return 无:
Private Function FirstTextBox(ByVal uiElement As UIElement) As TextBox
Dim textBox As TextBox = TryCast(uiElement, TextBox)
If textBox IsNot Nothing Then Return textBox
Dim panel As Panel = TryCast(uiElement, Panel)
If panel IsNot Nothing Then
For Each child As UIElement In panel.Children
textBox = FirstTextBox(child)
If textBox IsNot Nothing Then Return textBox
Next
End If
Dim itemsControl As ItemsControl = TryCast(uiElement, ItemsControl)
If itemsControl IsNot Nothing Then
For i As Integer = 0 To itemsControl.Items.Count
textBox = FirstTextBox(CType(itemsControl.ItemContainerGenerator.ContainerFromIndex(i), UIElement))
If textBox IsNot Nothing Then Return textBox
Next
End If
Return textBox
End Function
我已经试过了,类似于here and here,但是ContentPresenter是Nothing:
Dim contentPresenter = CType(MyControl.ItemContainerGenerator.ContainerFromIndex(0), ContentPresenter)
Dim textbox As TextBox = CType(CType(contentPresenter.ContentTemplate.LoadContent(), Panel).Children.First(Function(c) TypeOf c Is TextBox), TextBox)
我尝试获取如图所示的 DataTemplate here, then loading the content and searching the children for a TextBox as shown here,但它从未找到 TextBox。
我已经为此工作了几天,但我看不出我做错了什么。这是一些明显的错误,还是我错误地解决了这个问题?谢谢。
编辑 - 这就是我通过添加 100 毫秒延迟使其工作的方式:
Private Function FindDescendant(Of TDescendant As DependencyObject)(ByVal obj As DependencyObject) As TDescendant
Dim all = VisualTreeExtensions.GetVisualDescendants(obj)
Dim first = all.OfType(Of TDescendant)().FirstOrDefault()
Return first
End Function
Private Sub bw_DoWork(ByVal sender As Object, ByVal e As ComponentModel.DoWorkEventArgs)
System.Threading.Thread.Sleep(100)
End Sub
Private Sub bw_RunWorkerCompleted(ByVal sender As Object, ByVal e As ComponentModel.RunWorkerCompletedEventArgs)
Dim firstTextBox = FindDescendant(Of IntegerTextBox)(MyControl)
If firstTextBox IsNot Nothing Then firstTextBox.Focus()
End Sub
Private Sub SetFocus()
Dim bw As New ComponentModel.BackgroundWorker
bw.WorkerReportsProgress = True
bw.WorkerSupportsCancellation = True
AddHandler bw.DoWork, AddressOf bw_DoWork
AddHandler bw.RunWorkerCompleted, AddressOf bw_RunWorkerCompleted
bw.RunWorkerAsync()
End Sub
您处理问题的方式不正确。访问 DataTemplate
并搜索 TextBox
将使您一无所获。
模板只是一个蓝图,只有当它在某处使用时(比如 ItemsControl 中的每个项目),它的内容才会被实例化(每个项目一次)。
将焦点设置到第一项的文本框的几种可能的解决方案之一:
在您的代码隐藏中,将事件处理程序添加到 itemsControl:
MyControl.GotFocus += (sender, args) =>
{
var firstItemTextBox = MyControl.FindDescendant<IntegerTextBox>();
if ( firstItemTextBox != null ) firstItemTextBox.Focus();
};
一些辅助代码:
//you need System.Windows.Controls.Toolkit.dll from the SilverlightToolkit for the class VisualTreeExtensions
using System.Windows.Controls.Primitives;
public static class ControlExtensions
{
public static TDescendant FindDescendant<TDescendant>(this DependencyObject element)
{
return element.GetVisualDescendants().OfType<TDescendant>().FirstOrDefault();
}
}
顺便说一句:为什么要将每个项目的 IntergerTextBox
包装在单独的 Grid
中?
到目前为止,我已经查看了几个有关如何在 DataTemplate 中获取文本框的问题和答案,但是 none 对我有用。
我有 xaml 这样的(最小示例)。数据模板在我的静态资源部分,ItemsControl在内容部分:
<DataTemplate x:Key="GridTemplate">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="140" />
</Grid.ColumnDefinitions>
<sdk:IntegerTextBox DataField="Model.DataField" Width="90" SelectAllOnFocus="True" />
</Grid>
</DataTemplate>
<ItemsControl x:Name="MyControl" ItemsSource="{Binding MyList}" ItemTemplate="{StaticResource GridTemplate}" />
我需要能够在后面的代码中将焦点设置到网格中的第一个 IntegerTextBox。 IntegerTextBox继承TextBox class.
我首先尝试编写自己的方法来递归搜索所有 UIElement 以查找第一个 TextBox,但我发现 DataTemplate 中的内容无法以这种方式搜索。 ItemsControl 的子项始终 return 无:
Private Function FirstTextBox(ByVal uiElement As UIElement) As TextBox
Dim textBox As TextBox = TryCast(uiElement, TextBox)
If textBox IsNot Nothing Then Return textBox
Dim panel As Panel = TryCast(uiElement, Panel)
If panel IsNot Nothing Then
For Each child As UIElement In panel.Children
textBox = FirstTextBox(child)
If textBox IsNot Nothing Then Return textBox
Next
End If
Dim itemsControl As ItemsControl = TryCast(uiElement, ItemsControl)
If itemsControl IsNot Nothing Then
For i As Integer = 0 To itemsControl.Items.Count
textBox = FirstTextBox(CType(itemsControl.ItemContainerGenerator.ContainerFromIndex(i), UIElement))
If textBox IsNot Nothing Then Return textBox
Next
End If
Return textBox
End Function
我已经试过了,类似于here and here,但是ContentPresenter是Nothing:
Dim contentPresenter = CType(MyControl.ItemContainerGenerator.ContainerFromIndex(0), ContentPresenter)
Dim textbox As TextBox = CType(CType(contentPresenter.ContentTemplate.LoadContent(), Panel).Children.First(Function(c) TypeOf c Is TextBox), TextBox)
我尝试获取如图所示的 DataTemplate here, then loading the content and searching the children for a TextBox as shown here,但它从未找到 TextBox。
我已经为此工作了几天,但我看不出我做错了什么。这是一些明显的错误,还是我错误地解决了这个问题?谢谢。
编辑 - 这就是我通过添加 100 毫秒延迟使其工作的方式:
Private Function FindDescendant(Of TDescendant As DependencyObject)(ByVal obj As DependencyObject) As TDescendant
Dim all = VisualTreeExtensions.GetVisualDescendants(obj)
Dim first = all.OfType(Of TDescendant)().FirstOrDefault()
Return first
End Function
Private Sub bw_DoWork(ByVal sender As Object, ByVal e As ComponentModel.DoWorkEventArgs)
System.Threading.Thread.Sleep(100)
End Sub
Private Sub bw_RunWorkerCompleted(ByVal sender As Object, ByVal e As ComponentModel.RunWorkerCompletedEventArgs)
Dim firstTextBox = FindDescendant(Of IntegerTextBox)(MyControl)
If firstTextBox IsNot Nothing Then firstTextBox.Focus()
End Sub
Private Sub SetFocus()
Dim bw As New ComponentModel.BackgroundWorker
bw.WorkerReportsProgress = True
bw.WorkerSupportsCancellation = True
AddHandler bw.DoWork, AddressOf bw_DoWork
AddHandler bw.RunWorkerCompleted, AddressOf bw_RunWorkerCompleted
bw.RunWorkerAsync()
End Sub
您处理问题的方式不正确。访问 DataTemplate
并搜索 TextBox
将使您一无所获。
模板只是一个蓝图,只有当它在某处使用时(比如 ItemsControl 中的每个项目),它的内容才会被实例化(每个项目一次)。
将焦点设置到第一项的文本框的几种可能的解决方案之一:
在您的代码隐藏中,将事件处理程序添加到 itemsControl:
MyControl.GotFocus += (sender, args) =>
{
var firstItemTextBox = MyControl.FindDescendant<IntegerTextBox>();
if ( firstItemTextBox != null ) firstItemTextBox.Focus();
};
一些辅助代码:
//you need System.Windows.Controls.Toolkit.dll from the SilverlightToolkit for the class VisualTreeExtensions
using System.Windows.Controls.Primitives;
public static class ControlExtensions
{
public static TDescendant FindDescendant<TDescendant>(this DependencyObject element)
{
return element.GetVisualDescendants().OfType<TDescendant>().FirstOrDefault();
}
}
顺便说一句:为什么要将每个项目的 IntergerTextBox
包装在单独的 Grid
中?