WPF: Adding Button Column to Datagrid
How can I add a开发者_开发百科 Button column to a Datagrid programmatically? I want to do this through code in the code-behind file.
Also i want to selectively enable or disable this button based on record (If status is Open then Enable it else disable this button). Here Status is a Column in the DataSource.
Thanks, Abhi
The answer linked by viky summarizes the idea of adding the button column from source. I've put together a short example that also shows the second part of your question, which is how to enable/disable the button based on the data in the grid. I used the DataGrid in 4.0, but the toolkit with 3.5 should be fine as well.
First, I add one Name column from XAML. This isn't necessary, but just shows that you can do a combination of XAML and C# additions to the grid. Note that I name the grid here so that I have a way to refer to it in the C# partial class.
<Window x:Class="WpfApplication2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Data Grid Populated in XAML and C#">
<Grid>
<DataGrid x:Name="_gridControl" IsReadOnly="True" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Header="Name" Width="*" Binding="{Binding Name}"/>
</DataGrid.Columns>
</DataGrid>
</Grid>
</Window>
Now, I do two things in the code behind. Aside from adding the button column and the data elements (which have a Name and a Status), I create a Converter class that will return true if the value is "Open" and false otherwise. Then, when setting the Binding (as opposed to value), I also add my converter so that when the ItemsControl generates and binds containers for my items, the Button displayed has its IsEnabled state linked to the Status field of my item.
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var buttonTemplate = new FrameworkElementFactory(typeof(Button));
buttonTemplate.SetBinding(Button.ContentProperty, new Binding("Name"));
buttonTemplate.SetBinding(Button.IsEnabledProperty, new Binding("Status")
{
Converter = new StatusToEnabledConverter()
});
buttonTemplate.AddHandler(
Button.ClickEvent,
new RoutedEventHandler((o, e) => MessageBox.Show("hi"))
);
this._gridControl.Columns.Add(
new DataGridTemplateColumn()
{
Header = "Close Button",
CellTemplate = new DataTemplate() { VisualTree = buttonTemplate }
}
);
this._gridControl.ItemsSource = new object[]
{
new { Name = "First Item", Status = "Open" },
new { Name = "Second Item", Status = "Open" },
new { Name = "Third Item", Status = "Closed" },
new { Name = "Fourth Item", Status = "Closed" },
new { Name = "Fifth Item", Status = "Open" }
};
}
}
public class StatusToEnabledConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter,
CultureInfo culture)
{
return "Open".Equals(value);
}
public object ConvertBack(object value, Type targetType, object parameter,
CultureInfo culture)
{
throw new System.NotImplementedException();
}
}
One final important note is that I only modify the DataGrid from C# after InitializeComponent is called. For a WPF content control that has a XAML and C# part, this is important, as the object construction done via XAML needs to have completed before you start modifying the objects defined in XAML.
Hope this helps!
Xaml :
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Click="Details">Details</Button>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
Code Behind
private IEnumerable<DataGridRow> GetDataGridRowsForButtons(DataGrid grid)
{ //IQueryable
var itemsSource = grid.ItemsSource as IEnumerable;
if (null == itemsSource) yield return null;
foreach (var item in itemsSource)
{
var row = grid.ItemContainerGenerator.ContainerFromItem(item) as DataGridRow;
if (null != row & row.IsSelected) yield return row;
}
}
void Details(object sender, RoutedEventArgs e)
{
for (var vis = sender as Visual; vis != null; vis = VisualTreeHelper.GetParent(vis) as Visual)
if (vis is DataGridRow)
{
// var row = (DataGrid)vis;
var rows = GetDataGridRowsForButtons(dgv_Students);
string id;
foreach (DataGridRow dr in rows)
{
id = (dr.Item as tbl_student).Identification_code;
MessageBox.Show(id);
}
break;
}
}
After clicking on the Button, the ID of that row is returned to you and you can use it for your Button name.
XAML:
<DataGrid.Columns>
<DataGridTemplateColumn Header="Check">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox x:Name="chkName" IsChecked="{Binding IsChecked , UpdateSourceTrigger=PropertyChanged}" Click="chkName_Click">
</CheckBox>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="as">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Click="OnAddQuantityClicked">hello</Button>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
Code Behind:
private async void OnAddQuantityClicked(object sender, RoutedEventArgs e)
{
if (sender is Button)
{
var temps = (Models.TempV)mainDatagrid.SelectedItem;
//Button button = (Button)e.OriginalSource;
if (temps.IsChecked is true)
{
MessageBox.Show("Do something when it is True");
}
else
{
MessageBox.Show("Do something when it is False");
}
}
}
精彩评论