0

我想为 a 实现一个自定义添加行按钮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

4

1 回答 1

0

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

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

dataCollection.Add(new DataType());

您应该能够在您的AttachedProperty使用中访问您的数据绑定集合:

var dataCollection = (DataCollectionType)dataGrid.ItemsSource;

我相信你也可以使用:

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

虽然不推荐这种方法。

于 2013-07-22T12:44:55.763 回答