创建AttachedProperty来保存滚动条位置的标记 [英] Creating an AttachedProperty to hold positions for scrollbar markers

查看:299
本文介绍了创建AttachedProperty来保存滚动条位置的标记的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经创建了小幅定制的垂直滚动条为我的DataGrid。在这里面我已经添加了一个ItemsControl来保存选定项目的位置。这里是一个样机到目前为止通过硬编码标记。



下面,是其中的ItemsControl被放置硬编码的标志值我定制的垂直滚动条的模板

 <控件模板X:键= VertScrollBar的TargetType ={X:类型滚动条}> 
<网格和GT;
< Grid.RowDefinitions>
< RowDefinition了maxHeight =18/>
< RowDefinition高度=* 0.00001/>
< RowDefinition了maxHeight =18/>
< /Grid.RowDefinitions>
< BORDER Grid.RowSpan =3CornerRadius =2背景=#F0F0F0/>
<的RepeatButton Grid.Row =0样式={StaticResource的ScrollBarLineButton}HEIGHT =18命令=ScrollBar.LineUpCommandCONTENT =M 0 4 L 8 4 L 4 0 Z/> ;
<轨道X:NAME =PART_TrackGrid.Row =1IsDirectionReversed =真>
< Track.DecreaseRepeatButton>
<的RepeatButton样式={StaticResource的ScrollBarPageButton}命令=ScrollBar.PageUpCommand/>
< /Track.DecreaseRepeatButton>
< Track.Thumb>
<拇指风格={StaticResource的ScrollBarThumb}保证金=1,0,1,0>
< Thumb.BorderBrush>
<一个LinearGradientBrush StartPoint可以=0,0终点=1,0>
< LinearGradientBrush.GradientStops>
< GradientStopCollection>
<渐变停止颜色={DynamicResource BorderLightColor}偏移=0.0/>
<渐变停止颜色={DynamicResource BorderDarkColor}偏移=1.0/>
< / GradientStopCollection>
< /LinearGradientBrush.GradientStops>
< /一个LinearGradientBrush>
< /Thumb.BorderBrush>
< Thumb.Background>
<一个LinearGradientBrush StartPoint可以=0,0终点=1,0>
< LinearGradientBrush.GradientStops>
< GradientStopCollection>
<渐变停止颜色={DynamicResource ControlLightColor}偏移=0.0/>
<渐变停止颜色={DynamicResource ControlMediumColor}偏移=1.0/>
< / GradientStopCollection>
< /LinearGradientBrush.GradientStops>
< /一个LinearGradientBrush>
< /Thumb.Background>
< /拇指>
< /Track.Thumb>
< Track.IncreaseRepeatButton>
<的RepeatButton样式={StaticResource的ScrollBarPageButton}命令=ScrollBar.PageDownCommand/>
< /Track.IncreaseRepeatButton>
< /轨道>
<! - BEGIN - >
< ItemsControl的Grid.Column =0VerticalAlignment =拉伸NAME =ItemsSelected>
< SYS:双> 30℃/ SYS:双>
< SYS:双> 70℃/ SYS:双>
< SYS:双> 120℃,/ SYS:双>
< SYS:双> 170℃; / SYS:双>
< ItemsControl.ItemTemplate>
<&DataTemplate的GT;
<矩形填充=青灰WIDTH =18HEIGHT =4/>
< / DataTemplate中>
< /ItemsControl.ItemTemplate>
< ItemsControl.ItemContainerStyle>
<风格的TargetType =ContentPresenter>
< setter属性=Canvas.TopVALUE ={结合}/>
< /样式和GT;
< /ItemsControl.ItemContainerStyle>
< ItemsControl.ItemsPanel>
< ItemsPanelTemplate>
<帆布/>
< / ItemsPanelTemplate>
< /ItemsControl.ItemsPanel>
< / ItemsControl的>
<! - 完 - >
<的RepeatButton Grid.Row =3风格={StaticResource的ScrollBarLineButton}HEIGHT =18命令=ScrollBar.LineDownCommandCONTENT =M 0 0 L 4 4 L 8 0 Z/> ;
< /网格和GT;
< /控件模板>



我所想下一步要做的就是创建一个AttachedProperty持有标记的位置并将其绑定回。ItemsControl的



我做的不太明白的是:

- 这应该附加属性类型是什么,廉政局的一个ObservableCollection
- 因为这是一个指导,以总在DataGrid中选定的项目,做标记的位置需要以某种方式缩放

? - 我有一个附加的行为,捕获的DataGrid .SelectionChanged,而是如果主集合更改那里似乎什么都不是这个事件?





要直接绑定到DataGrid中SelectedItems。 (但是有一个在ItemsControl的顶部的闪烁选择东西的时候)

- 删除或注释掉的SelectionChanged行为

- 更改的ItemSource到:

 的ItemsSource ={绑定的ElementName = GenericDataGrid,路径= SelectedItems}

- 更改Multibinding为:

 < MultiBinding转换器= {StaticResource的MarkerPositionConverter}> 
<装订/>
<绑定的RelativeSource ={的RelativeSource AncestorType = {X:类型的DataGrid}}/>
<绑定路径=的ActualHeight的ElementName =ItemsSelected/>
<绑定路径=Items.Count的ElementName =GenericDataGrid/>
< / MultiBinding>



- 最后一点转换器:

 公共类MarkerPositionConverter:IMultiValueConverter 
{
//执行翻译转换
公共对象转换为指数(对象[]值类型TARGETTYPE,对象参数, System.Globalization.CultureInfo培养)
{
//计算基于以下
对象o =(对象)的值的变换值[0];
数据网格克=(数据网格)值[1];
双的ItemIndex = dg.Items.IndexOf(O);
双trackHeight =(双)值[2];
INT ITEMCOUNT =(int)的值[3];
双translateDelta = trackHeight / ITEMCOUNT;
返回的ItemIndex * translateDelta;
}

公共对象[] ConvertBack(对象的值,类型[] targetTypes,对象参数,System.Globalization.CultureInfo文化)
{
抛出新NotImplementedException( );
}
}


解决方案

我试图达到您想要的结果。



所以,我已经做了一些改变,我已经在这里评论我已经修改了



此转换器参考添加到资源

 <助手:MarkerPositionConverter X:键=MarkerPositionConverter/> 



项的控制XAML这正显示出标记



 <! - 加入Grid.Row =1,删除其他属性,去掉了ItemsControlBeahviors,不急需的 - > 
< ItemsControl的Grid.Row =1NAME =ItemsSelected
的ItemsSource ={绑定源= {X:静态助手:MyClass.Instance},路径= SelectedMarkers}>
< ItemsControl.ItemTemplate>
<&DataTemplate的GT;
<! - 你可以根据需要有选择绑定的高度相应地扩大 - >
<矩形填充=#99708090WIDTH =18HEIGHT =4>
< Rectangle.RenderTransform>
<! - 增加了一个翻译转换 - >
< TranslateTransform>
< TranslateTransform.Y>
<! - 多绑定Y以项目和MarkerItems的实际高度使用新MarkerPositionConverter控制 - >
< MultiBinding转换器={StaticResource的MarkerPositionConverter}>
<装订/>
<绑定路径=的ActualHeight的ElementName =ItemsSelected/>
< / MultiBinding>
< /TranslateTransform.Y>
< / TranslateTransform>
< /Rectangle.RenderTransform>
< /矩形>
< / DataTemplate中>
< /ItemsControl.ItemTemplate>
< ItemsControl.ItemsPanel>
< ItemsPanelTemplate>
<帆布/>
< / ItemsPanelTemplate>
< /ItemsControl.ItemsPanel>
< / ItemsControl的>



behavior.cs

 公共类DataGridBehaviors:行为<&DataGrid的GT; 
{
...

无效DataGrid_SelectionChanged(对象发件人,SelectionChangedEventArgs E)
{
MyClass.Instance.SelectedMarkers.Clear();
//更新项目数
MyClass.Instance.ItemCount = this.AssociatedObject.Items.Count;
的foreach(对象this.AssociatedObject.SelectedItems O)
MyClass.Instance.SelectedMarkers.Add(this.AssociatedObject.Items.IndexOf(O));
}
}

//删除ItemsControlBeahviors

公共MyClass类:INotifyPropertyChanged的
{
...

//添加项目计数财产
公众诠释ItemCount中获得{;组; }


}

//添加类来执行索引翻译转换
公共类MarkerPositionConverter:IMultiValueConverter
{
公共对象转换(对象[]值类型TARGETTYPE,对象参数,System.Globalization.CultureInfo文化)
{
//计算基于以下
双变换值的ItemIndex =(双)值[0];
双trackHeight =(双)值[1];
双translateDelta = trackHeight / MyClass.Instance.ItemCount;
返回的ItemIndex * translateDelta;
}

公共对象[] ConvertBack(对象的值,类型[] targetTypes,对象参数,System.Globalization.CultureInfo文化)
{
抛出新NotImplementedException( );
}
}

现在,你可以定制它根据您的需求



删除闪烁



闪烁是由于之前的矩形和初始位置结合得到的所有它的价值,所以为了避免这个初始间断闪烁使用本

 <! - 加入后备值,以避免间歇性的价值 - > 
< MultiBinding转换器={StaticResource的MarkerPositionConverter}FallbackValue = - 1000>
<装订/>
<绑定的RelativeSource ={的RelativeSource AncestorType = {X:类型的DataGrid}}/>
<绑定路径=的ActualHeight的ElementName =ItemsSelected/>
<绑定路径=Items.Count的ElementName =GenericDataGrid/>
< / MultiBinding>



所以我把矩形出来的观点推回1000像素当任何绑定属性正忙于解决的价值或没有任何价值。



和中的项目面板模板(可选)

 < ItemsPanelTemplate> 
<! - 加入ClipToBounds要格外安全 - >
<帆布ClipToBounds =真/>
< / ItemsPanelTemplate>



由于默认画布不夹及其子集ClipToBounds为true是安全的。当闪烁即使使用一个巨大的后备值后仍然可见某处UI,这是必要的。


I have created slightly customized vertical scrollbar for my DataGrid. In it I have added an ItemsControl to hold positions of the selected items. Here is a mockup so far with hard-coded markers.

Below is my customized vertical scrollbar template where the ItemsControl is placed with hard-coded marker values.

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

What I am trying to do next is create an AttachedProperty to hold marker positions and bind it back to the ItemsControl.

What I don't really understand is:
- What should this attached property Type be, an ObservableCollection of int's?
- As this is a guide to the total selected items in the DataGrid, do the positions of the markers need to be scaled somehow?
- I have an attached behavior that captures DataGrid.SelectionChanged, but what about if the main collection changes there doesn't seem to be an event for this?

[EDIT]

To bind directly to the DataGrids SelectedItems. (However there is a flicker in the top of the ItemsControl when something is selected)
- Remove or comment out the SelectionChanged behavior.
- Change the ItemSource to:

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

- Change Multibinding to:

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

- And lastly converter to:

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();
    }
}

解决方案

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.

这篇关于创建AttachedProperty来保存滚动条位置的标记的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆