WPF DataGrid actual ColumnHeaderHeight - c#

When I set a WPF DataGrid's ColumnHeaderHeight to Auto (double.NaN), how do I get the actual rendered height of the column header?
I cannot seem to find the property in the DataGrid class.

You could get hold of it by searching through the visual tree for the DataGridColumnHeadersPresenter and reading its ActualHeight property.
var headersPresenter = FindVisualChild<DataGridColumnHeadersPresenter>(dataGrid);
double actualHeight = headersPresenter.ActualHeight;
Here's the FindVisualChild method. It could be implemented as an extension method as well.
public static T FindVisualChild<T>(DependencyObject current) where T : DependencyObject
{
if (current == null) return null;
int childrenCount = VisualTreeHelper.GetChildrenCount(current);
for (int i = 0; i < childrenCount ; i++)
{
DependencyObject child = VisualTreeHelper.GetChild(current, i);
if (child is T) return (T)child;
T result = FindVisualChild<T>(child);
if (result != null) return result;
}
return null;
}

When I remember correctly, the property is an attached property - meaning the real value should be found on a DataGridColumn.
There is a separate class for the DataGridColumnHeader with the same name - see: http://msdn.microsoft.com/de-de/library/system.windows.controls.primitives.datagridcolumnheader(v=vs.110).aspx
This class can probably be gained through a single DataGridColumns "Header" property.
See: http://msdn.microsoft.com/en-us/library/system.windows.controls.datagridcolumn.header(v=vs.110).aspx
So I would grab the first column of the grid, convert it's Header property to DataGridColumnHeaderand read its actualheight attribute.
Please make sure to guard for the case that the Header attribute or ActualHeight is null - this can happen when the grid is build / refreshing or closing. I dimly remeber that there should be an event which is fired when the grid is rendered completely.

Related

How to determine the type of items in classes derived from ItemsControl

I am implementing an Attached Property for the ItemsControl.
Faced with such a task that I cannot solve.
I climb from the UI element in the ItemTemplate along the visual tree to the ItemsControl. There is no problem with that.
But I also need to define the type used to generate items in the ItemsControl.
And this type is also different in different classes derived from ItemsControl.
Let's say for ListBox can apply the following code
public static bool GetIndexOn(FrameworkElement element)
{
int? index = (int?)element.GetValue(IndexProperty);
if (index == null)
{
FrameworkElement parent = element;
// Search ListBoxItem
// But I need to find any type used to generate Item
while (!(parent is System.Windows.Controls.ListBoxItem || parent == null))
parent = VisualTreeHelper.GetParent(parent) as FrameworkElement;
if (parent == null)
return false;
// Saving the ListBoxItem
System.Windows.Controls.ListBoxItem listBoxItem = (System.Windows.Controls.ListBoxItem)parent;
// Search ItemsControl
while (!(parent is ItemsControl || parent == null))
parent = VisualTreeHelper.GetParent(parent) as FrameworkElement;
if (parent == null)
return false;
// Saving the ListBox
ItemsControl listBox = (ItemsControl)parent;
// Retrieving and storing index of ListBoxItem in ListBox
index = listBox.ItemContainerGenerator.IndexFromContainer(listBoxItem);
element.SetValue(IndexPropertyKey, index);
}
return false;
}

Finding a cell in devexpress datagrid

I'm new to DevExpress GridControl.
I need to find a particular cell in the grid and then do something with it's value.
How do I go about this please?
In the grid's Loaded method, I tried using myGrid.FindRowByValue("ProductType","ABC"), but always gives a negative number.
Thanks.
Here is code you can try
for (int i = 0; i < gridView1.DataRowCount; i++) {
object b = gridView1.GetRowCellValue(i, "FieldName");
if (b != null && b.Equals(<someValue>)){
gridView1.FocusedRowHandle = i;
return;
}
}
you can go to this link for more details.
https://www.devexpress.com/Support/Center/Question/Details/Q132599/get-row-by-cell-value
Unlike XtraGrid, the DXGrid for WPF does not provide the DataRowCount property - that is why we suggested checking the GridControl's ItemsSource. On the other hand, our grid has the VisibleRowCount property, which will be useful in some scenarios.
To accomplish this task, iterate through visible grid rows manually as shown below.
void MoveFocusToLast(GridControl grid, string fieldName, object value) {
for (int i = grid.VisibleRowCount - 1; i >= 0; i--) {
var handle = grid.GetRowHandleByVisibleIndex(i);
var currentValue = grid.GetCellValue(handle, fieldName);
if (currentValue != null && currentValue.Equals(value)) {
grid.View.FocusedRowHandle = handle;
return;
}
}
}
Grid also provides the FindRowByValue method, which allows you to
find a row by a specific cell value. This method returns the handle of
the corresponding row, and you can make that row visible by setting
the FocusedRowHandle property or calling ScrollIntoView. I
have prepared a sample demonstrating this approach.
See Also:
Traversing Rows
Find Row
Get RowHandle from a cell value

Read each cell values in WPF gridview

I have a datagridview in wpf called datagrid1. I need to read value in each cells in datagrid. I know how to do it in windows form
string result = datagrid1.Rows[0].Cells[1].Value.ToString();
How do this in WPF?
There is no easy way to do this in WPF, however this tutorial can be of use to you.
Edit:
First of all I totally agree with the comment Nitin Joshi mentioned above.
Second, According to this answer The WPF datagrid was built to bind to something like a DataTable. The majority of the time, you will modify the DataTable, and the Rows/Columns within the DataTable that is bound to the DataGrid, not the DataGrid it self so you don't need to use something like this datagrid1.Rows[0].Cells[1].Value. But if you still insist on getting the value that way, here is a solution :
Second EDIT:
Since you asked only for a way to read call value, I'll make my answer shorter but also a little more concrete:
GetCellValue method returns a string value representing cell content of a given DataGrid by column/row indices:
I wrote this method assuming column types are either TextBox, TextBlock or ComboBox. Other Types could be handled the same way.
public string GetCellValue(DataGrid datagrid, int row, int column)
{
var cellInfo = new DataGridCellInfo(
datagrid.Items[row], dataGrid.Columns[column]);
DataGridCell cell = null;
var cellContent = cellInfo.Column.GetCellContent(cellInfo.Item);
if (cellContent != null)
cell = (DataGridCell)cellContent.Parent;
if (cell == null) return string.Empty;
// if DataGridTextColumn / DataGridComboBoxColumn is used
// or AutoGeneratedColumns is True
if (cell.Content is TextBlock)
return ((TextBlock)cell.Content).Text;
else if (cell.Content is ComboBox)
return ((ComboBox)cell.Content).Text;
// if DataGridTemplateColumn is used
// assuming cells are either TextBox, TextBlock or ComboBox. Other Types could be handled the same way.
else
{
var txtPresenter = FindVisualChild<TextBox>((ContentPresenter)cell.Content);
if (txtPresenter != null) return txtPresenter.Text;
var txbPresenter = FindVisualChild<TextBlock>((ContentPresenter)cell.Content);
if (txbPresenter != null) return txbPresenter.Text;
var cmbPresenter = FindVisualChild<ComboBox>((ContentPresenter)cell.Content);
if (cmbPresenter != null) return cmbPresenter.Text;
}
return string.Empty;
}
public static T FindVisualChild<T>(DependencyObject obj) where T : DependencyObject
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
{
DependencyObject child = VisualTreeHelper.GetChild(obj, i);
if (child != null && child is T)
return (T)child;
else
{
T childOfChild = FindVisualChild<T>(child);
if (childOfChild != null)
return childOfChild;
}
}
return null;
}
Then calling string result = GetCellValue(dataGrid, 2, 1); (e.g. from a Button click event), will return the value of dataGrid[2,1].
*Note:
The SelectionUnit of the DataGrid must be set to Cell.
The DataGridmust fully generated otherwise ItemContainerGenerator returns null.
GetCellValue method works for a few UIElements considered to be more common to be used as DataGridColumn Types.

How i can get the value of cell in datagrid in wpf?

I have a datagrid, with a number of rows. I want to get the value of cell[0].
In the window form I was using this code:
for (int i = 0; i < dataGridView1.Rows.Count; i++)
{
if (dataGridView1.Rows[i].Cells[0].Value == null)
{
//do somthing
}
}
The problem is, I do not know how to get the value of the cell, as this code does not work in WPF.
Like I mentioned in the comments, you need to read more on WPF and bindings that how it works because value which you are trying to get from UI can easily be fetched from underlying data object.
Say you have binded dataGrid to some list ObservableCollection<MyObject> and first column of dataGrid is binded to property Name. You can get value for first cell simply like this:
for (int i = 0; i < dataGridView1.Items.Count; i++)
{
string value = ((MyObject)dataGridView1.Items[0]).Name;
if (String.IsNullOrEmpty(textBlock.Text))
{
// do something.
}
}
That being said, assuming first cell is simple DataGridTextColumn, you can get the value in traditional WinForms way in WPF like this:
for (int i = 0; i < dataGridView1.Items.Count; i++)
{
TextBlock textBlock = dataGridView1.Columns[0]
.GetCellContent(dataGridView1.Items[i]) as TextBlock;
if (textBlock != null)
{
if (String.IsNullOrEmpty(textBlock.Text))
{
// do something.
}
}
}
== is a comparison operator. = is used for assignment:
comboBox3.Text = dataGridView1.Rows[i].Cells[0].Value.ToString();

ComboBox.SelectedValue is not Working

I have a WinForms application. I've populated my ComboBox with the following code:
cboGridSize.Items.Clear();
for (int i = 2; i <= 12; i++)
cboGridSize.Items.Add(new KeyValuePair<string,int>(i.ToString(), i));
cboGridSize.SelectedValue = 4;
However, the last line has absolutely no effect. The ComboBox appears with no items selected.
So I was doing some debugging and noticed some odd things. The following image is from the watch window after setting cboGridSize.SelectedIndex to 0.
Watch Window http://www.softcircuits.com/Client/debugwin.jpg
Even though the SelectedItem property contains exactly what I would expect, SelectedValue is still null. Although the documentation for SelectedValue is pathetic, I understood it would contain the value of the selected item (SelectedItem). Instead, the two properties seem completely unrelated. Can anyone see what I have wrong?
As you can see, I have the ValueMember property set. And the DropDownStyle property is set to DropDownList.
EDIT:
Once Nikolay Khil set me straight on the issue here (why the docs for SelectedValue don't do that escapes me), I decided to simply write my own code to accomplish the same task. I'm posting it here in case anyone is interested.
static class ComboBoxHelper
{
public static void LookupAndSetValue(this ComboBox combobox, object value)
{
if (combobox.Items.Count > 0)
{
for (int i = 0; i < combobox.Items.Count; i++)
{
object item = combobox.Items[i];
object thisValue = item.GetType().GetProperty(combobox.ValueMember).GetValue(item);
if (thisValue != null && thisValue.Equals(value))
{
combobox.SelectedIndex = i;
return;
}
}
// Select first item if requested item was not found
combobox.SelectedIndex = 0;
}
}
}
This is implemented as an extension method so I simply change my original code as follows:
cboGridSize.Items.Clear();
for (int i = 2; i <= 12; i++)
cboGridSize.Items.Add(new KeyValuePair<string,int>(i.ToString(), i));
cboGridSize.LookupAndSetValue(4);
Both ValueMember and DisplayMember properties are used only if DataSource property is defined.
So, you should re-write your code as follows:
private readonly BindingList<KeyValuePair<string, int>> m_items =
new BindingList<KeyValuePair<string, int>>();
public YourForm()
{
InitializeComponent();
cboGridSize.DisplayMember = "Key";
cboGridSize.ValueMember = "Value";
cboGridSize.DataSource = m_items;
for (int i = 2; i <= 12; i++)
m_items.Add(new KeyValuePair<string,int>(i.ToString(), i));
cboGridSize.SelectedValue = 4;
}
Links:
BindingList class
ObservableCollection class
INotifyCollectionChanged Interface
This does not answer the OP however...the ComboBox SelectedValue must be an integer type.
If you have a short or byte var that holds the value that will set the SelectedValue, it won't work - you will have null/nothing value.
Use an integer.
I know this is an old question but I've just come across this problem myself. I solved with the following - it's slightly hacky but it works:
if(newVal != null)
{
MyComboBox.SelectedValue = newVal;
}
else
{
MyComboBox.SelectedIndex = 0; // the 'None Selected' item
}
Hope this helps someone.
u can set SelectedValue first, and then set Datasource and others

Categories

Resources