I am trying to find child element from Listbox. Listbox contains Itemtemplate. Here is my design.
I have created UserControl. In that I have added ListBox.
I am showing this control as pop up. Here is code for pop up
GlobalSettings.popup = new Popup();
//GlobalSettings.popup.VerticalOffset = 50;
FilesListControl popupcontrol = new FilesListControl();
popupcontrol.Height = 480;
popupcontrol.Width = 480;
GlobalSettings.popup.Child = popupcontrol;
popupcontrol.fileListbox.ItemsSource = filesList;
LayoutRoot.IsHitTestVisible = false;
GlobalSettings.popup.IsOpen = true;
//Here I need to create checkbox. so thats why I need to find the child elemnt of listbox
popupcontrol.btnDone.Click += (s, args) =>
{
};
Here code from FilesListControl
<ScrollViewer Grid.Row="0" HorizontalScrollBarVisibility="Auto">
<ListBox Name="fileListbox">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<CheckBox Name="chkFile" CommandParameter="{Binding value}" Content="{Binding Key}" Click="chkFile_Click" FontFamily="Segoe WP SemiLight"></CheckBox>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</ScrollViewer>
I want to find the CheckBox i.e. chkFile. Here is my code
ListBoxItem item = popupcontrol.fileListbox.ItemContainerGenerator.ContainerFromIndex(1) as ListBoxItem;
CheckBox chk = FindFirstElementInVisualTree<CheckBox>(item);
private T FindFirstElementInVisualTree<T>(DependencyObject parentElement) where T : DependencyObject
{
var count = VisualTreeHelper.GetChildrenCount(parentElement);
if (count == 0)
return null;
for (int i = 0; i < count; i++)
{
var child = VisualTreeHelper.GetChild(parentElement, i);
if (child != null && child is T)
{
return (T)child;
}
else
{
var result = FindFirstElementInVisualTree<T>(child);
if (result != null)
return result;
}
}
return null;
}
But nothing is getting. What I did wrong? How can I access CheckBox Click event?
Related
I am using interactive data display lib, and I want to generate my charts dynamically. Unfortunatelly I can't access one of the StackPanels by its name:
<Grid>
<d3:Chart Name="plotter">
<d3:Chart.Title>
<TextBlock HorizontalAlignment="Center" FontSize="18" Margin="0,5,0,5">Line graph legend sample</TextBlock>
</d3:Chart.Title>
<d3:Chart.LegendContent>
<d3:LegendItemsPanel>
<d3:LegendItemsPanel.Resources>
<DataTemplate x:Key="InteractiveDataDisplay.WPF.LineGraph">
<StackPanel Name="chartPanel" Orientation="Horizontal">
</StackPanel>
</DataTemplate>
</d3:LegendItemsPanel.Resources>
</d3:LegendItemsPanel>
</d3:Chart.LegendContent>
<Grid Name="lines"/>
</d3:Chart>
</Grid>
And when I am trying to access it by name (chartPanel.method()) it seems that it doesnt exist.
Implement this in your Code
private 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
return child;
}
else
{
// Not found it - search children
DependencyObject nextLevel = FindChildControl<T>(child, ctrlName);
if (nextLevel != null)
return nextLevel;
}
}
return null;
After that u can search the stackpanel with this Method:
StackPanel chartPanel= FindChildControl<StackPanel>(plotter, "chartPanel") as StackPanel;
now you can edit your Stackpanel.
I have a C# WPF application that contains a user control:
<UserControl
x:Name="payrollEntryControl"
x:Class="MyNamespace.PayrollEntryControl"
[...]
>
[...]
</UserControl>
Within the user control, I have a Telerik RadDataForm:
<telerik:RadDataForm
x:Name="payrollAddForm"
CurrentItem="[...]"
EditTemplate="{StaticResource myEditTemplate}"
/>
The template contains a Telerik RadGridView and a Button:
<telerik:RadGridView Grid.Row="0" Grid.Column="0"
x:Name="workGridView"
[...]
ItemsSource="{Binding [...]}"
>
<telerik:RadGridView.Columns>
[...]
</telerik:RadGridView.Columns>
</telerik:RadGridView>
<Button Grid.Row="1" Grid.Column="0"
Command="{Binding addWorkCommand, ElementName=payrollEntryControl}"
>
Add
</Button>
I want the command to do is call BeginInsert() on workGridView. But I can't seem to get access to workGridView.
My command, so far:
private DelegateCommand addWorkCommand_ = null;
public DelegateCommand addWorkCommand
{
get
{
if (this.addWorkCommand_ == null)
{
this.addWorkCommand_ = new DelegateCommand(
o => addWork(o)
);
}
return this.addWorkCommand_;
}
}
private void addWork(object o)
{
var addForm = this.payrollAddForm;
var editTemplate = addForm.EditTemplate;
var workGrid = editTemplate.FindName("workGridView", addForm);
}
My problem? When I make the call to editTemplate.FindName(), I get an exception:
This operation is valid only on elements that have this template applied.
I don't understand. I'm getting the template from the form. How can it not be applied?
Peter Duniho's comment pointed me to this answer, which addressed my problem.
This method will help you:
public T FindElementByName<T>(FrameworkElement element, string sChildName) where T : FrameworkElement
{
T childElement = null;
var nChildCount = VisualTreeHelper.GetChildrenCount(element);
for (int i = 0; i < nChildCount; i++)
{
FrameworkElement child = VisualTreeHelper.GetChild(element, i) as FrameworkElement;
if (child == null)
continue;
if (child is T && child.Name.Equals(sChildName))
{
childElement = (T)child;
break;
}
childElement = FindElementByName<T>(child, sChildName);
if (childElement != null)
break;
}
return childElement;
}
And, how I use it, just add button, and on button Click:
private void Button_OnClick(object sender, RoutedEventArgs e)
{
var element = FindElementByName<ComboBox>(ccBloodGroup, "cbBloodGroup");
}
[1]: https://stackoverflow.com/a/19907800/243563
An alternative is to pass the workGridView as a CommandParameter:
<Button Grid.Row="1" Grid.Column="0"
CommandParameter="{Binding ElementName=workGridView}"
Command="{Binding addWorkCommand}" >
....
private void addWork(object o)
{
RadGridView grid = o as RadGridView;
grid.BeginInsert();
}
I have code like this
<ListBox x:Name="filterListBox" Height="60">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"
VirtualizingStackPanel.VirtualizationMode="Standard"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel x:Name="TargetPanel">
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.Background>
<SolidColorBrush />
</ListBox.Background>
</ListBox>
and i get first listbox item with this
object item = filterListBox.ItemContainerGenerator.ContainerFromIndex(0);
ListBoxItem lbi = item as ListBoxItem;
Now I need to get this stackpanel called "TargetPanel" but I don't know how. Can you please help.
There's not a built in way to do this with a simple method call unfortunately. However, it's easy enough. With a few modifications to this example, you can get a particular child of the DataTemplate by name:
// the call
var item = filterListBox.ItemContainerGenerator
.ContainerFromIndex(0) as ListBoxItem;
var sp = FindVisualChild<StackPanel>(item, "TargetPanel");
// the variable sp should be set to the TargetPanel for the item now
The code you'll need to add somewhere (it could be in a "helper" class):
using System.Windows.Media; // for VisualTreeHelper
private static TChildItem FindVisualChild<TChildItem>(DependencyObject obj,
string matchName = "") where TChildItem : DependencyObject
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
{
var child = VisualTreeHelper.GetChild(obj, i);
if (child != null && child is TChildItem)
{
// match by name
var childName = child.GetValue(FrameworkElement.NameProperty) as string;
if (!string.IsNullOrWhiteSpace(matchName))
{
if (matchName == childName)
{
return (TChildItem)child;
}
}
else
{
return (TChildItem)child;
}
}
else
{
var childOfChild = FindVisualChild<TChildItem>(child, matchName);
if (childOfChild != null)
{
return childOfChild;
}
}
}
return null;
}
I am working on a WPF application where I have to bind three different ListViews grouped inside a GroupBox container.
This is the XAML for the display:
<GroupBox Header="Zone2 Sensors" Height="250" Name="grpBoxZone2" Width="380" Margin="25,248,90,660" Grid.Column="5" Grid.ColumnSpan="2" Foreground="#FF1E5EE6">
<Grid Height="250" Width="375" MinHeight="250">
<Label Content="Strain" Width="40" Name="labelZone2S" Foreground="#FF1E5EE6" Margin="44,1,291,227" />
<Label Content="Accelerometer" Width="79" Name="labelZone2A" Foreground="#FF1E5EE6" Margin="132,1,164,227" />
<Label Content="Tilt" Name="labelZone2T" Foreground="#FF1E5EE6" Margin="264,1,82,227" />
<ListView Margin="25,42,268,49" Name="lst2" ItemsSource="{Binding}" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch" BorderThickness="0" SelectionChanged="lst2_SelectionChanged">
<ListView.ItemTemplate>
<DataTemplate>
<Border Padding="5" Background="#FF83A2DA" BorderThickness="1" BorderBrush="Black">
<CheckBox Name="CheckBoxs1" IsChecked="{Binding IsSelected}" Click="CheckBoxs1_Click" Unchecked="CheckBoxs1_Unchecked">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding ObjectData}"></TextBlock>
</StackPanel>
</CheckBox>
</Border>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<ListView Margin="134,42,159,111" Name="lstZone2A" ItemsSource="{Binding}" HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch" BorderThickness="0" SelectionChanged="lstZone2A_SelectionChanged">
<ListView.ItemTemplate>
<DataTemplate>
<Border Padding="5" Background="#FF83A2DA" BorderThickness="1" BorderBrush="Black">
<CheckBox Name="ChkZone2A" IsChecked="{Binding IsSelected}" Checked="ChkZone2A_Checked" Unchecked="ChkZone2A_Unchecked">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding ObjectData}"></TextBlock>
</StackPanel>
</CheckBox>
</Border>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<ListView Margin="249,42,44,156" Name="lstZone2T" ItemsSource="{Binding}" HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch" BorderThickness="0" SelectionChanged="lstZone2T_SelectionChanged">
<ListView.ItemTemplate>
<DataTemplate>
<Border Padding="5" Background="#FF83A2DA" BorderThickness="1" BorderBrush="Black">
<CheckBox Name="ChkZone2T" IsChecked="{Binding IsSelected}" Checked="ChkZone2T_Checked" Unchecked="ChkZone2T_Unchecked">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding ObjectData}"></TextBlock>
</StackPanel>
</CheckBox>
</Border>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<CheckBox Content="Select ALL Sensors" Margin="14,21,248,213" Name="chkZone2SelectAll" Checked="chkZone2SelectAll_Checked" Unchecked="chkZone2SelectAll_Unchecked" />
</Grid>
</GroupBox>
This is the C# code which I use to check and uncheck items:
private void chkZone2SelectAll_Checked(object sender, RoutedEventArgs e)
{
try
{
StringBuilder sb = new StringBuilder();
for (int i = 0; i < lst2.Items.Count; i++)
{
// Get a all list items from listbox
ListBoxItem ListBoxItemObj = (ListBoxItem)lst2.ItemContainerGenerator.ContainerFromItem(lst2.Items[i]);
//bool check = ListBoxItemObj.HasContent;
// find a ContentPresenter of that list item.. [Call FindVisualChild Method]
ContentPresenter ContentPresenterObj = FindVisualChild<ContentPresenter>(ListBoxItemObj);
// call FindName on the DataTemplate of that ContentPresenter
DataTemplate DataTemplateObj = ContentPresenterObj.ContentTemplate;
CheckBox Chk = (CheckBox)DataTemplateObj.FindName("CheckBoxs1", ContentPresenterObj);
Chk.IsChecked = true;
}
for (int i = 0; i < lstZone2A.Items.Count; i++)
{
// Get a all list items from listbox
ListBoxItem ListBoxItemObj = (ListBoxItem)lstZone2A.ItemContainerGenerator.ContainerFromItem(lstZone2A.Items[i]);
// find a ContentPresenter of that list item.. [Call FindVisualChild Method]
ContentPresenter ContentPresenterObj = FindVisualChild<ContentPresenter>(ListBoxItemObj);
// call FindName on the DataTemplate of that ContentPresenter
DataTemplate DataTemplateObj = ContentPresenterObj.ContentTemplate;
CheckBox Chk = (CheckBox)DataTemplateObj.FindName("ChkZone2A", ContentPresenterObj);
Chk.IsChecked = true;
}
for (int i = 0; i < lstZone2T.Items.Count; i++)
{
// Get a all list items from listbox
ListBoxItem ListBoxItemObj = (ListBoxItem)lstZone2T.ItemContainerGenerator.ContainerFromItem(lstZone2T.Items[i]);
// find a ContentPresenter of that list item.. [Call FindVisualChild Method]
ContentPresenter ContentPresenterObj = FindVisualChild<ContentPresenter>(ListBoxItemObj);
// call FindName on the DataTemplate of that ContentPresenter
DataTemplate DataTemplateObj = ContentPresenterObj.ContentTemplate;
CheckBox Chk = (CheckBox)DataTemplateObj.FindName("ChkZone2T", ContentPresenterObj);
Chk.IsChecked = true;
}
foreach (TripInfo cbObject in lst2.Items)
{
cbObject.IsSelected = true;
}
foreach (TripInfo cbObject in lstZone2A.Items)
{
cbObject.IsSelected = true;
}
foreach (TripInfo cbObject in lstZone2T.Items)
{
cbObject.IsSelected = true;
}
foreach (TripInfo cbObject in lst2.Items)
{
if (cbObject.IsSelected)
{
if (SelectedSensser != null)
{
if (SelectedSensser.Contains(cbObject.ObjectData.ToString())) { }
else
{
sb.AppendFormat("{0}, ", cbObject.ObjectData.ToString());
}
}
else
{
sb.AppendFormat("{0}, ", cbObject.ObjectData.ToString());
}
SelectedSensser += sb.ToString().Trim();
sb.Clear();
}
}
foreach (TripInfo cbObject in lstZone2A.Items)
{
if (cbObject.IsSelected)
{
if (SelectedSensser != null)
{
if (SelectedSensser.Contains(cbObject.ObjectData.ToString())) { }
else
{
sb.AppendFormat("{0}, ", cbObject.ObjectData.ToString());
}
}
else
{
sb.AppendFormat("{0}, ", cbObject.ObjectData.ToString());
}
SelectedSensser += sb.ToString().Trim();
sb.Clear();
}
}
foreach (TripInfo cbObject in lstZone2T.Items)
{
if (cbObject.IsSelected)
{
if (SelectedSensser != null)
{
if (SelectedSensser.Contains(cbObject.ObjectData.ToString())) { }
else
{
sb.AppendFormat("{0}, ", cbObject.ObjectData.ToString());
}
}
else
{
sb.AppendFormat("{0}, ", cbObject.ObjectData.ToString());
}
SelectedSensser += sb.ToString().Trim();
sb.Clear();
}
}
}
catch (Exception ex) { throw ex; }
}
private ChildControl FindVisualChild<ChildControl>(DependencyObject DependencyObj) where ChildControl : DependencyObject
{
int count = VisualTreeHelper.GetChildrenCount(DependencyObj);
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;
}
public class TripInfo
{
public TripInfo(string objectData) { ObjectData = objectData; }
public TripInfo(bool isSelected, string objectData)
{
IsSelected = isSelected;
ObjectData = objectData;
}
public Boolean IsSelected
{ get; set; }
public String ObjectData
{ get; set; }
}
However, this gives me the following error when it reaches the 8th index, but the ListItems count shows 10 elements:
Value cannot be null.
Parameter name: element
Thanks for all who just visit this Question.I found solution for this.This is something tricky
:-).Listitems which are coming under vertical scroll or you can say that those items which are not visible didn't found by FindVisualChild class.When i increase the height of the listview and all items found.
I see you are using Binding and Templates to display your data.
You could easily invoke a ICommand on your viewmodel and set all items to IsSelected=True. If you've implemented INotifyPropertyChanged correctly it should work, and you won't need the code-behind/FindVisual stuff anymore.
I found a way to template the embedding of controls within the column headings of a GridView. However I do not know how to find the controls using my code behind to fill them up with items. I have figured out how to respond to an event raised from the embedded control and determine which column it was in. Otherwise I don't know how to get a reference to the embedded ComboBoxes.
Some code to give you an idea:
<Page.Resources>
<DataTemplate x:Key="ComboHeaderTemplate">
<DockPanel>
<ComboBox Name="columnHeading" />
</DockPanel>
</DataTemplate>
</Page.Resources>
And in the code-behind:
GridView grdView = new GridView();
for (int column = 1; column <= context.data.GetLength(1); column++)
{
GridViewColumn gvc = new GridViewColumn();
gvc.DisplayMemberBinding = new Binding(column.ToString());
gvc.Header = column.ToString();
gvc.Width = 120;
gvc.HeaderTemplate = (DataTemplate)this.Resources["ComboHeaderTemplate"];
grdView.Columns.Add(gvc);
}
ListView1.View = grdView;
ListView1.ItemsSource = dt.DefaultView;
If every ComboBox had the same list of items to choose from using data binding that would be fine as long as I could select unique values for each column.
You could use the VisualTreeHelper to retrieve the combo-box:
Create a helper method to find the combo box on the GridViewColumn:
public T FindVisualChild<T>(DependencyObject depObj) where T : DependencyObject
{
if (depObj != null)
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
{
DependencyObject child = VisualTreeHelper.GetChild(depObj, i);
if (child != null && child is T)
{
return (T)child;
}
T childItem = FindVisualChild<T>(child);
if (childItem != null) return childItem;
}
}
return null;
}
To get a reference to the combo-box then do something like the following:
ComboBox cb = FindVisualChild<ComboBox>(gvc);
Hopefully this is what you are looking for?
Here's what I ended up with.
XAML:
<DataTemplate x:Key="ComboHeaderTemplate">
<DockPanel>
<ComboBox Name="columnHeading" Loaded="columnHeadingLoaded" SelectionChanged="columnHeadingSelectedChanged" Width="Auto" />
</DockPanel>
</DataTemplate>
Code behind:
private void columnHeadingLoaded(object sender, RoutedEventArgs e)
{
((ComboBox)sender).ItemsSource = myList;
((ComboBox)sender).SelectedIndex = 0;
}
// My columns are named "1", "2" etc
private void columnHeadingSelectedChanged(object sender, SelectionChangedEventArgs e)
{
int columnIndex = int.Parse(((ComboBox)sender).DataContext.ToString()) - 1;
if (((ComboBox)sender).SelectedIndex == 0)
{
this.Headings[columnIndex] = null;
}
else
{
this.Headings[columnIndex] = ((ComboBox)sender).SelectedValue.ToString();
}
}
Thought I should use Data Binding in the XAML but this was easier.
You can try this:
var cbx= gvc.HeaderTemplate.LoadContent() as ComboBox;
gvc is GridViewColumn