English 中文(简体)
WPF: Adding Button Column to Datagrid
原标题:
  • 时间:2009-11-18 10:41:44
  •  标签:
  • wpf
  • 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");
                }
            }
        }




相关问题
WPF convert 2d mouse click into 3d space

I have several geometry meshes in my Viewport3D, these have bounds of (w:1800, h:500, d:25). When a user clicks in the middle of the mesh, I want the Point3D of (900, 500, 25)... How can I achieve ...

Editing a xaml icons or images

Is it possible to edit a xaml icons or images in the expression design or using other tools? Is it possible to import a xaml images (that e.g you have exported) in the expression designer for editing?...

WPF: writing smoke tests using ViewModels

I am considering to write smoke tests for our WPF application. The question that I am faced is: should we use UI automation( or some other technology that creates a UI script), or is it good enough to ...

WPF - MVVM - NHibernate Validation

Im facing a bit of an issue when trying to validate a decimal property on domain object which is bound to a textbox on the view through the viewmodel. I am using NHibernate to decorate my property on ...

How do WPF Markup Extensions raise compile errors?

Certain markup extensions raise compile errors. For example StaticExtension (x:Static) raises a compile error if the referenced class cannot be found. Anyone know the mechanism for this? Is it baked ...

WPF design-time context menu

I am trying to create a custom wpf control, I m wondering how I can add some design-time features. I ve googled and can t seem to get to my goal. So here s my simple question, how can I add an entry ...

How to combine DataTrigger and EventTrigger?

NOTE I have asked the related question (with an accepted answer): How to combine DataTrigger and Trigger? I think I need to combine an EventTrigger and a DataTrigger to achieve what I m after: when ...

热门标签