inside a behavior (connected to windows.interactivity) im trying to find a child of a Listview - specifically Gridviewcolumn- to be able to resize its width, the code is built using MVVM without code-behind.
the problem is simply that using the code below the Gridviewcolumn is not found, meanwhile other children of the Maingrid , f.e. a Button, it would be no problem (see the button example below).
any suggestions where the mistake comes from? thanks in advance!
// _parent is the main Grid of the Window
Button button = GetTemplateChildByName(_parent); // for the button its working and the value is returned
GridViewColumn gridviewcolumn = GetTemplateChildByNames(_parent);// for the GridViewColumn its not working and no value is returned
....
public Button GetTemplateChildByName(DependencyObject parent)
{
int childnum = VisualTreeHelper.GetChildrenCount(parent);
for (int i = 0; i < childnum; i++)
{
var child = VisualTreeHelper.GetChild(parent, i);
if (child is Button)
{
return child as Button;
}
else
{
var s = GetTemplateChildByName(child);
if (s != null)
return s;
}
}
return null;
}
public GridViewColumn GetTemplateChildByNames(DependencyObject parent)
{
int childnum = VisualTreeHelper.GetChildrenCount(parent);
for (int i = 0; i < childnum; i++)
{
var child = VisualTreeHelper.GetChild(parent, i);
if (child is GridViewColumn)
{
return child as GridViewColumn;
}
else
{
var s = GetTemplateChildByNames(child);
if (s != null)
return s;
}
}
return null;
}
Related
I come to write my first WPF Control. It contains a DataGrid filled with data. Change the font of some of the cells based by function that I call in the main form.Its here I really hit rock bottom.Anyone has ideas?
=========================================================================
I Looked in the topic above and still can't get my head around how to make it function that is dynamically called from the control in the main form. Here is the Code I am working on so far.
public void PaintCell(int row, int column)
{
DataGridRow rowContainer = GetRow(row);
if (rowContainer != null)
{
DataGridCellsPresenter presenter = GetVisualChild<DataGridCellsPresenter>(rowContainer);
DataGridCell cell = (DataGridCell)presenter.ItemContainerGenerator.ContainerFromIndex(column);
if (cell == null)
{
CalendarGridView.ScrollIntoView(rowContainer, CalendarGridView.Columns[column]);
cell = (DataGridCell)presenter.ItemContainerGenerator.ContainerFromIndex(column);
// I want to the text in the cell in red
}
}
}
private DataGridRow GetRow(int index)
{
DataGridRow row = (DataGridRow)CalendarGridView.ItemContainerGenerator.ContainerFromIndex(index);
if (row == null)
{
CalendarGridView.UpdateLayout();
CalendarGridView.ScrollIntoView(CalendarGridView.Items[index]);
row = (DataGridRow)CalendarGridView.ItemContainerGenerator.ContainerFromIndex(index);
}
return row;
}
public static T GetVisualChild<T>(Visual parent) where T : Visual
{
T child = default(T);
int numVisuals = VisualTreeHelper.GetChildrenCount(parent);
for (int i = 0; i < numVisuals; i++)
{
Visual v = (Visual)VisualTreeHelper.GetChild(parent, i);
child = v as T;
if (child == null)
{
child = GetVisualChild<T>(v);
}
if (child != null)
{
break;
}
}
return child;
}
}
Don't said is the best idea since it's my very first experience with WPF.
I am trying to get added user control in a list box, but couldn't find proper way to get it.
I am using below for finding user controls in binded listbox, but out of 10 items it could not find 3 or 4.
private T FindFirstElementInVisualTree<T>(DependencyObject parentElement) where T : DependencyObject
{
var count = System.Windows.Media.VisualTreeHelper.GetChildrenCount(parentElement);
if (count == 0)
return null;
for (int i = 0; i < count; i++)
{
var child = System.Windows.Media.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;
}
Code for button click to find user control.
private void Button_Click(object sender, RoutedEventArgs e)
{
if (!downloadClicked)
{
downloadClicked = true;
SuraWithProgressBar prg = null;
ListBoxItem item = null;
for (int rowIndex = 0; rowIndex < lsbQuranData.Items.Count; rowIndex++)
{
item = this.lsbQuranData.ItemContainerGenerator.ContainerFromIndex(rowIndex) as ListBoxItem;
if (item != null)
{
prg = FindFirstElementInVisualTree<SuraWithProgressBar>(item);
if (prg != null)
{
//Do Somthing
prg.addButtonClickInterface(this);
}
}
}
}
else
MessageBox.Show("Please wait, downloading...");
}
As I mentioned out of 10, It cannot find 3-4 items. I am looking for proper way to find my user control inside listbox.
Thanks!
After a lot of headache I find out the solution in two below links:
WP7 - VisualTreeHelper to loop through all ListBox Items
http://msdn.microsoft.com/en-us/library/windows/apps/jj709920.aspx
Add template to your listbox and change SerializeStackPanel to StackPanel and the problem is solved. Please make sure to add this to ItemTemplate section.
I've managed to bind my data to a datagrid and listbox via ObservableCollection. I've also managed to get the listbox items from the first column of my datagrid using the below code. Can anyone tell me how to access the listboxes within the second and third columns as I'm only getting the first column containing my listboxes? (I thought my FindVisualChild merthod would have pulled ALL listboxes from the datagrid irrespective of which column they were in and I could have separated them via a change in tag name or something - I was wrong I guess...)
private void button1_Click(object sender, RoutedEventArgs e)
{
// Update Job Step Grid ListBox
for (int i = 0; i < dataGridJobSteps.Items.Count; i++)
{
DependencyObject obj = dataGridJobSteps.ItemContainerGenerator.ContainerFromIndex(i);
ListBox _listBox = FindVisualChild<ListBox>(obj);
var selectedItems = _listBox.Items;
foreach (var selectedItem in selectedItems)
{
MessageBox.Show(selectedItem.ToString());
}
}
}
public static childItem FindVisualChild<childItem>(DependencyObject obj) where childItem : DependencyObject
{
// Search immediate children
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
{
DependencyObject child = VisualTreeHelper.GetChild(obj, i);
if (child is childItem)
return (childItem)child;
else
{
childItem childOfChild = FindVisualChild<childItem>(child);
if (childOfChild != null)
return childOfChild;
}
}
return null;
}
Your FindVisualChild method only returns the first ListBox found, if you want to find all ListBoxes that are in the DataGrid you will need to modify the method to return IEnumerable<childItem>
public static IEnumerable<childItem> FindVisualChildren<childItem>(DependencyObject obj) where childItem : DependencyObject
{
// Search immediate children
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
{
DependencyObject child = VisualTreeHelper.GetChild(obj, i);
if (child is childItem)
yield return (childItem)child;
else
{
var childOfChild = FindVisualChildren<childItem>(child);
if (childOfChild != null)
{
foreach(var item in childOfChild )
{
yield return item;
}
}
}
}
return null;
}
Note: However if you follow the MVVM pattern in WPF this will be a lot easier than iterating visual elements
I need to access the nodes of a TreeView as a plain list (as if all the nodes where expanded) to be able to do multiselection pressing the Shift key. Is there a way to accomplish this?
Thanks
Here is a method that will retrieve all the TreeViewItems in a TreeView. Please be aware that this is an extremely expensive method to run, as it will have to expand all TreeViewItems nodes and perform an updateLayout each time. As the TreeViewItems are only created when expanding the parent node, there is no other way to do that.
If you only need the list of the nodes that are already opened, you can remove the code that expand them, it will then be much cheaper.
Maybe you should try to find another way to manage multiselection. Having said that, here is the method :
public static List<TreeViewItem> FindTreeViewItems(this Visual #this)
{
if (#this == null)
return null;
var result = new List<TreeViewItem>();
var frameworkElement = #this as FrameworkElement;
if (frameworkElement != null)
{
frameworkElement.ApplyTemplate();
}
Visual child = null;
for (int i = 0, count = VisualTreeHelper.GetChildrenCount(#this); i < count; i++)
{
child = VisualTreeHelper.GetChild(#this, i) as Visual;
var treeViewItem = child as TreeViewItem;
if (treeViewItem != null)
{
result.Add(treeViewItem);
if (!treeViewItem.IsExpanded)
{
treeViewItem.IsExpanded = true;
treeViewItem.UpdateLayout();
}
}
foreach (var childTreeViewItem in FindTreeViewItems(child))
{
result.Add(childTreeViewItem);
}
}
return result;
}
Here is what you asked;
private static TreeViewItem[] getTreeViewItems(TreeView treeView)
{
List<TreeViewItem> returnItems = new List<TreeViewItem>();
for (int x = 0; x < treeView.Items.Count; x++)
{
returnItems.AddRange(getTreeViewItems((TreeViewItem)treeView.Items[x]));
}
return returnItems.ToArray();
}
private static TreeViewItem[] getTreeViewItems(TreeViewItem currentTreeViewItem)
{
List<TreeViewItem> returnItems = new List<TreeViewItem>();
returnItems.Add(currentTreeViewItem);
for (int x = 0; x < currentTreeViewItem.Items.Count; x++)
{
returnItems.AddRange(getTreeViewItems((TreeViewItem)currentTreeViewItem.Items[x]));
}
return returnItems.ToArray();
}
Call with your control as the first parameter e.g.;
getTreeViewItems(treeView1);
Can you please tell , how to get and set the value of a cell in WPF DataGrid by providing columnidnex and row index
Thanks
This is not as easy as it should be in WPF, it is all about selecting visual children (the WPF 'Visual' object type). This blog post explains quite well how to accomplish it. Google it and you will probably find a lot more.
// Getting Data from Grid Cell
string cellContent = ((TextBox)(GetCell(3).Content)).Text; //As I want the value of 3 column
public DataGridCell GetCell(int column)
{
DataGridRow rowContainer = GetRow();
if (rowContainer != null)
{
DataGridCellsPresenter presenter = GetVisualChild<DataGridCellsPresenter>(rowContainer);
// Try to get the cell but it may possibly be virtualized.
DataGridCell cell = (DataGridCell)presenter.ItemContainerGenerator.ContainerFromIndex(column);
if (cell == null)
{
// Now try to bring into view and retreive the cell.
customDataGrid.UCdataGridView.ScrollIntoView(rowContainer, customDataGrid.UCdataGridView.Columns[column]);
cell = (DataGridCell)presenter.ItemContainerGenerator.ContainerFromIndex(column);
}
return cell;
}
return null;
}
public DataGridRow GetRow()
{
DataGridRow row = (DataGridRow)customDataGrid.UCdataGridView.ItemContainerGenerator.ContainerFromIndex(_currentRowIndex);
if (row == null)
{
// May be virtualized, bring into view and try again.
customDataGrid.UCdataGridView.UpdateLayout();
customDataGrid.UCdataGridView.ScrollIntoView(customDataGrid.UCdataGridView.Items[_currentRowIndex]);
row = (DataGridRow)customDataGrid.UCdataGridView.ItemContainerGenerator.ContainerFromIndex(_currentRowIndex);
}
return row;
}
public static T GetVisualChild<T>(Visual parent) where T : Visual
{
T child = default(T);
int numVisuals = VisualTreeHelper.GetChildrenCount(parent);
for (int i = 0; i < numVisuals; i++)
{
Visual v = (Visual)VisualTreeHelper.GetChild(parent, i);
child = v as T;
if (child == null)
{
child = GetVisualChild<T>(v);
}
if (child != null)
{
break;
}
}
return child;
}
// Setting Data to Grid Cell
if (GetCell(3).Content is TextBlock) // if grid cell is not editable
{
((TextBlock)(GetCell(3).Content)).Text = "sometext";
}
else // TextBox - if grid cell is editable
{
((TextBox)(GetCell(3).Content)).Text = "sometext";
}