Creating an AttachedProperty to hold positions for scrollbar markers

五迷三道 提交于 2019-12-04 21:19:49

I attempted to achieve your desired result

so for that I have made some changes, I've commented where I have made changes

add this converter reference to the resources

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

Items control xaml which is showing the markers

    <!-- added Grid.Row="1", removed other attributes, removed the ItemsControlBeahviors, not much needed-->
    <ItemsControl Grid.Row="1" Name="ItemsSelected"
                  ItemsSource="{Binding Source={x:Static helpers:MyClass.Instance}, Path=SelectedMarkers}">
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <!--you can optionally bind height to scale accordingly if needed-->
                <Rectangle Fill="#99708090" Width="18" Height="4">
                    <Rectangle.RenderTransform>
                        <!--added a translate transform-->
                        <TranslateTransform>
                            <TranslateTransform.Y>
                                <!--multi binded Y to the item and the actual height of MarkerItems control using the new MarkerPositionConverter-->
                                <MultiBinding Converter="{StaticResource MarkerPositionConverter}">
                                    <Binding/>
                                    <Binding Path="ActualHeight" ElementName="ItemsSelected"/>
                                </MultiBinding>
                            </TranslateTransform.Y>
                        </TranslateTransform>
                    </Rectangle.RenderTransform>
                </Rectangle>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <Canvas/>
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
    </ItemsControl>

behavior.cs

public class DataGridBehaviors : Behavior<DataGrid>
{
    ...

    void DataGrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        MyClass.Instance.SelectedMarkers.Clear();
        //updated item count
        MyClass.Instance.ItemCount = this.AssociatedObject.Items.Count;
        foreach (object o in this.AssociatedObject.SelectedItems)
            MyClass.Instance.SelectedMarkers.Add(this.AssociatedObject.Items.IndexOf(o));
    }
}

//removed ItemsControlBeahviors

public class MyClass : INotifyPropertyChanged
{
    ...

    //added item count property
    public int ItemCount { get; set; }

    ...
}

//added class to perform the index to translate conversion
public class MarkerPositionConverter: IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        //calculated the transform values based on the following
        double itemIndex = (double)values[0];
        double trackHeight = (double)values[1];
        double translateDelta = trackHeight / MyClass.Instance.ItemCount;
        return itemIndex * translateDelta;
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

now you may customize it as per your needs

Remove flicker

the flicker is due to the initial placement of the rectangle and before the binding gets all of its values so to avoid this initial intermittent flicker use this

    <!--added fallback value to avoid intermittent value-->
    <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>

so I placed the rectangle out of the view by pushing it back 1000 px when any of the binded property is busy in resolving the value or does not have any value.

and in items panel template (optional)

    <ItemsPanelTemplate>
        <!--added ClipToBounds to be extra safe-->
        <Canvas ClipToBounds="True"/>
    </ItemsPanelTemplate>

since the canvas by default does not clip its children, set ClipToBounds to true to be safe. this is necessary when the flicker is still visible somewhere in the UI even after using a huge fallback value.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!