ControlTemplate中的边框导致DataGrid出现奇怪的选择行为

时间:2009-07-01 14:03:01

标签: c# wpf xaml datagrid

我已经将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 个答案:

答案 0 :(得分:2)

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

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

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元素的公共成员。

答案 1 :(得分:1)

工具包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并不暗示或设置该属性。

答案 2 :(得分:0)

感谢您的回复,我得到了一般的想法,但是将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();
}