代码之家  ›  专栏  ›  技术社区  ›  dariusriggins

ControlTemplate中的边框导致使用DataGrid的奇怪选择行为

  •  2
  • dariusriggins  · 技术社区  · 17 年前

    我已经将Microsoft WPF DataGrid中的DataGridRow重新模板到下面,我遇到的问题是,如果用户单击模板的边框元素,该行就不会被选中。有没有一种方法可以使单击边框导致行选择。

    <Grid x:Name="LayoutRoot" Margin="0,0,0,-1">
            <Border x:Name="DGR_Border" BorderBrush="Transparent" Background="Transparent" BorderThickness="1" CornerRadius="5" SnapsToDevicePixels="True">
                <Border x:Name="DGR_InnerBorder" BorderBrush="Transparent" Background="Transparent" BorderThickness="1" CornerRadius="5" SnapsToDevicePixels="True">
                    <toolkit:SelectiveScrollingGrid Name="DGR_SelectiveScrollingGrid">
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="Auto"/>
                            <ColumnDefinition Width="*"/>
                        </Grid.ColumnDefinitions>
    
                        <Grid.RowDefinitions>
                            <RowDefinition Height="*"/>
                            <RowDefinition Height="Auto"/>
                        </Grid.RowDefinitions>
    
                        <toolkit:DataGridCellsPresenter Grid.Column="1" Name="DGR_CellsPresenter" ItemsPanel="{TemplateBinding ItemsPanel}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
                        <toolkit:DataGridDetailsPresenter Grid.Column="1" Grid.Row="1" Visibility="{TemplateBinding DetailsVisibility}" toolkit:SelectiveScrollingGrid.SelectiveScrollingOrientation="{Binding RelativeSource={RelativeSource AncestorType={x:Type Controls:DataGrid}}, Path=AreRowDetailsFrozen, Converter={x:Static Controls:DataGrid.RowDetailsScrollingConverter}, ConverterParameter={x:Static Controls:SelectiveScrollingOrientation.Vertical}}" />
                        <toolkit:DataGridRowHeader Grid.RowSpan="2" toolkit:SelectiveScrollingGrid.SelectiveScrollingOrientation="Vertical" Visibility="{Binding RelativeSource={RelativeSource AncestorType={x:Type Controls:DataGrid}}, Path=HeadersVisibility, Converter={x:Static Controls:DataGrid.HeadersVisibilityConverter}, ConverterParameter={x:Static Controls:DataGridHeadersVisibility.Row}}"/>
                    </toolkit:SelectiveScrollingGrid>
                </Border>
            </Border>
        </Grid>
    
    3 回复  |  直到 17 年前
        1
  •  2
  •   Fabrício Matté    17 年前

    调用内部方法似乎有点危险。如果实现细节发生变化怎么办?以前的版本有很多变化。

    我认为在您的行中简单地添加这样的事件处理程序可能更为谨慎:

    protected void DataGridRow_MouseDown(object sender, MouseButtonEventArgs e)
    {
        // GetVisualChild<T> helper method, simple to implement
        DataGridCellsPresenter presenter = GetVisualChild<DataGridCellsPresenter>(rowContainer);
    
        // try to get the first cell in a row
        DataGridCell cell = (DataGridCell)presenter.ItemContainerGenerator.ContainerFromIndex(0);
        if (cell != null)
        {
            RoutedEventArgs newEventArgs = new RoutedEventArgs(MouseLeftButtonDownEvent);
            //if the DataGridSelectionUnit is set to FullRow this will have the desired effect
            cell.RaiseEvent(newEventArgs);
        }
    }
    

    这将具有与单击单元格本身相同的效果,并且只使用DataGrid元素的公共成员。

        2
  •  1
  •   Fabrício Matté    17 年前

    工具箱DataGridRow没有定义的OnMouseDown重写或类似方法。整行的选择通过以下方法处理:

    internal void HandleSelectionForCellInput(DataGridCell cell, bool startDragging, bool allowsExtendSelect, bool allowsMinimalSelect)
    {
        DataGridSelectionUnit selectionUnit = SelectionUnit;
    
        // If the mode is None, then no selection will occur
        if (selectionUnit == DataGridSelectionUnit.FullRow)
        {
            // In FullRow mode, items are selected
            MakeFullRowSelection(cell.RowDataItem, allowsExtendSelect, allowsMinimalSelect);
        }
        else
        {
            // In the other modes, cells can be individually selected
            MakeCellSelection(new DataGridCellInfo(cell), allowsExtendSelect, allowsMinimalSelect);
        }
    
        if (startDragging)
        {
            BeginDragging();
        }
    }
    

    当输入发生在 细胞 . makefullRowSelection方法只选择一行中的所有单元格,而不是行本身。

    因此,当您单击DataGridRow(而不是DataGridCell)时,不会发生鼠标向下或选择处理。要完成您想要的,您应该在行的鼠标悬停事件中添加某种鼠标悬停处理程序,您可以在其中设置IsSelected属性。当然,请注意,您应该分别为行中的每个单元格指定Selected属性,因为row.isselected并不意味着或设置该属性。

        3
  •  0
  •   dariusriggins    17 年前

    感谢您的回答,我得到了一个一般性的想法,但是将isselected设置为true并没有按我预期的方式工作,当它击中时,会导致行被选中,但不会取消另一行的选中(在这种情况下,它应该是这样)。我可以通过在我的处理程序中调用handleselectionforcellinput来解决这个问题。然后我将从下面创建的lambda与网格和单元格一起调用,效果非常好。

    public static Action<DataGrid, DataGridCell, bool> CreateSelectRowMethod(bool allowExtendSelect, bool allowMinimalSelect)
    {
    var selectCellMethod = typeof(DataGrid).GetMethod("HandleSelectionForCellInput", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
    
    ParameterExpression dataGrid = Expression.Parameter(typeof(DataGrid), "dataGrid");
    ParameterExpression paramCell = Expression.Parameter(typeof(DataGridCell), "cell");
    ParameterExpression paramStartDragging = Expression.Parameter(typeof(bool), "startDragging");
    var paramAllowsExtendSelect = Expression.Constant(allowExtendSelect, typeof(bool));
    var paramAllowsMinimalSelect = Expression.Constant(allowMinimalSelect, typeof(bool));
    
    var call = Expression.Call(dataGrid, selectCellMethod, paramCell, paramStartDragging, paramAllowsExtendSelect, paramAllowsMinimalSelect);
    
    return (Action<DataGrid, DataGridCell, bool>)Expression.Lambda(call, dataGrid, paramCell, paramStartDragging).Compile();
    }
    
    推荐文章