Wp8:Not able to get checkBox in listbox - c#

I am not able to find checkbox in listbox xaml:
<ListBox x:Name="my_list" Grid.Row="0">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" >
<CheckBox x:Name="cbx_state" Tag="{Binding}"/>
<TextBlock x:Name="txt_string" Text="{Binding}" VerticalAlignment="Center" FontSize="34" />
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ListBox>
I am trying to get cbk_state so that i can set its checked property.The function i used to get the checkbox is
private void GetItemsRecursive(DependencyObject lb)
{
var childrenCount = VisualTreeHelper.GetChildrenCount(lb);
for (int i = 0; i < childrenCount; i++)
{
var child = VisualTreeHelper.GetChild(lb, i);
if (child is ListBoxItem)
{
MessageBox.Show(child.GetType().ToString());
return;
}
GetItemsRecursive(child);
}
}
The problem is that i am getting ChildrenCount as zero everytime.
I have gone through several methods but no as such of use.Also tried
this
but here i am not getting ItemContainerGenerator for listBox.
I am new to wp8 programming plz help.Thanks

Are you asking about getting the Checked property of the Checkbox?
Is this the one you were looking for?. Sample code to find the Children control within a Parent using VisualTreeHelper:
private ChildControl FindVisualChild<ChildControl>(DependencyObject DependencyObj)
where ChildControl : DependencyObject
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(DependencyObj); i++)
{
DependencyObject Child = VisualTreeHelper.GetChild(DependencyObj, i);
if (Child != null && Child is ChildControl)
{
return (ChildControl)Child;
}
else
{
ChildControl ChildOfChild = FindVisualChild<ChildControl>(Child);
if (ChildOfChild != null)
{
return ChildOfChild;
}
}
}
return null;
}

Hi got the solution here. there is no need to set virtualization property its simple.
private void GetItemsRecursive(DependencyObject lb)
{
var childrenCount = VisualTreeHelper.GetChildrenCount(lb);
for (int i = 0; i < childrenCount; i++)
{
DependencyObject child = VisualTreeHelper.GetChild(lb, i);
if (child is CheckBox) // specific/child control
{
CheckBox targeted_element = (CheckBox)child;
targeted_element.IsChecked = true;
if (targeted_element.IsChecked == true)
{
return;
}
}
GetItemsRecursive(child);
}
}
just a bit change at DependencyObject child = VisualTreeHelper.GetChild(lb, i); instead of var child

Related

How to get ToolTip from WPF Data Grid Column Header (DataGridTemplateColumn) in code?

I set Tooltip for a DataGridTemplateColumn like this:
<DataGridTemplateColumn.Header>
<TextBlock Text="Current" ToolTip="Price" ToolTipService.InitialShowDelay="0" ToolTipService.Placement="Top" ToolTipService.ShowDuration="999999" RenderOptions.BitmapScalingMode="NearestNeighbor"/>
</DataGridTemplateColumn.Header>
How can I get the tooltip data in code?
Put the TextBlock in the HeaderTemplate of the column:
<DataGridTemplateColumn x:Name="col">
<DataGridTemplateColumn.HeaderTemplate>
<DataTemplate>
<TextBlock Text="Current" ToolTip="Price" ToolTipService.InitialShowDelay="0" ToolTipService.Placement="Top"
ToolTipService.ShowDuration="999999" RenderOptions.BitmapScalingMode="NearestNeighbor"/>
</DataTemplate>
</DataGridTemplateColumn.HeaderTemplate>
</DataGridTemplateColumn>
...and find it in using the VisualTreeHelper:
private void Button_Click(object sender, RoutedEventArgs e)
{
var columns = FindVisualChildren<System.Windows.Controls.Primitives.DataGridColumnHeader>(dataGrid)?
.ToArray();
if (columns != null)
{
int columnIndex = 1;
if (columns.Length > columnIndex)
{
var textBlock = FindVisualChildren<TextBlock>(columns[columnIndex])?
.FirstOrDefault();
if (textBlock != null)
{
string tooltip = textBlock.ToolTip?.ToString();
//...
}
}
}
}
private static IEnumerable<T> FindVisualChildren<T>(DependencyObject depObj) where T : DependencyObject
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
{
DependencyObject child = VisualTreeHelper.GetChild(depObj, i);
if (child is T t)
yield return t;
foreach (T childOfChild in FindVisualChildren<T>(child))
yield return childOfChild;
}
}
My guess from your comment on #mm8 answer:
private void DataGrid_Sorting( object sender, DataGridSortingEventArgs e )
{
var myHeaderItem = e.Column.Header as TextBlock;
Console.WriteLine(myHeaderItem?.ToolTip.ToString());
}

Adding button click event in datagridtemplatecolumn in user control from mainwindow programmatically

I have a MainWindow. It has a stackpanel myStack and some other things.
In stackPanel, there is a usercontrol (TaskGrid(_TG)) added programmatically.
In this UserControl, there is a DataGrid(dgEmployee), which have 4 template columns. the last column contains a button.
I am trying to assign the button click event from the mainwindow constructor and handle the event here.
Here are the codes:
in MainWindow.xaml
<Grid Grid.Row="2">
<StackPanel Name="myStack"/>
</Grid>
in MainWindow.xaml.cs
public MainWindow()
{
InitializeComponent();
_TG = new TaskGrid();
_TD = new _1.TaskDetails();
_TM = new _1.TaskMaster();
myStack.Children.Add(_TG);
_AUC = ActiveUserControl.Grid;
foreach (object child in myStack.Children)
{
string childname = "";
if (child is FrameworkElement)
{
childname = (child as FrameworkElement).Name;
if (childname == "TaskGrid")
{
Grid dg = ((Grid)((UserControl)child).Content);
foreach (var item in dg.Children)
{
DataGridColumn b = ((DataGrid)item).Columns[3] as DataGridColumn;
}
}
}
}
}
And in TaskGrid.xaml, the only template column is given here
<DataGridTemplateColumn Width="30">
<DataGridTemplateColumn.CellTemplate>
<ItemContainerTemplate>
<Button Name="btnMaster" Background="Transparent">
<Button.Template>
<ControlTemplate>
<Image Source="ArrowRight.png"/>
</ControlTemplate>
</Button.Template>
</Button>
</ItemContainerTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
I have to assign the click event like
button.click += new RoutedEvent(button_click);
And later use button_click event in the MainWindow.xaml.cs
Wait until the UserControl has been loaded. You could then get a reference to the DataGrid using the following helper method that searches for an element of a specific type recursively in the visual tree.
private static T GetChildOfType<T>(DependencyObject depObj) where T : DependencyObject
{
if (depObj == null)
return null;
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
{
var child = VisualTreeHelper.GetChild(depObj, i);
var result = (child as T) ?? GetChildOfType<T>(child);
if (result != null) return result;
}
return null;
}
The same way you can get a reference to a specific cell:
public static DataGridCell GetCell(DataGrid dataGrid, DataGridRow rowContainer, int column)
{
if (rowContainer != null)
{
System.Windows.Controls.Primitives.DataGridCellsPresenter presenter =
GetChildOfType<System.Windows.Controls.Primitives.DataGridCellsPresenter>(rowContainer);
if (presenter != null)
return presenter.ItemContainerGenerator.ContainerFromIndex(column) as DataGridCell;
}
return null;
}
Please refer to the following blog post for more information about this: https://blog.magnusmontin.net/2013/11/08/how-to-programmatically-select-and-focus-a-row-or-cell-in-a-datagrid-in-wpf/
Below is a full example for you. Note that the DataGrid may contain several rows and some of the rows may have been virtualized away. You will find more information about this on the link above.
public MainWindow()
{
InitializeComponent();
_TG = new TaskGrid();
_TD = new _1.TaskDetails();
_TM = new _1.TaskMaster();
myStack.Children.Add(_TG);
_AUC = ActiveUserControl.Grid;
_TG.Loaded += (s, e) =>
{
DataGrid dataGrid = GetChildOfType<DataGrid>(_TG);
if (dataGrid != null)
{
foreach (var item in dataGrid.Items)
{
DataGridRow dgr = dataGrid.ItemContainerGenerator.ContainerFromItem(item) as DataGridRow;
if (dgr != null)
{
DataGridCell cell = GetCell(dataGrid, dgr, 3); //<-- column index
if (cell != null)
{
Button button = GetChildOfType<Button>(cell);
if (button != null)
{
button.Click += new RoutedEvent(button_click);
}
}
}
}
}
};
}

How to get access to controls from CB when using hub - Windows Phone 8.1

I'm writing app in Windows Phone 8.1 and
I want to get access to controls from Code-Behind.
Normally everything works great but when I use hub I don't have access to fields from Code-Behind.
<Hub x:Name="RHub">
<HubSection>
<DataTemplate>
<Grid>
<TextBox x:Name="Test5"/>
</Grid>
</DataTemplate>
</HubSection>
<HubSection>
<DataTemplate>
<Grid>
</Grid>
</DataTemplate>
</HubSection>
</Hub>
And now in Code-Behind file is no such field like Test5, only RHub.
This is because the control is inside a DataTemplate. One easy way to get around this limitation is to hook into the Element Loaded-event. Here’s the XAML:
<HubSection Header="Trailers">
<DataTemplate>
<ListView x:Name="MovieTrailers" Loaded="MovieTrailers_Loaded">
</ListView>
</DataTemplate>
</HubSection>
And the code-behind:
private void MovieTrailers_Loaded(object sender, RoutedEventArgs e)
{
var listView = (ListView)sender;
listView.ItemsSource = trailers;
}
if you want to search any element in the list view you can use a method like:
public static DependencyObject FindChildControl<T>(DependencyObject control, string ctrlName)
{
int childNumber = VisualTreeHelper.GetChildrenCount(control);
for (int i = 0; i < childNumber; i++)
{
DependencyObject child = VisualTreeHelper.GetChild(control, i);
FrameworkElement fe = child as FrameworkElement;
// Not a framework element or is null
if (fe == null) return null;
if (child is T && fe.Name == ctrlName)
{
// Found the control so return
Debug.WriteLine("Achou");
return child;
}
else
{
// Not found it - search children
DependencyObject nextLevel = FindChildControl<T>(child, ctrlName);
if (nextLevel != null)
return nextLevel;
}
}
return null;
}
and search:
private void findRectangle(ListView listView)
{
Rectangle ret = this.FindChildControl<Rectangle>(listView, "ret1") as Rectangle;
if(ret != null)
{
ret.Fill = new SolidColorBrush(this.color);
}
}

VisualTreeHelper.GetChildrenCount return 0?

I'm using VisualTreeHelper.GetChildrenCount() to find child controls, but it always return 0.
Here is my code
<ScrollViewer x:Name="scrollViewerChannelsRecordTimeData">
<StackPanel x:Name="channelsRecordTimeData">
<ItemsControl x:Name="channelRecordTimeItems" ItemsSource="{Binding}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid x:Name="hoursLines">
//Some Controls here
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</ScrollViewer>
C# code:
channelRecordTimeItems.ItemContainerGenerator.StatusChanged += ChannelRecordTimeItemsStatusChangedEventHandler;
private void ChannelRecordTimeItemsStatusChangedEventHandler(Object sender, EventArgs e)
{
if (channelRecordTimeItems.ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated)
{
if (channelRecordTimeItems.HasItems)
{
DependencyObject dependencyObject = null;
Grid gridHighlightRecordData = null;
for (int i = 0; i < channelRecordTimeItems.Items.Count; i++)
{
dependencyObject = channelRecordTimeItems.ItemContainerGenerator.ContainerFromIndex(i); //dependencyObject != null
if (dependencyObject != null)
{
Grid hoursLines = FindElement.FindChild<Grid>(dependencyObject, "hoursLines"); //hoursLines = null
}
}
}
}
}
public static T FindChild<T>(DependencyObject parent, string childName)
where T : DependencyObject
{
// Confirm parent and childName are valid.
if (parent == null) return null;
T foundChild = null;
int childrenCount = VisualTreeHelper.GetChildrenCount(parent); //Return 0 here
for (int i = 0; i < childrenCount; i++)
{
var child = VisualTreeHelper.GetChild(parent, i);
// If the child is not of the request child type child
T childType = child as T;
if (childType == null)
{
// recursively drill down the tree
foundChild = FindChild<T>(child, childName);
// If the child is found, break so we do not overwrite the found child.
if (foundChild != null) break;
}
else if (!string.IsNullOrEmpty(childName))
{
var frameworkElement = child as FrameworkElement;
// If the child's name is set for search
if (frameworkElement != null && frameworkElement.Name == childName)
{
// if the child's name is of the request name
foundChild = (T)child;
break;
}
}
else
{
// child element found.
foundChild = (T)child;
break;
}
}
return foundChild;
}
VisualTreeHelper.GetChildrenCount() always return 0,
The code for constructing for items here
List<ChannelRecordTimeItemData> listChannelRecordTimeItemData = new List<ChannelRecordTimeItemData>();
for(int i = 0; i < 5; i++)
{
ChannelRecordTimeItemData item = new ChannelRecordTimeItemData();
listChannelRecordTimeItemData.Add(ChannelRecordTimeItemData);
}
channelRecordTimeItems.ItemsSource = listChannelRecordTimeItemData;
channelRecordTimeItems.Items.Refresh();
I have searched on forum and internet, but i can not solve it, someone can help me?
Many thanks!
T&T
The problem is that when the ItemContainerGenerator signals the ContainersGenerated status, the container (a ContentPresenter) has been created, but not yet loaded. Especially the data template has not yet been applied to the ContentPresenter, hence there is nothing in the visual tree.
You may get around this by adding a Loaded event handler when looping over the generated containers.
private void ItemContainerGeneratorStatusChanged(object sender, EventArgs e)
{
if (itemsControl.ItemContainerGenerator.Status
== GeneratorStatus.ContainersGenerated)
{
var containers = itemsControl.Items.Cast<object>().Select(
item => (FrameworkElement)itemsControl
.ItemContainerGenerator.ContainerFromItem(item));
foreach (var container in containers)
{
container.Loaded += ItemContainerLoaded;
}
}
}
private void ItemContainerLoaded(object sender, RoutedEventArgs e)
{
var element = (FrameworkElement)sender;
element.Loaded -= ItemContainerLoaded;
var grid = VisualTreeHelper.GetChild(element, 0) as Grid;
...
}
If your using Caliburn.Micro this will help you.
For your Viewmodel the base Class should be Screen then only VisualTreeHelper.GetChildrenCount() give no.of childs.(because Screen will Activate all childs
or
otherwise (FrameworkElement)YourParent).ApplyTemplate() method

How to access a specific item in a Listbox with DataTemplate?

I have a ListBox including an ItemTemplate with 2 StackPanels.
There is a TextBox in the second StackPanel i want to access.
(Change it's visibility to true and accept user input)
The trigger should be the SelectionChangedEvent. So, if a user clicks on an ListBoxItem, the TextBlock gets invisible and the TextBox gets visible.
XAML CODE:
<ListBox Grid.Row="1" Name="ContactListBox" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" ItemsSource="{Binding Contacts}" Margin="0,36,0,0" SelectionChanged="ContactListBox_SelectionChanged">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Margin="0,0,0,0">
<toolkit:ContextMenuService.ContextMenu>
<toolkit:ContextMenu>
<toolkit:MenuItem Header="Edit Contact" Click="ContactMenuItem_Click"/>
<toolkit:MenuItem Header="Delete Contact" Click="ContactMenuItem_Click"/>
</toolkit:ContextMenu>
</toolkit:ContextMenuService.ContextMenu>
<Grid>
<Rectangle Fill="{StaticResource PhoneAccentBrush}"
Width="72" Height="72">
<Rectangle.OpacityMask>
<ImageBrush ImageSource="/Images/defaultContactImage.png" Stretch="UniformToFill"/>
</Rectangle.OpacityMask>
</Rectangle>
</Grid>
<StackPanel>
<TextBox Text="{Binding Name}" TextWrapping="Wrap" Visibility="Collapsed"/>
<TextBlock Text="{Binding Name}" TextWrapping="Wrap" Style="{StaticResource PhoneTextExtraLargeStyle}" />
<TextBlock Text="{Binding Number}" TextWrapping="Wrap" Margin="12,-6,12,0" Style="{StaticResource PhoneTextAccentStyle}"/>
</StackPanel>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
I guess there are several ways to solve this, but nothing I tried worked.
My current approach looks like this
private void ContactListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
ListBoxItem listBoxItem = ContactListBox.SelectedItem as ListBoxItem;
DataTemplate listBoxTemplate = listBoxItem.ContentTemplate;
// How to access the DataTemplate content?
StackPanel outerStackPanel = listBoxTemplate.XXX as StackPanel;
StackPanel innerStackPanel = outerStackPanel.Children[1] as StackPanel;
TextBox nameBox = innerStackPanel.Children[0] as TextBox;
TextBlock nameBlock = innerStackPanel.Children[1] as TextBlock;
nameBox.Visibility = System.Windows.Visibility.Visible;
nameBlock.Visibility = System.Windows.Visibility.Collapsed;
}
Thank you for your help guys!! Finally i got it. Solved the problem with the VisualTreeHelper. What a great function ^^
private void ContactListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (ContactListBox.SelectedIndex == -1)
return;
currentSelectedListBoxItem = this.ContactListBox.ItemContainerGenerator.ContainerFromIndex(ContactListBox.SelectedIndex) as ListBoxItem;
if (currentSelectedListBoxItem == null)
return;
// Iterate whole listbox tree and search for this items
TextBox nameBox = helperClass.FindDescendant<TextBox>(currentSelectedListBoxItem);
TextBlock nameBlock = helperClass.FindDescendant<TextBlock>(currentSelectedListBoxItem);
helperFunction
public T FindDescendant<T>(DependencyObject obj) where T : DependencyObject
{
// Check if this object is the specified type
if (obj is T)
return obj as T;
// Check for children
int childrenCount = VisualTreeHelper.GetChildrenCount(obj);
if (childrenCount < 1)
return null;
// First check all the children
for (int i = 0; i < childrenCount; i++)
{
DependencyObject child = VisualTreeHelper.GetChild(obj, i);
if (child is T)
return child as T;
}
// Then check the childrens children
for (int i = 0; i < childrenCount; i++)
{
DependencyObject child = FindDescendant<T>(VisualTreeHelper.GetChild(obj, i));
if (child != null && child is T)
return child as T;
}
return null;
}
With this edited function you can also search for control by name (its converted from VB.NET):
public T FindDescendantByName<T>(DependencyObject obj, string objname) where T : DependencyObject
{
string controlneve = "";
Type tyype = obj.GetType();
if (tyype.GetProperty("Name") != null) {
PropertyInfo prop = tyype.GetProperty("Name");
controlneve = prop.GetValue((object)obj, null);
} else {
return null;
}
if (obj is T && objname.ToString().ToLower() == controlneve.ToString().ToLower()) {
return obj as T;
}
// Check for children
int childrenCount = VisualTreeHelper.GetChildrenCount(obj);
if (childrenCount < 1)
return null;
// First check all the children
for (int i = 0; i <= childrenCount - 1; i++) {
DependencyObject child = VisualTreeHelper.GetChild(obj, i);
if (child is T && objname.ToString().ToLower() == controlneve.ToString().ToLower()) {
return child as T;
}
}
// Then check the childrens children
for (int i = 0; i <= childrenCount - 1; i++) {
string checkobjname = objname;
DependencyObject child = FindDescendantByName<T>(VisualTreeHelper.GetChild(obj, i), objname);
if (child != null && child is T && objname.ToString().ToLower() == checkobjname.ToString().ToLower()) {
return child as T;
}
}
return null;
}
I can't give you a complete answer...
But I think you can use the VisualTreeHelper to iterate through the children of any control
http://blogs.msdn.com/b/kmahone/archive/2009/03/29/visualtreehelper.aspx
However, for the effect you are looking for, then I think using the SelectedItem Style might be a better solution - e.g. see this article - http://joshsmithonwpf.wordpress.com/2007/07/30/customizing-the-selected-item-in-a-listbox/
Use ItemContainerGenerator.
private void ContactListBox_SelectionChanged
(object sender, SelectionChangedEventArgs e)
{
if (e.AddedItems.Count == 1)
{
var container = (FrameworkElement)ContactListBox.ItemContainerGenerator.
ContainerFromItem(e.AddedItems[0]);
StackPanel sp = container.FindVisualChild<StackPanel>();
TextBox tbName = (TextBox) sp.FindName("tbName");
TextBlock lblName = (TextBlock)sp.FindName("lblName");
TextBlock lblNumber = (TextBlock)sp.FindName("lblNumber");
}
}
Since DataTemplate is a generic template that could be used many times in the code, there is no way to access it by name (x:Name="numberTextBox").
I solved similar problem to this by making a collection of Controls - while Listbox was populating I add Textbox control to the collection.
string text = myCollectionOfTextBoxes[listbox.SelectedIndex].Text;
Till I found a better soultion - Tag property. In your ListboxItem you bind Tag property to the name
Tag="{Binding Name}"
and the to access it
ListBoxItem listBoxItem = ContactListBox.SelectedItem as ListBoxItem;
string name = listBoxItem.Tag.ToString();

Categories