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
Related
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 a grid view and checked listbox. i wanto to add the selected items of checked listbox as a Column of the Grid View.
private void btnProceed_Click(object sender, EventArgs e)
{
if (listSubjects.Items.Count > 0)
{
for (int i = 0; i < listSubjects.Items.Count; i++)
{
if (listSubjects.GetItemChecked(i))
{
//dataGridView1.Rows.Add(checkedListBox1.Items[i], "1");
DataRowView castedItem = listSubjects.Items[i] as DataRowView;
string item = castedItem.ToString();
dgvEnterMarks.Columns.Add(item, item);
}
}
}
}
This is something that I have done... Add the items to the collection
SelectedItems="{Binding SelectedSalesMultiCountries, Mode=TwoWay}"
bind the visibility to a property..
<telerik:GridViewDataColumn IsVisible="{Binding CompanyNameVisibility, Mode=TwoWay}" />
now set the above property to true when the checkbox item is selected. Hope this helped. thanks.
private void btnProceed_Click(object sender, EventArgs e)
{
if (listSubjects.Items.Count > 0)
{
for (int i = 0; i < listSubjects.Items.Count; i++)
{
if (listSubjects.GetItemChecked(i))
{
DataRowView castedItem = listSubjects.Items[i] as DataRowView;
string item = Convert.ToString(castedItem["SubjectName"]);
dgvEnterMarks.Columns.Add(item, item);
}
}
PopulateGridView();
}
}
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?
I have a list of result listed after extracting from a .txt file. I would like to add a checkbox behind every results listed. The following is my code:
private void LoadFile() {
List<string> lines = new List<string>();
try
{
StreamReader sr = new StreamReader("test.txt");
while (!sr.EndOfStream)
{
lines.Add(sr.ReadLine());
}
sr.Close();
for (int i = 3; i < lines.Count; i++)
{
resultsTreeView.Items.Add(lines[i].ToString().Substring(67,17));
resultsTreeView.Items.Add(CheckBox[i]);
}
How can I add checkboxes as the results extracted will change every time? I would like to track which boxes has checked as well so that I can print the result to users. Thank you!
for (int i = 3; i < lines.Count; i++)
{
resultsTreeView.Items.Add(lines[i].ToString().Substring(67,17));
resultsTreeView.Items.Add(new CheckBox());
// resultsTreeView.Items.Add(BuildCheckBox())
}
OR
CheckBox BuildCheckbox()
{
CheckBox C = new CheckBox();
return C;
}
That's all you need to create a checkbox, or you can create a function that returns a checkbox, inside it you create a new instance of checkbox and set the attributes/subscribe to events the way you want and return it.
As for the tracking which checkboxes are checked, I only need you to provide me with the type of your "resultsTreeView"
EDIT :
To loop through checkboxes in the TreeView and do something on the checked ones:
resultsTreeView.Items.OfType<CheckBox>().ToList()
.ForEach(C =>
{
if (C.IsChecked.HasValue && C.IsChecked.Value == true)
{
//DoSomething
}
});
I am not sure exactly what you are looking for. I assume resultsTreeView is a TreeViewItem. and I also assume that you are working in wpf. You can do the following through wpf.
for (int i = 0; i < lines.Count(); i++)
{
resultsTreeView.Items.Add(lines[i].ToString().Substring(67,17));
}
<TreeView x:Name="resultsTreeView" HorizontalAlignment="Left" Height="100" Margin="37,344,0,0" VerticalAlignment="Top" Width="257" >
<TreeView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding}"/>
<CheckBox/>
</StackPanel>
</DataTemplate>
</TreeView.ItemTemplate>
</TreeView>
Something similar could be done through code behind
for (int i = 0; i < mylist.Count(); i++)
{
resultsTreeView.Items.Add(mylist[i]);
}
resultsTreeView.ItemTemplate = TreeViewDataTemp;
And then create TreeViewDataTemp the following way
private static DataTemplate TreeViewDataTemp
{
get
{
DataTemplate TVDT = new DataTemplate();
FrameworkElementFactory Stack = new FrameworkElementFactory(typeof(StackPanel));
Stack.SetValue(StackPanel.OrientationProperty, Orientation.Horizontal);
FrameworkElementFactory TextB = new FrameworkElementFactory(typeof(TextBlock));
TextB.SetValue(TextBlock.TextProperty, new Binding());
FrameworkElementFactory ChkBox = new FrameworkElementFactory(typeof(CheckBox));
Stack.AppendChild(TextB);
Stack.AppendChild(ChkBox);
TVDT.VisualTree = Stack;
return TVDT;
}
}
The above gives you 1 item which is text together with a checkbox.
Alternatively your method will add a checkbox as a new item after every string item that you add.. which is
for (int I=0; I<lines.Count(); I++)
{
resultsTreeView.Items.Add(mylist[i]);
resultsTreeView.Items.Add(new CheckBox());
}
Please help me, Im trying to get the value of Cell[0] from the selected row in a SelectionChangedEvent.
I am only managing to get lots of different Microsoft.Windows.Controls and am hoping im missing something daft.
Hoping I can get some help from here...
private void datagrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
Microsoft.Windows.Controls.DataGrid _DataGrid = sender as Microsoft.Windows.Controls.DataGrid;
}
I was hoping it would be something like...
_DataGrid.SelectedCells[0].Value;
However .Value isn't an option....
Many many thanks this has been driving me mad!
Dan
Less code, and it works.
private void datagrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
DataGrid dataGrid = sender as DataGrid;
DataGridRow row = (DataGridRow)dataGrid.ItemContainerGenerator.ContainerFromIndex(dataGrid.SelectedIndex);
DataGridCell RowColumn = dataGrid.Columns[ColumnIndex].GetCellContent(row).Parent as DataGridCell;
string CellValue = ((TextBlock)RowColumn.Content).Text;
}
ColumnIndex is the index of the column you want to know.
pls, check if code below would work for you:
private void dataGrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
DataGrid dataGrid = sender as DataGrid;
if (e.AddedItems!=null && e.AddedItems.Count>0)
{
// find row for the first selected item
DataGridRow row = (DataGridRow)dataGrid.ItemContainerGenerator.ContainerFromItem(e.AddedItems[0]);
if (row != null)
{
DataGridCellsPresenter presenter = GetVisualChild<DataGridCellsPresenter>(row);
// find grid cell object for the cell with index 0
DataGridCell cell = presenter.ItemContainerGenerator.ContainerFromIndex(0) as DataGridCell;
if (cell != null)
{
Console.WriteLine(((TextBlock)cell.Content).Text);
}
}
}
}
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;
}
hope this helps, regards
This will give you the current selected row in the DataGrid in WPF:-
DataRow dtr = ((System.Data.DataRowView)(DataGrid1.SelectedValue)).Row;
Now to get the cell value just write dtr[0], dtr["ID"], etc.
Since you are using the "SelectionChanged", you can use the sender as a Data Grid:
DataGrid dataGrid = sender as DataGrid;
DataRowView rowView = dataGrid.SelectedItem as DataRowView;
string myCellValue = rowView.Row[0].ToString(); /* 1st Column on selected Row */
I tried the answers posted here and were good, but gave me problems when started to hide columns in the DataGrid. This one works for me even when hiding columns. Hope it works for you too.
private void datagrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
DataGrid _DataGrid = sender as DataGrid;
string strEID = _DataGrid.SelectedCells[0].Item.ToString();
}