IScrollProvider的Automation Peer始终为null

时间:2012-05-17 14:06:17

标签: c# wpf silverlight automation scroll

我正在尝试实现一种方法,将数据网格的滚动条移回到此示例http://www.codeproject.com/Articles/109531/Controlling-and-Viewing-the-ScrollBar-Positions-of之后的前一个位置,但此方法始终返回null,因此无法创建自动化。有没有人知道为什么这总是会返回null?

    public static IScrollProvider GetScrollProvider(DataGrid grid)
    {
        var p = FrameworkElementAutomationPeer.FromElement(grid)
            ?? FrameworkElementAutomationPeer.CreatePeerForElement(grid);
        return p.GetPattern(PatternInterface.Scroll) as IScrollProvider;
    }

2 个答案:

答案 0 :(得分:1)

古代历史,但至少目前的版本似乎在所有情况下都像魅力一样。

//p.GetPattern(PatternInterface.Scroll) as IScrollProvider;
{System.Windows.Automation.Peers.DataGridAutomationPeer}
    [System.Windows.Automation.Peers.DataGridAutomationPeer]: 
        {System.Windows.Automation.Peers.DataGridAutomationPeer}
    HorizontallyScrollable: true
    HorizontalScrollPercent: 0.0
    HorizontalViewSize: 81.44329896907216
    VerticallyScrollable: true
    VerticalScrollPercent: 29.062733871459486
    VerticalViewSize: 2.9625

答案 1 :(得分:0)

我知道它是一个旧帖子,但万一有人带着同样的问题来到这里,(像我一样),这就是我解决它的方法:

出于某种原因,当您使用DataGrid的滚动条时,如果用户还没有滚动,它将通知最大位置为0,即使它不是。所以我在更新之前保存了最大值,并在之后恢复它:

首先我创建一个类来保存这些值。它可能是变量,但是一个类似乎更有条理:

public static ScrollInfo GetScrollInfo(this DataGrid grid)
{
    ScrollInfo oInfo = new ScrollInfo();

    ScrollBar sbHorizontal = grid.GetScrollbar(ScrollMode.Horizontal);
    oInfo.HorizontalMaximum = sbHorizontal.Maximum;
    oInfo.HorizontalPosition = sbHorizontal.Value;

    ScrollBar sbVertical = grid.GetScrollbar(ScrollMode.Vertical);
    oInfo.VerticalMaximum = sbVertical.Maximum;
    oInfo.VerticalPosition = sbVertical.Value;

    return oInfo;
}

在更新ItemSource属性之前,我使用此方法保存滚动信息:

public static void SetScrollPosition(this DataGrid grid, ScrollInfo info)
{
    if (info.HorizontalPosition > 0)
    {
        ScrollBar sbHorizontal = grid.GetScrollbar(ScrollMode.Horizontal);
        sbHorizontal.Maximum = info.HorizontalMaximum;
        grid.Scroll(ScrollMode.Horizontal, info.HorizontalPosition);
    }

    if (info.VerticalPosition > 0)
    {
        ScrollBar sbVertical = grid.GetScrollbar(ScrollMode.Vertical);
        sbVertical.Maximum = info.VerticalMaximum;            
        grid.Scroll(ScrollMode.Vertical, info.VerticalPosition);
    }
}

然后我调用此方法在更新后将此信息设置回网格:

public static void UpdateItemSource(this DataGrid grid, IEnumerable itemSource)
{
    ScrollInfo oInfo = grid.GetScrollInfo();
    grid.ItemsSource = itemSource;
    grid.SetScrollPosition(oInfo);
}

我甚至创建了一个UpdateItemSource方法来简化操作:

public static void Scroll(this DataGrid grid, ScrollMode mode, double position)
{
    // Get the scrollbar and convert the position to percent.
    var scrollBar = grid.GetScrollbar(mode);
    double positionPct = ((position / scrollBar.Maximum) * 100);

    // Scroll to a specfic percentage of the scrollbar.
    grid.ScrollToPercent(mode, positionPct);
}

public static void ScrollToPercent(this DataGrid grid, ScrollMode mode, double percent)
{
    // Fix the percentage.
    if (percent < 0)
        percent = 0;
    else if (percent > 100)
        percent = 100;

    // Get the scroll provider.
    var scrollProvider = GetScrollProvider(grid);

    // Scroll.
    switch (mode)
    {
        case ScrollMode.Vertical:                        
            scrollProvider.SetScrollPercent( System.Windows.Automation.ScrollPatternIdentifiers.NoScroll, percent);
            break;
        case ScrollMode.Horizontal:
            scrollProvider.SetScrollPercent(percent, System.Windows.Automation.ScrollPatternIdentifiers.NoScroll);
            break;
    }
}

我使用的其他方法,我想我会从发布问题的用户的同一帖子中提到:

class FooBehavior : Behavior<Foo>
{
    public static readonly DependencyProperty FooPropProperty = DependencyProperty.Register("FooProp", typeof(string), typeof(FooBehavior),
                                                                                        new FrameworkPropertyMetadata(FooPropProperty_Changed)
                                                                                        {
                                                                                            BindsTwoWayByDefault = true,
                                                                                            DefaultUpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged
                                                                                        });

    public String FooProp { get { return (string)GetValue(FooPropProperty); } set { SetValue(FooPropProperty, value); } }

    private static void FooPropProperty_Changed(object sender, DependencyPropertyChangedEventArgs args)
    {
        /* re-entrancy check done here*/
        // ...

        if (/* args.NewValue is something bad that I can't use */)
            FooProp = (string)args.OldValue;

        try
        {
            /* do stuff here that might throw */
        }
        catch
        {
            FooProp = /* some known good value */;
            throw;
        }
    }
}