DataGrid自定义CanUserAddRows实现

时间:2013-07-22 01:53:17

标签: wpf datagrid wpfdatagrid wpf-4.0 attached-properties

我想为DataGrid实现自定义添加行按钮(这是一个很长的故事)。我在模板中添加了按钮,并定义了附加属性,我可以点击按钮。但我不能以通用方式添加新行 - 不是指定类型。我知道我可以在ViewModel中做类似的事情,但我希望在模板和附加属性中执行此操作。这是我的尝试;有没有想过要完成这个?

XAML:

<Style x:Key="{x:Type DataGrid}" TargetType="{x:Type DataGrid}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type DataGrid}">
                <Border x:Name="border">
                    <ScrollViewer x:Name="DG_ScrollViewer" Focusable="false">
                        <ScrollViewer.Template>
                            <ControlTemplate TargetType="{x:Type ScrollViewer}">
                                <Grid>
                                    <Grid.ColumnDefinitions>
                                        <ColumnDefinition Width="Auto" />
                                        <ColumnDefinition Width="*" />
                                        <ColumnDefinition Width="Auto" />
                                    </Grid.ColumnDefinitions>
                                    <Grid.RowDefinitions>
                                        <RowDefinition Height="Auto" />
                                        <RowDefinition Height="*" />
                                        <RowDefinition Height="Auto" />
                                    </Grid.RowDefinitions>

                                    <Button Focusable="false"
                                            Command="{x:Static DataGrid.SelectAllCommand}" />
                                    <DataGridColumnHeadersPresenter 
                                        x:Name="PART_ColumnHeadersPresenter"
                                        Grid.Column="1" />

                                    <Grid Grid.ColumnSpan="2" Grid.Row="1">
                                        <Grid.RowDefinitions>
                                            <RowDefinition Height="*"/>
                                            <RowDefinition Height="22" />
                                        </Grid.RowDefinitions>
                                        <ScrollContentPresenter 
                                                x:Name="PART_ScrollContentPresenter" />

                                        <!-- THIS IS MY CUSTOM BUTTON TO ADD NEW ROW -->
                                        <Button x:Name="PART_AddRowButton"
                                                Content="Add"/>
                                    </Grid>

                                    <ScrollBar x:Name="PART_VerticalScrollBar"/>

                                    <Grid Grid.Column="1" Grid.Row="2">
                                        <ScrollBar x:Name="PART_HorizontalScrollBar"/>
                                    </Grid>
                                </Grid>
                            </ControlTemplate>
                        </ScrollViewer.Template>
                        <ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
                    </ScrollViewer>
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

C#:

public class DataGridHelper {

    public static readonly DependencyProperty CanUserAddRowsProperty
        = DependencyProperty.RegisterAttached(
        "CanUserAddRows", typeof(bool), typeof(DataGridHelper),
        new FrameworkPropertyMetadata(default(bool), CanUserAddRowsChanged));

    [AttachedPropertyBrowsableForType(typeof(DataGrid))]
    public static bool GetCanUserAddRows(DependencyObject obj) {
        return (bool)obj.GetValue(CanUserAddRowsProperty);
    }

    [AttachedPropertyBrowsableForType(typeof(DataGrid))]
    public static void SetCanUserAddRows(DependencyObject obj, bool value) {
        obj.SetValue(CanUserAddRowsProperty, value);
    }

    private static void CanUserAddRowsChanged(
        DependencyObject d,
        DependencyPropertyChangedEventArgs e) {
        var dataGrid = d as DataGrid;
        if (dataGrid == null)
            return;
        bool oldValue = (bool)e.OldValue,
            newValue = (bool)e.NewValue;
        if (newValue == oldValue)
            return;
        if (newValue) {
            dataGrid.Loaded += CanUserAddRowsDataGridLoaded;
        } else {
            dataGrid.Loaded -= CanUserAddRowsDataGridLoaded;
        }
    }

    private static void CanUserAddRowsDataGridLoaded(object sender, RoutedEventArgs e) {
        var dataGrid = sender as DataGrid;
        if (dataGrid == null)
            return;
        if (dataGrid.Style == null)
            return;
        var rootTemplate = dataGrid.Template;
        if (rootTemplate == null)
            return;
        var scroll = rootTemplate.FindName("DG_ScrollViewer", dataGrid) as ScrollViewer;
        if (scroll == null)
            return;
        var scrollTemplate = scroll.Template;
        if (scrollTemplate == null)
            return;
        var button = scrollTemplate.FindName("PART_AddRowButton", scroll) as ButtonBase;
        if (button == null)
            return;
        if (GetCanUserAddRows(dataGrid)) {
            button.Click += AddRowClicked;
        } else {
            button.Click -= AddRowClicked;
        }
    }

    private static void AddRowClicked(object sender, RoutedEventArgs e) {
        var button = ((ButtonBase)sender);
        var parent = VisualTreeHelper.GetParent(button);
        while (!(parent is DataGrid))
            parent = VisualTreeHelper.GetParent(parent);
        var source = ((DataGrid)parent).Items.Add(...) // now what???
    }
}

嗯,正如您所看到的,点击按钮后我可以访问DataGrid;但是下一步是什么?如何强制DataGrid显示NewItemPlaceHolder

1 个答案:

答案 0 :(得分:0)

通常在WPF中,我们将数据对象的集合(最好是支持更改通知的集合,如ObservableCollection)绑定到UI控件。我们不是将新项添加到UI控件,而是将代码添加到代码隐藏/视图模型中的集合中。只要集合支持更改通知,UI控件就会自动更新。

因此,要向DataGrid添加新行,您需要在集合中添加新项目:

dataCollection.Add(new DataType());

您应该能够使用以下内容访问AttachedProperty中的数据绑定集合。

var dataCollection = (DataCollectionType)dataGrid.ItemsSource;

我相信你也可以使用:

dataGrid.Items.Add(new DataType());

虽然不推荐这种方法。