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

如何在DevExpress TreeListView列中访问内嵌的TableView?

问题:无法访问TreeListView列内嵌套的TableView对象

在dxg:TreeListView的列中嵌入了dxg:TableView,界面运行正常,但后台代码无法直接访问名为LocationView的TableView,却能正常访问外层的StatesView:

// 可正常运行
var focusedState = (StateType)StatesView.FocusedNode.Content; 

// LocationView无法被调试器或解释器识别
var focusedLocationInStateRow = (LocationType)LocationView.FocusedNode.Content; 

目标是获取State行内选中的Location行(Location是State数据模型中的集合),并通过DeleteLocationRow方法删除该记录。

对应的WPF标记如下:

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="*" />
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*" />
    </Grid.ColumnDefinitions>
    <dxg:TreeListControl x:Name="StateGrid"
                     AllowLiveDataShaping="True"
                        SelectionMode="Cell"
                    Margin="16.5,0,0,0"
                         SelectedItem="{Binding SelectedState}"
                     ItemsSource="{Binding MyStates}">
        <dxg:TreeListControl.Resources>
            <Style x:Key="SummaryStyle" TargetType="Run">
                <Setter Property="FontWeight" Value="Bold"/>
                <Setter Property="dxp:TextExportSettings.FontFamily" Value="Arial Narrow"/>
            </Style>
        </dxg:TreeListControl.Resources>
        <dxg:TreeListControl.Columns>
            <dxg:TreeListColumn Header="Name" Width="190" FieldName="Name" />                               
            <dxg:TreeListColumn Header="State Id" Width="80" FieldName="StateId" />
            <dxg:TreeListColumn
                AllowEditing="true"
                Header="Locations"
                Width="Auto">
                <dxg:TreeListColumn.CellTemplate>
                    <DataTemplate>
                        <TextBlock Text="{Binding RowData.Row.Locations, Converter={valueConverters:LocaleIdsTextValueConverter}}"/>
                    </DataTemplate>
                </dxg:TreeListColumn.CellTemplate>
                <dxg:TreeListColumn.CellEditTemplate>
                    <DataTemplate>
                        <dxg:GridControl
                            x:Name="LocationGrid" 
                            ItemsSource="{Binding RowData.Row.Locations}"
                            HorizontalAlignment="Stretch" 
                            Height="100"
                            Width="525"
                            AutoGenerateColumns="AddNew" 
                            EnableSmartColumnsGeneration="True"
                            SelectionMode="Cell">
                            <dxg:GridControl.Columns>
                                <dxg:GridColumn Header="LocationId" FieldName="LocationId" SortIndex="0" Width="100" AllowEditing="true">
                                    <dxg:GridColumn.EditSettings>
                                        <dxe:SpinEditSettings MaskType="Numeric" Mask="d" MinValue="1" MaxValue="100"  
                                            ShowText="{Binding Path=RowData.Row.IsNode}"  
                                            IsTextEditable="{Binding Path=RowData.Row.IsNode}"  
                                            IsEnabled="{Binding Path=RowData.Row.IsNode}" />
                                    </dxg:GridColumn.EditSettings>
                                </dxg:GridColumn>
                                <dxg:GridColumn Header="Incorporated Date" SortIndex="1" SortOrder="Ascending" Width="110" FieldName="IncorporatedDate" AllowEditing="true">
                                    <dxg:GridColumn.EditSettings>
                                        <dxe:DateEditSettings MaskType="DateTime"
                                              Mask="MM/dd/yyyy HH:mm"
                                              MaskUseAsDisplayFormat="True"
                                              dxe:DateTimeMaskOptions.DateTimeKind="Local"
                                              NullText=""
                                              AllowNullInput="True"
                                              ValidateOnEnterKeyPressed="True"
                                              ValidateOnTextInput="True">
                                            <dxe:DateEditSettings.StyleSettings>
                                                <dxe:DateEditNavigatorWithTimePickerStyleSettings/>
                                            </dxe:DateEditSettings.StyleSettings>
                                        </dxe:DateEditSettings>
                                    </dxg:GridColumn.EditSettings>
                                </dxg:GridColumn>
                                <dxg:GridColumn Header="Delete Rows"  Width="100">
                                    <dxg:GridColumn.CellTemplate>
                                        <DataTemplate>
                                            <Button Click="DeleteLocationRow">
                                                Delete Row
                                            </Button>
                                        </DataTemplate>
                                    </dxg:GridColumn.CellTemplate>
                                </dxg:GridColumn>
                            </dxg:GridControl.Columns>
                            <dxg:GridControl.View>
                                <dxg:TableView
                                    Name="LocationView"
                                    NavigationStyle="Cell"
                                    AutoScrollOnSorting="False"
                                    NewItemRowPosition="Bottom"
                                    HorizontalScrollbarVisibility="Hidden"
                                    ShowColumnHeaders="True"
                                    ImmediateUpdateRowPosition="False"
                                    AllowSorting="True"
                                    AllowEditing="True"
                                    ShowIndicator="True"
                                    ShowGroupPanel="False"
                                    ShowTotalSummary="False"
                                    ShowFilterPanelMode="Never"
                                    CellStyle="{StaticResource CustomLocaleCellStyle}"
                                    ShowAutoFilterRow="False">
                                </dxg:TableView>
                            </dxg:GridControl.View>
                        </dxg:GridControl>
                    </DataTemplate>
                </dxg:TreeListColumn.CellEditTemplate>
            </dxg:TreeListColumn>
            <dxg:TreeListColumn Header="City" Width="60"  FieldName="City" />
        </dxg:TreeListControl.Columns>
        <dxg:TreeListControl.View>
            <dxg:TreeListView Name="StatesView"
                          TreeDerivationMode="HierarchicalDataTemplate"
                          AutoExpandAllNodes="True"
                          AllowConditionalFormattingMenu="True"
                          AutoScrollOnSorting="False"
                          ShowEmptyText ="False"
                          AutoWidth="False"
                          ShowExpandButtons="True"
                          ShowRootIndent="True"
                          ShowAutoFilterRow="True"
                          NavigationStyle="Cell"
                          ImmediateUpdateRowPosition="False"
                         EnableImmediatePosting ="True"
                            AllowSorting="False"
                            AllowEditing="True"
                            ShowIndicator="False"
                            ClipboardCopyOptions="All"
                            ClipboardMode="Formatted"
                            ShowTotalSummary="True"
                            ShowFilterPanelMode="Never"
                            EditorShowMode="MouseDown"
                            RowStyle="{StaticResource FocusedRowStyle}"
                            CellStyle="{StaticResource CustomCellStyle}"
                           AllowDataUpdateFormatConditionMenu="True">
                <dxg:TreeListView.ColumnHeaderTemplate>
                    <DataTemplate>
                        <TextBlock Text="{Binding}" TextWrapping="Wrap"/>
                    </DataTemplate>
                </dxg:TreeListView.ColumnHeaderTemplate>
            </dxg:TreeListView>
        </dxg:TreeListControl.View>
    </dxg:TreeListControl>
</Grid>

原因分析

LocationView和它所在的LocationGrid定义在CellEditTemplate的DataTemplate内部,DataTemplate是复用模板,只有当TreeList单元格进入编辑状态时才会实例化模板内容。XAML编译器不会为模板内的元素生成后台代码可直接访问的字段,因此无法通过名称直接调用。


解决方法

方法1:通过VisualTreeHelper查找激活的TableView

当TreeList单元格处于编辑状态时,遍历可视化树找到对应的LocationView:

private TableView GetActiveLocationView()
{
    var activeEditor = StatesView.ActiveEditor;
    if (activeEditor == null) return null;

    return FindVisualChild<TableView>(activeEditor);
}

private T FindVisualChild<T>(DependencyObject obj) where T : DependencyObject
{
    for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
    {
        DependencyObject child = VisualTreeHelper.GetChild(obj, i);
        if (child is T target)
            return target;
        
        T childOfChild = FindVisualChild<T>(child);
        if (childOfChild != null)
            return childOfChild;
    }
    return null;
}

// 使用示例
var locationView = GetActiveLocationView();
if (locationView != null)
{
    var focusedLocation = (LocationType)locationView.FocusedRow;
    DeleteLocationRow(focusedLocation);
}

方法2:通过按钮DataContext直接获取当前Location对象

删除按钮位于LocationGrid的行内,可直接绑定按钮的DataContext到当前Location行,点击时直接获取对象:
修改按钮XAML:

<Button Click="DeleteLocationRow" DataContext="{Binding RowData.Row}">
    Delete Row
</Button>

后台代码:

private void DeleteLocationRow(object sender, RoutedEventArgs e)
{
    var button = sender as Button;
    var locationToDelete = button.DataContext as LocationType;
    if (locationToDelete == null) return;

    var focusedState = (StateType)StatesView.FocusedNode.Content;
    focusedState.Locations.Remove(locationToDelete);
    // 如果Locations是ObservableCollection,UI会自动更新;否则需触发PropertyChanged
}

方法3:MVVM方式绑定SelectedItem

将LocationGrid的SelectedItem绑定到ViewModel属性,无需直接操作View:
修改LocationGrid的XAML:

<dxg:GridControl
    x:Name="LocationGrid" 
    ItemsSource="{Binding RowData.Row.Locations}"
    SelectedItem="{Binding DataContext.SelectedLocation, RelativeSource={RelativeSource AncestorType=dxg:TreeListControl}}"
    ...>

ViewModel添加属性和方法:

private LocationType _selectedLocation;
public LocationType SelectedLocation
{
    get => _selectedLocation;
    set
    {
        _selectedLocation = value;
        OnPropertyChanged();
    }
}

private StateType _selectedState;
public StateType SelectedState
{
    get => _selectedState;
    set
    {
        _selectedState = value;
        OnPropertyChanged();
    }
}

public ICommand DeleteLocationCommand => new RelayCommand(() =>
{
    if (SelectedState != null && SelectedLocation != null)
    {
        SelectedState.Locations.Remove(SelectedLocation);
    }
});

按钮绑定命令:

<Button Command="{Binding DataContext.DeleteLocationCommand, RelativeSource={RelativeSource AncestorType=dxg:TreeListControl}}">
    Delete Row
</Button>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 03:20:52