Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/joomla/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何加快垂直滚动条标记的渲染速度_C#_Wpf_Xaml_Rendering_Wpfdatagrid - Fatal编程技术网

C# 如何加快垂直滚动条标记的渲染速度

C# 如何加快垂直滚动条标记的渲染速度,c#,wpf,xaml,rendering,wpfdatagrid,C#,Wpf,Xaml,Rendering,Wpfdatagrid,我有一个定制的垂直滚动条,它显示DataGrid中选定项目的标记 我面临的问题是,当有大量项目(例如,可能是5000到50000)时,在渲染标记时会出现延迟 使用下面的代码,它基本上根据所选项目索引、项目数量和轨迹高度进行渲染。显然,这是低效的,我正在寻找其他解决方案 这是我定制的垂直滚动条 <helpers:MarkerPositionConverter x:Key="MarkerPositionConverter"/> <ControlTemplate x:Key="V

我有一个定制的垂直滚动条,它显示DataGrid中选定项目的标记

我面临的问题是,当有大量项目(例如,可能是5000到50000)时,在渲染标记时会出现延迟

使用下面的代码,它基本上根据所选项目索引、项目数量和轨迹高度进行渲染。显然,这是低效的,我正在寻找其他解决方案

这是我定制的垂直滚动条

<helpers:MarkerPositionConverter x:Key="MarkerPositionConverter"/>

<ControlTemplate x:Key="VerticalScrollBar" TargetType="{x:Type ScrollBar}">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition MaxHeight="18" />
            <RowDefinition Height="0.00001*" />
            <RowDefinition MaxHeight="18" />
        </Grid.RowDefinitions>
        <Border Grid.RowSpan="3"
                        CornerRadius="2"
                        Background="#F0F0F0" />
        <RepeatButton Grid.Row="0"
                              Style="{StaticResource ScrollBarLineButton}"
                              Height="18"
                              Command="ScrollBar.LineUpCommand"
                              Content="M 0 4 L 8 4 L 4 0 Z" />
        <!--START-->
        <ItemsControl VerticalAlignment="Stretch"  x:Name="ItemsSelected"
                                   ItemsSource="{Binding ElementName=GenericDataGrid, Path=SelectedItems}">
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <Rectangle Fill="SlateGray" Width="9" Height="4">
                        <Rectangle.RenderTransform>
                            <TranslateTransform>
                                <TranslateTransform.Y>
                                    <MultiBinding Converter="{StaticResource MarkerPositionConverter}" FallbackValue="-1000">
                                        <Binding/>
                                        <Binding RelativeSource="{RelativeSource AncestorType={x:Type DataGrid}}" />
                                        <Binding Path="ActualHeight" ElementName="ItemsSelected"/>
                                        <Binding Path="Items.Count" ElementName="GenericDataGrid"/>
                                    </MultiBinding>
                                </TranslateTransform.Y>
                            </TranslateTransform>
                        </Rectangle.RenderTransform>
                    </Rectangle>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <Canvas ClipToBounds="True"/>
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
        </ItemsControl>
        <!--END-->
        <Track x:Name="PART_Track" Grid.Row="1" IsDirectionReversed="true">
            <Track.DecreaseRepeatButton>
                <RepeatButton Style="{StaticResource ScrollBarPageButton}"
                                      Command="ScrollBar.PageUpCommand" />
            </Track.DecreaseRepeatButton>
            <Track.Thumb>
                <Thumb Style="{StaticResource ScrollBarThumb}" Margin="1,0,1,0">
                    <Thumb.BorderBrush>
                        <LinearGradientBrush StartPoint="0,0" EndPoint="1,0">
                            <LinearGradientBrush.GradientStops>
                                <GradientStopCollection>
                                    <GradientStop Color="{DynamicResource BorderLightColor}" Offset="0.0" />
                                    <GradientStop Color="{DynamicResource BorderDarkColor}" Offset="1.0" />
                                </GradientStopCollection>
                            </LinearGradientBrush.GradientStops>
                        </LinearGradientBrush>
                    </Thumb.BorderBrush>
                    <Thumb.Background>
                        <LinearGradientBrush StartPoint="0,0"
                                 EndPoint="1,0">
                            <LinearGradientBrush.GradientStops>
                                <GradientStopCollection>
                                    <GradientStop Color="{DynamicResource ControlLightColor}" Offset="0.0" />
                                    <GradientStop Color="{DynamicResource ControlMediumColor}" Offset="1.0" />
                                </GradientStopCollection>
                            </LinearGradientBrush.GradientStops>
                        </LinearGradientBrush>
                    </Thumb.Background>
                </Thumb>
            </Track.Thumb>
            <Track.IncreaseRepeatButton>
                <RepeatButton Style="{StaticResource ScrollBarPageButton}" Command="ScrollBar.PageDownCommand" />
            </Track.IncreaseRepeatButton>
        </Track>
        <RepeatButton Grid.Row="3" Style="{StaticResource ScrollBarLineButton}" Height="18" Command="ScrollBar.LineDownCommand" Content="M 0 0 L 4 4 L 8 0 Z" />
    </Grid>
</ControlTemplate>

[重新编辑]我尝试为标记画布创建一个单独的类,用于ObservableCollection。请注意,目前,这不起作用

XAML仍然与昨天一样:

<helpers:MarkerCollectionCanvas 
         x:Name="SearchMarkerCanvas" 
         Grid.Row="1" 
         Grid="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"
         MarkerCollection="{Binding Source={x:Static helpers:MyClass.Instance}, Path=SearchMarkers}"/>

Canvas类,ObservableCollection更改为使用object而不是double,MarkerCollectionCanvas_CollectionChanged中有一个console.writeline,从未调用过:

class MarkerCollectionCanvas : Canvas
{
    public DataGrid Grid
    {
        get { return (DataGrid)GetValue(GridProperty); }
        set { SetValue(GridProperty, value); }
    }

    public static readonly DependencyProperty GridProperty =
        DependencyProperty.Register("Grid", typeof(DataGrid), typeof(MarkerCollectionCanvas), new PropertyMetadata(null));

    public ObservableCollection<object> MarkerCollection
    {
        get { return (ObservableCollection<object>)GetValue(MarkerCollectionProperty); }
        set { SetValue(MarkerCollectionProperty, value); }
    }

    public static readonly DependencyProperty MarkerCollectionProperty =
        DependencyProperty.Register("MarkerCollection", typeof(ObservableCollection<object>), typeof(MarkerCollectionCanvas), new PropertyMetadata(null, OnCollectionChanged));

    private static void OnCollectionChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        MarkerCollectionCanvas canvas = d as MarkerCollectionCanvas;

        if (e.NewValue != null)
        {
            (e.NewValue as ObservableCollection<object>).CollectionChanged += canvas.MarkerCollectionCanvas_CollectionChanged;
        }
        if (e.OldValue != null)
        {
            (e.NewValue as ObservableCollection<object>).CollectionChanged -= canvas.MarkerCollectionCanvas_CollectionChanged;
        }
    }

    void MarkerCollectionCanvas_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        Console.WriteLine("InvalidateVisual");
        InvalidateVisual();
    }

    public Brush MarkerBrush
    {
        get { return (Brush)GetValue(MarkerBrushProperty); }
        set { SetValue(MarkerBrushProperty, value); }
    }

    public static readonly DependencyProperty MarkerBrushProperty =
        DependencyProperty.Register("MarkerBrush", typeof(Brush), typeof(MarkerCollectionCanvas), new PropertyMetadata(Brushes.DarkOrange));

    protected override void OnRender(System.Windows.Media.DrawingContext dc)
    {
        base.OnRender(dc);

        if (Grid == null || MarkerCollection == null)
            return;

        //Get all items
        object[] items = new object[Grid.Items.Count];
        Grid.Items.CopyTo(items, 0);

        //Get all selected items
        object[] selection = new object[MarkerCollection.Count];
        MarkerCollection.CopyTo(selection, 0);

        Dictionary<object, int> indexes = new Dictionary<object, int>();

        for (int i = 0; i < selection.Length; i++)
        {
            indexes.Add(selection[i], 0);
        }

        int itemCounter = 0;
        for (int i = 0; i < items.Length; i++)
        {
            object item = items[i];
            if (indexes.ContainsKey(item))
            {
                indexes[item] = i;
                itemCounter++;
            }
            if (itemCounter >= selection.Length)
                break;
        }

        double translateDelta = ActualHeight / (double)items.Length;
        double width = ActualWidth;
        double height = Math.Max(translateDelta, 4);
        Brush dBrush = MarkerBrush;
        double previous = 0;

        IEnumerable<int> sortedIndex = indexes.Values.OrderBy(v => v);

        foreach (int itemIndex in sortedIndex)
        {
            double top = itemIndex * translateDelta;
            if (top < previous)
                continue;

            dc.DrawRectangle(dBrush, null, new Rect(0, top, width, height));
            previous = (top + height) - 1;
        }
    }
}
类标记集合画布:画布
{
公共数据网格
{
获取{return(DataGrid)GetValue(GridProperty);}
set{SetValue(GridProperty,value);}
}
公共静态只读DependencyProperty GridProperty=
DependencyProperty.Register(“网格”、typeof(DataGrid)、typeof(MarkerCollectionCanvas)、new PropertyMetadata(null));
公共可观测集合标记集合
{
获取{return(observeCollection)GetValue(MarkerCollectionProperty);}
set{SetValue(MarkerCollectionProperty,value);}
}
公共静态只读从属属性MarkerCollectionProperty=
DependencyProperty.Register(“MarkerCollection”、typeof(ObservableCollection)、typeof(MarkerCollectionCanvas)、new PropertyMetadata(null、OnCollectionChanged));
CollectionChanged上的私有静态无效(DependencyObject d、DependencyPropertyChangedEventArgs e)
{
MarkerCollectionCanvas canvas=d作为MarkerCollectionCanvas;
如果(如NewValue!=null)
{
(e.NewValue作为ObservableCollection)。CollectionChanged+=canvas.MarkerCollectionCanvas\u CollectionChanged;
}
如果(e.OldValue!=null)
{
(e.NewValue作为ObservableCollection)。CollectionChanged-=canvas.MarkerCollectionCanvas\u CollectionChanged;
}
}
void MarkerCollectionCanvas_CollectionChanged(对象发送方,NotifyCollectionChangedEventArgs e)
{
控制台。写入线(“无效”);
无效的(通常的);
}
毛刷
{
获取{return(Brush)GetValue(MarkerBrushProperty);}
set{SetValue(MarkerBrushProperty,value);}
}
公共静态只读从属属性MarkerBrushProperty=
DependencyProperty.Register(“MarkerBrush”、typeof(Brush)、typeof(MarkerCollectionCanvas)、new PropertyMetadata(Brush.DarkOrange));
受保护的覆盖无效OnRender(System.Windows.Media.DrawingContext dc)
{
base.OnRender(dc);
如果(网格==null | |标记集合==null)
返回;
//获取所有项目
object[]items=新对象[Grid.items.Count];
Grid.Items.CopyTo(Items,0);
//获取所有选定项目
object[]selection=新对象[MarkerCollection.Count];
MarkerCollection.CopyTo(选择,0);
字典索引=新字典();
for(int i=0;i=selection.Length)
打破
}
双平移LTA=实际高度/(双)项长度;
双倍宽度=实际宽度;
双倍高度=数学最大值(translateDelta,4);
笔刷dBrush=MarkerBrush;
双倍上一次=0;
IEnumerable sortedIndex=索引.Values.OrderBy(v=>v);
foreach(sortedIndex中的int itemIndex)
{
双层顶部=itemIndex*translateDelta;
如果(顶部<上一个)
继续;
DrawRectangle(dBrush,null,新矩形(0,顶部,宽度,高度));
先前=(顶部+高度)-1;
}
}
}
这是我的singleton类,其中包含搜索标记:

public class MyClass : INotifyPropertyChanged
{
    public static ObservableCollection<object> m_searchMarkers = new ObservableCollection<object>();
    public ObservableCollection<object> SearchMarkers
    {
        get
        {
            return m_searchMarkers;
        }
        set
        {
            m_searchMarkers = value;
            NotifyPropertyChanged();
        }
    }

    private static MyClass m_Instance;
    public static MyClass Instance
    {
        get
        {
            if (m_Instance == null)
            {
                m_Instance = new MyClass();
            }

            return m_Instance;
        }
    }

    private MyClass()
    {
    }

    public event PropertyChangedEventHandler PropertyChanged;

    private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}
公共类MyClass:INotifyPropertyChanged
{
公共静态ObservableCollection m_searchMarkers=新ObservableCollection();
公共可观测收集搜索标记
{
得到
{
返回m_搜索标记;
}
设置
{
m_=值;
NotifyPropertyChanged();
}
}
私有静态MyClass m_实例;
公共静态MyClass实例
{
得到
{
if(m_实例==null)
{
m_实例=新的MyClass();
}
返回m_实例;
}
}
私有MyClass()
{
}
公共事件属性更改事件处理程序属性更改;
私有void NotifyPropertyChanged([CallerMemberName]字符串propertyName=”“)
{
if(PropertyChanged!=null)
{
PropertyChanged(这是新的PropertyChangedEventArgs(propertyName));
}
}
}
这是一个文本框文本更改行为。这是ObservableCollection搜索标记填充的地方

public class FindTextChangedBehavior : Behavior<TextBox>
{
    protected override void OnAttached()
    {
        base.OnAttached();
        AssociatedObject.TextChanged += OnTextChanged;
    }

    protected override void OnDetaching()
    {
        AssociatedObject.TextChanged -= OnTextChanged;
        base.OnDetaching();
    }

    private void OnTextChanged(object sender, TextChangedEventArgs args)
    {
        var textBox = (sender as TextBox);
        if (textBox != null)
        {
            DataGrid dg = DataGridObject as DataGrid;
            string searchValue = textBox.Text;

            if (dg.Items.Count > 0)
            {
                var columnBoundProperties = new List<KeyValuePair<int, string>>();

                IEnumerable<DataGridColumn> visibleColumns = dg.Columns.Where(c => c.Visibility == System.Windows.Visibility.Visible);

                foreach (var col in visibleColumns)
                {
                    if (col is DataGridTextColumn)
                    {
                        var binding = (col as DataGridBoundColumn).Binding as Binding;
                        columnBoundProperties.Add(new KeyValuePair<int, string>(col.DisplayIndex, binding.Path.Path));
                    }
                    else if (col is DataGridComboBoxColumn)
                    {
                        DataGridComboBoxColumn dgcbc = (DataGridComboBoxColumn)col;
                        var binding = dgcbc.SelectedItemBinding as Binding;
                        columnBoundProperties.Add(new KeyValuePair<int, string>(col.DisplayIndex, binding.Path.Path));
                    }
                }

                Type itemType = dg.Items[0].GetType();
                if (columnBoundProperties.Count > 0)
                {
                    ObservableCollection<Object> tempItems = new ObservableCollection<Object>();
                    var itemsSource = dg.Items as IEnumerable;
                    Task.Factory.StartNew(() =>
                    {
                        ClassPropTextSearch.init(itemType, columnBoundProperties);
                        if (itemsSource != null)
                        {
                            foreach (object o in itemsSource)
                            {
                                if (ClassPropTextSearch.Match(o, searchValue))
                                {
                                    tempItems.Add(o);
                                }
                            }
                        }
                    })
                    .ContinueWith(t =>
                    {
                        Application.Current.Dispatcher.Invoke(new Action(() => MyClass.Instance.SearchMarkers = tempItems));
                    });
                }
            }
        }
    }

    public static readonly DependencyProperty DataGridObjectProperty =
        DependencyProperty.RegisterAttached("DataGridObject", typeof(DataGrid), typeof(FindTextChangedBehavior), new UIPropertyMetadata(null));

    public object DataGridObject
    {
        get { return (object)GetValue(DataGridObjectProperty); }
        set { SetValue(DataGridObjectProperty, value); }
    }
}
公共类FindTextChangedBehavior:行为
{
受保护的覆盖无效附加()
{
base.onatached();
AssociatedObject.TextChanged+=OnTextChanged;
}
附加时受保护的覆盖无效()
{
AssociatedObject.TextChanged-=OnTextChanged;
base.OnDetaching();
}
私有void OnTextChanged(对象发送方,textchangedventargs args)
{
变量文本框=(
public class FindTextChangedBehavior : Behavior<TextBox>
{
    protected override void OnAttached()
    {
        base.OnAttached();
        AssociatedObject.TextChanged += OnTextChanged;
    }

    protected override void OnDetaching()
    {
        AssociatedObject.TextChanged -= OnTextChanged;
        base.OnDetaching();
    }

    private void OnTextChanged(object sender, TextChangedEventArgs args)
    {
        var textBox = (sender as TextBox);
        if (textBox != null)
        {
            DataGrid dg = DataGridObject as DataGrid;
            string searchValue = textBox.Text;

            if (dg.Items.Count > 0)
            {
                var columnBoundProperties = new List<KeyValuePair<int, string>>();

                IEnumerable<DataGridColumn> visibleColumns = dg.Columns.Where(c => c.Visibility == System.Windows.Visibility.Visible);

                foreach (var col in visibleColumns)
                {
                    if (col is DataGridTextColumn)
                    {
                        var binding = (col as DataGridBoundColumn).Binding as Binding;
                        columnBoundProperties.Add(new KeyValuePair<int, string>(col.DisplayIndex, binding.Path.Path));
                    }
                    else if (col is DataGridComboBoxColumn)
                    {
                        DataGridComboBoxColumn dgcbc = (DataGridComboBoxColumn)col;
                        var binding = dgcbc.SelectedItemBinding as Binding;
                        columnBoundProperties.Add(new KeyValuePair<int, string>(col.DisplayIndex, binding.Path.Path));
                    }
                }

                Type itemType = dg.Items[0].GetType();
                if (columnBoundProperties.Count > 0)
                {
                    ObservableCollection<Object> tempItems = new ObservableCollection<Object>();
                    var itemsSource = dg.Items as IEnumerable;
                    Task.Factory.StartNew(() =>
                    {
                        ClassPropTextSearch.init(itemType, columnBoundProperties);
                        if (itemsSource != null)
                        {
                            foreach (object o in itemsSource)
                            {
                                if (ClassPropTextSearch.Match(o, searchValue))
                                {
                                    tempItems.Add(o);
                                }
                            }
                        }
                    })
                    .ContinueWith(t =>
                    {
                        Application.Current.Dispatcher.Invoke(new Action(() => MyClass.Instance.SearchMarkers = tempItems));
                    });
                }
            }
        }
    }

    public static readonly DependencyProperty DataGridObjectProperty =
        DependencyProperty.RegisterAttached("DataGridObject", typeof(DataGrid), typeof(FindTextChangedBehavior), new UIPropertyMetadata(null));

    public object DataGridObject
    {
        get { return (object)GetValue(DataGridObjectProperty); }
        set { SetValue(DataGridObjectProperty, value); }
    }
}
class MarkerCanvas : Canvas
{
    public DataGrid Grid
    {
        get { return (DataGrid)GetValue(GridProperty); }
        set { SetValue(GridProperty, value); }
    }

    // Using a DependencyProperty as the backing store for Grid.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty GridProperty =
        DependencyProperty.Register("Grid", typeof(DataGrid), typeof(MarkerCanvas), new PropertyMetadata(null, OnGridChanged));

    private static void OnGridChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        MarkerCanvas canvas = d as MarkerCanvas;

        if (e.NewValue != null)
        {
            (e.NewValue as DataGrid).SelectionChanged += canvas.MarkerCanvas_SelectionChanged;
        }
        if (e.OldValue != null)
        {
            (e.NewValue as DataGrid).SelectionChanged -= canvas.MarkerCanvas_SelectionChanged;
        }
    }

    void MarkerCanvas_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        InvalidateVisual();
    }

    public Brush MarkerBrush
    {
        get { return (Brush)GetValue(MarkerBrushProperty); }
        set { SetValue(MarkerBrushProperty, value); }
    }

    // Using a DependencyProperty as the backing store for MarkerBrush.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty MarkerBrushProperty =
        DependencyProperty.Register("MarkerBrush", typeof(Brush), typeof(MarkerCanvas), new PropertyMetadata(Brushes.SlateGray));


    protected override void OnRender(System.Windows.Media.DrawingContext dc)
    {
        base.OnRender(dc);

        if (Grid==null || Grid.SelectedItems == null)
            return;

        object[] markers = Grid.SelectedItems.OfType<object>().ToArray();
        double translateDelta = ActualHeight / (double)Grid.Items.Count;
        double width = ActualWidth;
        double height = Math.Max(translateDelta, 4);
        Brush dBrush = MarkerBrush;

        for (int i = 0; i < markers.Length; i++)
        {
            double itemIndex = Grid.Items.IndexOf(markers[i]);
            double top = itemIndex * translateDelta;

            dc.DrawRectangle(dBrush, null, new Rect(0, top, width, height));
        }
    }
}
<helpers:MarkerCanvas Grid.Row="1" Grid="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"/>
protected override void OnRender(System.Windows.Media.DrawingContext dc)
{
    base.OnRender(dc);

    if (Grid==null || Grid.SelectedItems == null)
        return;

    object[] markers = Grid.SelectedItems.OfType<object>().ToArray();
    double translateDelta = ActualHeight / (double)Grid.Items.Count;
    double width = ActualWidth;
    double height = Math.Max(translateDelta, 4);
    Brush dBrush = MarkerBrush;
    double previous = 0;

    for (int i = 0; i < markers.Length; i++)
    {
        double itemIndex = Grid.Items.IndexOf(markers[i]);
        double top = itemIndex * translateDelta;
        if (top < previous)
            continue;
        dc.DrawRectangle(dBrush, null, new Rect(0, top, width, height));
        previous = (top + height) - 1;
    }
}
protected override void OnRender(System.Windows.Media.DrawingContext dc)
{
    base.OnRender(dc);

    if (Grid == null || Grid.SelectedItems == null)
        return;

    object[] items = new object[Grid.Items.Count];
    Grid.Items.CopyTo(items, 0);

    object[] selection = new object[Grid.SelectedItems.Count];
    Grid.SelectedItems.CopyTo(selection, 0);

    Dictionary<object, int> indexes = new Dictionary<object, int>();

    for (int i = 0; i < selection.Length; i++)
    {
        indexes.Add(selection[i], 0);
    }

    int itemCounter = 0;
    for (int i = 0; i < items.Length; i++)
    {
        object item = items[i];
        if (indexes.ContainsKey(item))
        {
            indexes[item] = i;
            itemCounter++;
        }
        if (itemCounter >= selection.Length)
            break;
    }

    double translateDelta = ActualHeight / (double)items.Length;
    double width = ActualWidth;
    double height = Math.Max(translateDelta, 4);
    Brush dBrush = MarkerBrush;
    double previous = 0;

    IEnumerable<int> sortedIndex = indexes.Values.OrderBy(v => v);

    foreach (int itemIndex in sortedIndex)
    {
        double top = itemIndex * translateDelta;
        if (top < previous)
            continue;

        dc.DrawRectangle(dBrush, null, new Rect(0, top, width, height));
        previous = (top + height) - 1;
    }
}
protected override void OnRender(System.Windows.Media.DrawingContext dc)
{
    base.OnRender(dc);

    if (Grid == null || Grid.SelectedItems == null)
        return;

    List<int> indexes = new List<int>();
    double translateDelta = ActualHeight / (double)Grid.Items.Count;
    double height = Math.Max(translateDelta, 4);
    int itemInOneRect = (int)Math.Floor(height / translateDelta);
    itemInOneRect -= (int)(itemInOneRect * 0.2);
    if (Grid.SelectedItems.Count == Grid.Items.Count)
    {
        for (int i = 0; i < Grid.Items.Count; i += itemInOneRect)
        {
            indexes.Add(i);
        }
    }
    else
    {
        FieldInfo fi = Grid.GetType().GetField("_selectedItems", BindingFlags.NonPublic | BindingFlags.FlattenHierarchy | BindingFlags.Instance);
        IEnumerable<object> internalSelectionList = fi.GetValue(Grid) as IEnumerable<object>;
        PropertyInfo pi = null;
        int lastIndex = int.MinValue;
        foreach (var item in internalSelectionList)
        {
            if (pi == null)
            {
                pi = item.GetType().GetProperty("Index", BindingFlags.Instance | BindingFlags.NonPublic);
            }
            int newIndex = (int)pi.GetValue(item);
            if (newIndex > (lastIndex + itemInOneRect))
            {
                indexes.Add(newIndex);
                lastIndex = newIndex;
            }
        }
        indexes.Sort();
    }

    double width = ActualWidth;
    Brush dBrush = MarkerBrush;

    foreach (int itemIndex in indexes)
    {
        double top = itemIndex * translateDelta;
        dc.DrawRectangle(dBrush, null, new Rect(0, top, width, height));
    }
}