You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

继承WPF DataGrid的自定义控件问题求助:事件与列配置等

Let's tackle each of your issues step by step, with concrete code fixes tailored to your current setup:

1. Fixing SelectionChanged and other event failures

The problem here is that your custom control uses an internal DataGrid in its template, but events like SelectionChanged or MouseDoubleClick are raised by this inner grid—not your CustomDataGrid control. The event handlers you’ve attached to your custom control aren’t triggered because those events aren’t being forwarded up.

Here’s how to fix it:

  1. Give the inner DataGrid a name in your control template so you can reference it in code:
    <Style TargetType="{x:Type local:CustomDataGrid}" BasedOn="{StaticResource {x:Type DataGrid}}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type local:CustomDataGrid}">
                    <Border Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}">
                        <!-- Add x:Name to the inner DataGrid -->
                        <DataGrid x:Name="InnerDataGrid" 
                                  BorderThickness="{TemplateBinding BorderThickness}" 
                                  ColumnHeaderStyle="{TemplateBinding ColumnHeaderStyle}" 
                                  ItemsSource="{TemplateBinding ItemsSource}" 
                                  CanUserAddRows="{TemplateBinding CanUserAddRows}" 
                                  IsReadOnly="{TemplateBinding IsReadOnly}"/>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    
  2. Override OnApplyTemplate in your CustomDataGrid class to hook up the inner grid’s events and forward them to your control:
    public class CustomDataGrid : DataGrid
    {
        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            
            var innerGrid = GetTemplateChild("InnerDataGrid") as DataGrid;
            if (innerGrid == null) return;
    
            // Forward SelectionChanged event
            innerGrid.SelectionChanged += (sender, e) =>
                RaiseEvent(new SelectionChangedEventArgs(SelectionChangedEvent, e.AddedItems, e.RemovedItems));
    
            // Forward MouseDoubleClick event
            innerGrid.MouseDoubleClick += (sender, e) =>
                RaiseEvent(new MouseButtonEventArgs(e.MouseDevice, e.Timestamp, e.ChangedButton)
                {
                    RoutedEvent = MouseDoubleClickEvent
                });
    
            // Add any other events you need to forward here (e.g., PreviewMouseDown)
        }
    }
    

This way, when the inner grid raises an event, your custom control will re-raise it, and your existing event handlers will fire as expected.

2. Using explicitly defined columns in your CustomDataGrid

Right now, the columns you define in your XAML (like the DataGridTemplateColumn for the delete button) aren’t being used because the inner DataGrid isn’t connected to your CustomDataGrid’s Columns collection.

Fix this by adding a TemplateBinding for the Columns property to the inner DataGrid:

<DataGrid x:Name="InnerDataGrid" 
          <!-- Add this line -->
          Columns="{TemplateBinding Columns}"
          BorderThickness="{TemplateBinding BorderThickness}" 
          ColumnHeaderStyle="{TemplateBinding ColumnHeaderStyle}" 
          ItemsSource="{TemplateBinding ItemsSource}" 
          CanUserAddRows="{TemplateBinding CanUserAddRows}" 
          IsReadOnly="{TemplateBinding IsReadOnly}"/>

Now any columns you define on your CustomDataGrid will be passed down to the inner grid and rendered correctly.

3. Inheriting the grid filter properties

Your colleague’s filter uses attached properties (e.g., filter:DataGridExtensions.UseBackgroundWorkerForFiltering). Since your CustomDataGrid inherits from DataGrid, these properties will work on your control—but you need to pass their values down to the inner DataGrid that actually renders the grid.

Add bindings for each filter attached property to the inner DataGrid in your template:

<DataGrid x:Name="InnerDataGrid" 
          Columns="{TemplateBinding Columns}"
          BorderThickness="{TemplateBinding BorderThickness}" 
          ColumnHeaderStyle="{TemplateBinding ColumnHeaderStyle}" 
          ItemsSource="{TemplateBinding ItemsSource}" 
          CanUserAddRows="{TemplateBinding CanUserAddRows}" 
          IsReadOnly="{TemplateBinding IsReadOnly}"
          <!-- Bind filter properties -->
          filter:DataGridExtensions.UseBackgroundWorkerForFiltering="{TemplateBinding (filter:DataGridExtensions.UseBackgroundWorkerForFiltering)}"
          filter:DataGridExtensions.IsClearButtonVisible="{TemplateBinding (filter:DataGridExtensions.IsClearButtonVisible)}"
          filter:DataGridExtensions.IsFilterVisible="{TemplateBinding (filter:DataGridExtensions.IsFilterVisible)}"/>

For column-level filter properties (like filter:DataGridColumnExtensions.DoNotGenerateFilterControl), you don’t need extra work—since we’re binding the Columns collection, those properties will be carried over to the inner grid’s columns automatically.


内容的提问来源于stack exchange,提问作者Patrick Pirzer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 07:22:10