【问题标题】:Datagrid sort, what happened to row?Datagrid排序,行发生了什么?
【发布时间】:2014-12-19 16:16:30
【问题描述】:

我正在编写一个用户控件,它可以用作带有颜色标记的滚动条(就像大多数 IDE 一样)。

我的 UserControl 外观

<UserControl x:Class="MarkedScrollBar" x:Name="Instance" ...>
<Grid Name="grd" >
    <COLUMN/ROW DEF>...</>
    <ScrollViewer Name="scrView" Grid.RowSpan="3" Grid.ColumnSpan="2" >
        <my:IcuContentPresenter x:Name="presenter" Content="{Binding AdditionnalContent, ElementName=Instance}" ContentUpdated="presenter_ContentUpdated"  />
    </ScrollViewer>
    <Canvas ...(Canvas place on the scrollbar) />
</Grid>
</UserControl>

在我的 UserControl 上,一切正常。我可以在我的 IcuContentPresenter 中添加内容(扩展 ContentPresenter 以获得 1 个更多事件)。

在我的主窗口中,我像这样使用我的 MarkedScroolBar:

<my:IcuMarkedScrollBar Grid.Row="0" x:Name="bbb" Grid.Column="0" >
        <my:IcuMarkedScrollBar.AdditionnalContent>
            <my:IcuDataGrid ItemsSource="{Binding AAA, RelativeSource={RelativeSource AncestorType={x:Type Window}}}" Loaded="DataGrid_Loaded" Width="300" LoadingRow="DataGrid_LoadingRow" />
        </my:IcuMarkedScrollBar.AdditionnalContent>
    </my:IcuMarkedScrollBar>

再次,我有一个 DataGrid 扩展来获取 1 个事件(排序事件,代码来自 here)。

现在我的问题是,当我在 MarkedScrollBar 中对数据网格进行排序时,我希望标记跟随标记绑定到的内容。

第一次尝试,我尝试将标记与具有 Dictionary Key=Mark, Value=Control 的控件链接。我得到了我想为我的数据上下文标记的 DatagridRow。

第一次出现数据网格时,我的标记都很好,但是如果我排序,我的标记不跟随。我进行调试,发现有一个 DataGridRow 包含我的数据上下文项,但它不是我保存在字典中的那个。

结束第一次尝试

第二次尝试,当我排序时 DataGridRow 发生变化,我认为如果我将 DataContext 项链接到我的标记,它会修复错误。

所以现在,当我对我的数据网格进行排序时,我会尝试找到包含我的数据上下文项的数据网格。但它确实找到了任何东西。

但是,当我使用窗口中的按钮手动重新执行相同的代码时,它就可以工作了。我所有的标记都出现在好的位置。

结束第二次尝试

我的扩展的简要说明:

  • DataGrid :我使用它来获取 Sorted 事件,因为在 Sorting 事件中尚未移动的行。
  • ContentPresenter :我在其上添加事件以修改内容,但不修改属性(如数据网格排序)。为此我需要检查内容的类型,所以我暂时不支持所有内容。

我的 ContentPresenter 代码是:

public class IcuContentPresenter : ContentPresenter
{

    public event EventHandler<ControlEventArgs> ContentUpdated;

    public IcuContentPresenter()
    {
        this.Loaded += OnLoaded;
    }

    protected void OnLoaded(object p_oSender, RoutedEventArgs p_oEvent)
    {
        Type t = this.Content.GetType();

        if (t == typeof(IcuDataGrid))
        {
            IcuDataGrid oControl = this.Content as IcuDataGrid;
            oControl.Sorted += CallEvent;
        }
    }

    void CallEvent(object sender, EventArgs e)
    {
        if (ContentUpdated != null)
        {
            ContentUpdated(this, new ControlEventArgs(Content.GetType()));
        }
    }


    public UIElement FindVisualElementForObject(object p_oObject)
    {
        UIElement oTheOne = null;

        if (Content.GetType() == typeof(IcuDataGrid))
        {
            oTheOne = FindInDatagrid(p_oObject);
        }

        return oTheOne;
    }

    private UIElement FindInDatagrid(Object p_oObj)
    {
        DataGrid oGrid = Content as DataGrid;

        var a = (DataGridRow)oGrid.ItemContainerGenerator.ContainerFromItem(p_oObj);

        return a;
    }

    //----------------------------------------------------
    // Inner class 
    //----------------------------------------------------
    public class ControlEventArgs : EventArgs
    {
        public ControlEventArgs(Type value)
        {
            ControlType = value;
        }

        public Type ControlType { get; set; }

    }
}

为了支持控件,我必须在此处添加它们。在加载此控件时,我检查内容,如果内容是我对事件排序的 Datagrid,我调用我的事件 ContentUpdated 以便能够更新我的标记。但此时,就像我的数据网格中没有包含我的数据上下文项的行。

【问题讨论】:

    标签: c# wpf xaml sorting datagrid


    【解决方案1】:

    启用虚拟化后,只会为实际可见的数据项生成行元素。您需要将标记与基础数据项(行对象)而不是DataGridRow 元素相关联。 DataGrid 上的 Items 属性应使行处于正确排序的位置。

    【讨论】:

    • 当您说将标记与底层元素相关联时,这与我的第二次尝试不一样?我试图获取包含此元素的行来更新标记,但是当我的事件结束时我没有找到一行,但是当我启动更新行的命令时是 find。
    • 不是底层元素;元素绑定到的底层数据项。如果该行不在视图中,则可能不会创建该元素。你只知道数据项在集合中的位置;你不知道元素的确切位置,所以你必须估计。
    • 感谢解答,我只能估计位置有点糟糕,但我现在就做吧。
    • 这就是 DataGrid 的滚动条所能做的 :)。这是行虚拟化的权衡之一。你不知道一行会有多大,你只生成和测量实际可见的行。
    猜你喜欢
    • 2013-07-08
    • 1970-01-01
    • 2015-09-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-28
    • 2014-02-28
    • 2010-10-02
    相关资源
    最近更新 更多