I have a databound WPF ListBox with a custom itemtemplate -> datatemplate. Part of that template is also a ListBox.
On certain event I'd like to loop through all textboxes in the ListBox and retreive their values.
Is this possible?
You should be able to do this by using the ItemContainerGenerator and finding elements in the template:
foreach (var item in lb.Items)
{
var itemContainer = lb.ItemContainerGenerator.ContainerFromItem(item) as ListBoxItem;
// Name the TextBox in the template to find it here.
var textBox = itemContainer.ContentTemplate.FindName("?????", itemContainer) as TextBox;
var value = textBox.Text;
}
(If the TextBoxes you referred to are within the ListBox which is in the template you have to dig deeper by repeating the same method.)
Related
I have a Button on a UserControl that adds an item to a ListBox on that UserControl. Let's call that control Parent. The ListBoxItems contain another UserControl. Let's call that Child. The button adds an item to the ItemSource of the listbox (MVVM style).
I can scroll that into view without a problem. I can set the focus to the ListBoxItem, but what I want is the focus to be set on the first TextBox of the child UserControlof the content of the ListBoxItem. I can't seem to figure that out. The code below sets the focus to the ListBoxItem, not the UserControl child of it or any control on it.
Private Sub bnAdd(sender As Object, e As RoutedEventArgs)
VM.AddDetail()
MyList.ScrollIntoView(MyList.Items(MyList.Items.Count - 1))
Dim ListBoxItem As ListBoxItem = MyList.ItemContainerGenerator.ContainerFromItem(MyList.SelectedItem)
ListBoxItem.Focus()
End Sub
On my child UserControl I used this in XAML:
FocusManager.FocusedElement="{Binding ElementName=txtMyBox}"
There is a related question here and most of the approaches use hooking into focus events to achieve the focus change. I want to propose another solution that is based on traversing the visual tree. Unfortunately, I can only provide you C# code, but you can use the concept to apply it in your Visual Basic code.
As far as I can see, you are using code-behind to scroll your items into view. I will build on that. Your list box has list box items and I guess you use a data template to display UserControls as child items. Within these user controls there is a TextBox that you have assigned a name in XAML via x:Name or in code-behind via the Name property. Now, you need a helper method to traverse the visual tree and search for text boxes.
private IEnumerable<TextBox> FindTextBox(DependencyObject dependencyObject)
{
// No other child controls, break
if (dependencyObject == null)
yield break;
// Search children of the current control
for (var i = 0; i < VisualTreeHelper.GetChildrenCount(dependencyObject); i++)
{
var child = VisualTreeHelper.GetChild(dependencyObject, i);
// Check if the current item is a text box
if (child is TextBox textBox)
yield return textBox;
// If we did not find a text box, search the children of this child recursively
foreach (var childOfChild in FindTextBox(child))
yield return childOfChild;
}
}
Then we add a method that filters the enumerable of text boxes for a given name using Linq.
private TextBox FindTextBox(DependencyObject dependencyObject, string name)
{
// Filter the list of text boxes for the right one with the specified name
return FindTextBox(dependencyObject).SingleOrDefault(child => child.Name.Equals(name));
}
In your bnAdd handler you can take your ListBoxItem, search for the text box child and focus it.
var textBox = FindTextBox(listBoxItem, "MyTextBox");
textBox.Focus();
i'm new to wpf and i am having a problem with items control. What i want to do is that i want to retrieve the user control that i've added in itemtemplate of items control. I tried using LoadContent() method of DataTemplate but it returns me the default template.
Here my code
ItemsControl parent = FindParent<ItemsControl>( this );
//this.isEditMode = true;
//this.editIngLayer.Visibility = Visibility.Visible;
foreach( var container in parent.Items )
{
DependencyObject contentPresenter=
parent.ItemContainerGenerator.ContainerFromItem( container ) as ContentPresenter;
//Something to retrieve the usercontrol
MyUserControl uC=contentPresenter.GetControl();
//
}
Thanks.
If you have your ItemsControl item with you then you can iterate its Visualtree to reach to your usercontrol using VisualTreeHelper
Recursive find child is explained in this post
How can I find WPF controls by name or type?
I have DataGrid that needs to be printed in multiple pages both horizontally and vertically. Based on exhaustive searching the closest solution i have is the one found #http://www.codeproject.com/Articles/138233/Custom-Data-Grid-Document-Paginator. However, if DataGridTemplateColumn having ComboBox as its content is printed, the resultant print output is blank combobox. Below is the screenshot of the print,
http://www.filedropper.com/datagridprint
Below is the code used to create a template column while printing,
private FrameworkElement GetTableCell(Grid grid, DataGridColumn column, object item, int columnIndex, int rowIndex)
{
FrameworkElement visualElement = null;
if (column is DataGridTemplateColumn)
{
DataGridTemplateColumn templateColumn = column as DataGridTemplateColumn;
ContentControl contentControl = new ContentControl();
contentControl.Focusable = true;
contentControl.ContentTemplate = templateColumn.CellTemplate;
contentControl.Content = item;
contentControl.SetValue(Grid.ColumnProperty, columnIndex);
contentControl.SetValue(Grid.RowProperty, rowIndex);
visualElement = contentControl;
}
The above code basically creates new content control and adds the CellTemplate associated with the grid to the newly created content, which does not work. I would like to know if there is a fix for the above code, if not, is there a working solution that would print DataGrid into multiple pages (WYSIWYG).
Thanks for your help.
I have Window that has a ListBox
ListBox(MyListBox) has a DataTable for its DataContext
ListBox's ItemSource is : {Binding}
Listbox has a UserControl(MyUserControl) as DataTemplate
UserControl has RadioButtons and TextBoxes (At first They're filled with values from DataTable and then user can change them)
Window has one Submit Button
What I want to do is, when user clicks the submit button
For each ListBox Item, get the values form UserControl's TextBoxes and RadioButtons.
I was using that method for this job :
foreach(var element in MyListBox.Items)
{
var border = MyListBox.ItemContainerGenerator.ContainerFromItem(element)as FrameworkElement;
MyUserControl currentControl = VisualTreeHelper.GetChild(VisualTreeHelper.GetChild(VisualTreeHelper.GetChild(myBorder,0) as Border,0)as ContentPresenter,0)as MyUserControl;
//And use currentControl
}
I realised nothing when using 3-5 items in Listbox. But when I used much more items, I saw that "var border" gets "null" after some elements looped in foreach function.
I found the reason here :
ListView.ItemContainerGenerator.ContainerFromItem(item) return null after 20 items
So what can I do now? I want to access all items and get their values sitting on user controls.
Thanks
You should use objects who implement INotifyPropertyChanged and bind an ObservableCollection of it to the ItemSource
And then you can get all the list of items.
Here some quick links from MSDN to get more informations
How to: Implement Property Change Notification
Binding Sources Overview
You should google for some tutorials about this.
Zied's post is a solution for this problem. But I did the following for my project:
I realised that there's no need to use UserControl as DataTemplate in my project. So I removed ListBox's DataTemplate.
I removed MyListBox.DataContext = myDataTable and used this:
foreach(DataRow dr in myDataTable.Rows)
{
MyUserControl muc = new MyUserControl(dr);
myListBox.Items.Add(muc);
}
I took DataRow in my UserControl's constructor and did what I want.
And at last I could access my UserControls in ListBox by using :
foreach(MyUserControl muc in
myListBox)
{
//do what you want
}
Easy huh? :)
Hi I have contentControl in my user control. I am applying style to this contentControl which consist of TextBlock and ListBox. I am binding text of the textBlock to CategoryName(from Tag of the control). I want to bind category's child items to listBox. I have set ContentControl's dataContext property to child items[]. Now how to bind these child items to listbox which is in resource.
In loaded event of the user control
Panel pnl = sender as Panel;
Category category = panel.Tag as Category;
Items[] items = GetChildItemsByCategoryId(category.CategoryID);
mainContent.DataContext = items;
If the control is in the visual tree of mainContent, simply set in code or XAML
ItemsSource={Binding}