Создание AttachedProperty для хранения позиций маркеров полосы прокрутки

Я создал слегка настроенную вертикальную полосу прокрутки для своего DataGrid. В нем я добавил ItemsControl для хранения позиций выбранных элементов. Вот макет с жестко запрограммированными маркерами. введите здесь описание изображения

Ниже приведен мой настраиваемый шаблон вертикальной полосы прокрутки, где ItemsControl размещен с жестко закодированными значениями маркера.

<ControlTemplate x:Key="VertScrollBar" 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" />
        <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>
        <!-- BEGIN -->
        <ItemsControl Grid.Column="0" VerticalAlignment="Stretch" Name="ItemsSelected">
            <sys:Double>30</sys:Double>
            <sys:Double>70</sys:Double>
            <sys:Double>120</sys:Double>
            <sys:Double>170</sys:Double>
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <Rectangle Fill="SlateGray" Width="18" Height="4"/>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
            <ItemsControl.ItemContainerStyle>
                <Style TargetType="ContentPresenter">
                    <Setter Property="Canvas.Top" Value="{Binding}" />
                </Style>
            </ItemsControl.ItemContainerStyle>
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <Canvas/>
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
        </ItemsControl>
        <!-- END -->
        <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>

Далее я пытаюсь создать AttachedProperty для хранения позиций маркеров и привязать его обратно к ItemsControl.

Чего я действительно не понимаю, так это:
– Каким должно быть это прикрепленное свойство Type, ObservableCollection из int?
– Поскольку это руководство по общему количеству выбранных элементов в DataGrid, укажите позиции маркеры нужно как-то масштабировать?
- У меня есть прикрепленное поведение, которое захватывает DataGrid.SelectionChanged, но что, если основная коллекция изменится, и для этого не будет события?

[ИЗМЕНИТЬ]

Для прямой привязки к DataGrids SelectedItems. (Однако в верхней части ItemsControl появляется мерцание, когда что-то выбрано)
 – Удалите или закомментируйте поведение SelectionChanged.
– Измените ItemSource на:

ItemsSource="{Binding ElementName=GenericDataGrid, Path=SelectedItems}"

- Измените мультипривязку на:

<MultiBinding Converter="{StaticResource MarkerPositionConverter}">
    <Binding/>
    <Binding RelativeSource="{RelativeSource AncestorType={x:Type DataGrid}}" />
    <Binding Path="ActualHeight" ElementName="ItemsSelected"/>
    <Binding Path="Items.Count" ElementName="GenericDataGrid"/>
</MultiBinding>

- И, наконец, конвертер в:

public class MarkerPositionConverter: IMultiValueConverter
{
    //Performs the index to translate conversion
    public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        //calculated the transform values based on the following
        object o = (object)values[0];
        DataGrid dg = (DataGrid)values[1];
        double itemIndex = dg.Items.IndexOf(o);
        double trackHeight = (double)values[2];
        int itemCount = (int)values[3];
        double translateDelta = trackHeight / itemCount;
        return itemIndex * translateDelta;
    }

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

person Hank    schedule 12.06.2014    source источник
comment
у вас есть что-то вроде свойства IsSelected в вашей модели просмотра? возможно, вы можете использовать то же самое. масштабирование может быть достигнуто путем манипулирования фактической высотой по количеству элементов.   -  person pushpraj    schedule 12.06.2014
comment
@pushpraj спасибо, нет привязки модели представления к IsSelected, к сожалению, не работает с виртуализированными элементами. Да, хорошее замечание о масштабировании. Любые идеи о создании поведения для коллекции, измененного в сетке данных?   -  person Hank    schedule 12.06.2014
comment
В прошлом я делал несколько проектов, связанных с графикой, которые включали масштабирование и т. Д. У меня есть хороший опыт работы с масштабированным графиком. Можете ли вы поделиться рабочим образцом вашего кода? могу ли я взглянуть на возможности.   -  person pushpraj    schedule 12.06.2014
comment
Это возможно, хотя я пробовал это раньше, и это не одобряется, вы уверены? Мой проект обширен, поэтому мне придется сократить его до площади.   -  person Hank    schedule 12.06.2014
comment
да, пожалуйста, удалите свой код, который может быть чувствительным или не нужным для соответствующей проблемы.   -  person pushpraj    schedule 12.06.2014
comment
ссылка говорит, что файл не найден ..!! Вернитесь назад   -  person pushpraj    schedule 14.06.2014
comment
@pushpraj Я не уверен, что там произошло, я попробовал еще раз: freeuploadsite.com/ do.php?id=44230   -  person Hank    schedule 14.06.2014
comment
Как у вас дела, нормально ли скачалось?   -  person Hank    schedule 14.06.2014
comment
была какая-то проблема с этим, я использовал прокси для загрузки. В следующий раз, когда вы загрузите код, вы можете удалить из него все исполняемые файлы. в противном случае он классифицируется как вредоносный. Кстати, решение удовлетворило ваши потребности?   -  person pushpraj    schedule 14.06.2014
comment
Однако я сделал замечание в комментарии под вашим ответом, просто интересно, получаете ли вы те же результаты и знаете ли вы, что может быть причиной этого.   -  person Hank    schedule 14.06.2014


Ответы (1)


Я пытался добиться желаемого результата

так что для этого я внес некоторые изменения, я прокомментировал, где я внес изменения

добавьте ссылку на этот конвертер в ресурсы

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

Элементы управляют xaml, который показывает маркеры

    <!-- 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>

поведение.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();
    }
}

теперь вы можете настроить его в соответствии с вашими потребностями

Удалить мерцание

мерцание связано с начальным размещением прямоугольника и до того, как привязка получит все свои значения, поэтому, чтобы избежать этого начального прерывистого мерцания, используйте это

    <!--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>

поэтому я поместил прямоугольник за пределы представления, отодвинув его назад на 1000 пикселей, когда какое-либо из связанных свойств занято разрешением значения или не имеет никакого значения.

и в шаблоне панели элементов (необязательно)

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

поскольку холст по умолчанию не обрезает своих дочерних элементов, установите для параметра ClipToBounds значение true, чтобы быть в безопасности. это необходимо, когда мерцание все еще видно где-то в пользовательском интерфейсе даже после использования огромного запасного значения.

person pushpraj    schedule 14.06.2014
comment
Это фантастическое спасибо, я только что попробовал кое-что, вместо использования SelectedMarkers ObservableCollection, связывая ItemsSource непосредственно с SelectedItems DataGrid. Это работает, но у него есть ужасное небольшое мерцание в верхней части ItemsControl, когда что-то выбрано. Я опубликую свои изменения в редактировании вопроса - person Hank; 14.06.2014
comment
На этом все, цените свое время! - person Hank; 14.06.2014
comment
Пожалуйста, свяжитесь с нами, если вы с нетерпением ждете такой помощи. - person pushpraj; 14.06.2014
comment
Возможно, вам снова понадобится ваша помощь в этом. Краткая история: если этот DataGrid содержит около 10 000 строк, то обновление ItemsControl с помощью преобразователя 10 000 раз и такое количество прямоугольников невероятно медленно. Можете ли вы придумать что-нибудь, что помогло бы ускорить это. Возможно, ItemsControl не является решением. - person Hank; 20.06.2014
comment
Холст может помочь вам здесь с переопределенным методом рендеринга, который может обрабатывать около 100 000 примерно за 100 мс, см. этот ответ stackoverflow.com/questions/23976163/ для аналогичной проблемы - person pushpraj; 20.06.2014
comment
Спасибо, я создал новый вопрос, чтобы решить эту проблему здесь: stackoverflow.com/questions/24318971/ - person Hank; 20.06.2014