views:

191

answers:

1

Hey SO, got a question about the TreeView control in Silverlight.

I have an application which dynamically adds elements to a treeview. Some of the elements are long enough to require horizontal scrolling. When they are added to the treeview, my treeview remains correctly all the way scrolled left so you have to scroll to see the end of the item. However, if I click on one of my items (which the hides the treeview), and then use the 'back to results' button I implemented (note this only deals with visibility changes) the treeview becomes visible and it is automatically scrolled to the center.

Does anyone know how I can get the treeview to scroll all the way left when I hit back to results?

I've tried messing with the treeview template:

<Style TargetType="controls:TreeView" x:Name="SCREW">
            <Setter Property="Background" Value="#FFFFFFFF" />
            <Setter Property="Foreground" Value="#FF000000" />
            <Setter Property="HorizontalContentAlignment" Value="Left" />
            <Setter Property="VerticalContentAlignment" Value="Top" />
            <Setter Property="Cursor" Value="Arrow" />
            <Setter Property="BorderThickness" Value="1" />
            <Setter Property="Padding" Value="1" />
            <Setter Property="BorderBrush" Value="#FF000000" />
            <Setter Property="IsTabStop" Value="True" />
            <Setter Property="TabNavigation" Value="Once" />
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="controls:TreeView" x:Name="SCREWTEMPLATE">
                        <Grid>
                            <VisualStateManager.VisualStateGroups>
                                <VisualStateGroup x:Name="CommonStates">
                                    <VisualState x:Name="Normal" />
                                    <VisualState x:Name="MouseOver" />
                                    <VisualState x:Name="Pressed" />
                                    <VisualState x:Name="Disabled" />
                                </VisualStateGroup>
                                <VisualStateGroup x:Name="FocusStates">
                                    <VisualState x:Name="Unfocused" />
                                    <VisualState x:Name="Focused" />
                                </VisualStateGroup>
                                <VisualStateGroup x:Name="ValidationStates">
                                    <VisualState x:Name="Valid" />
                                    <VisualState x:Name="InvalidUnfocused">
                                        <Storyboard>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="Validation" Storyboard.TargetProperty="Visibility">
                                                <DiscreteObjectKeyFrame KeyTime="0" Value="Visible" />
                                            </ObjectAnimationUsingKeyFrames>
                                        </Storyboard>
                                    </VisualState>
                                    <VisualState x:Name="InvalidFocused">
                                        <Storyboard>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="Validation" Storyboard.TargetProperty="Visibility">
                                                <DiscreteObjectKeyFrame KeyTime="0" Value="Visible" />
                                            </ObjectAnimationUsingKeyFrames>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ValidationToolTip" Storyboard.TargetProperty="IsOpen">
                                                <DiscreteObjectKeyFrame KeyTime="0">
                                                    <DiscreteObjectKeyFrame.Value>
                                                        <System:Boolean>True</System:Boolean>
                                                    </DiscreteObjectKeyFrame.Value>
                                                </DiscreteObjectKeyFrame>
                                            </ObjectAnimationUsingKeyFrames>
                                        </Storyboard>
                                    </VisualState>
                                </VisualStateGroup>
                            </VisualStateManager.VisualStateGroups>

                            <Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="2">
                                <Border Padding="{TemplateBinding Padding}" Background="{TemplateBinding Background}" Margin="1">
                                    <ScrollViewer x:Name="ScrollViewer" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto" Background="{x:Null}" BorderBrush="Transparent" BorderThickness="0" IsTabStop="False" TabNavigation="Once" Loaded="ScrollViewer_Loaded">
                                        <ItemsPresenter Margin="5" />
                                    </ScrollViewer>
                                </Border>
                            </Border>

                            <Border x:Name="Validation" Grid.Column="1" BorderThickness="{TemplateBinding BorderThickness}" BorderBrush="#FFDB000C" CornerRadius="2" Visibility="Collapsed">
                                <ToolTipService.ToolTip>
                                    <ToolTip x:Name="ValidationToolTip" Placement="Right" PlacementTarget="{Binding RelativeSource={RelativeSource TemplatedParent}}" DataContext="{Binding RelativeSource={RelativeSource TemplatedParent}}" IsHitTestVisible="True" />
                                </ToolTipService.ToolTip>
                                <Grid Width="10" Height="10" HorizontalAlignment="Right" Margin="0,-4,-4,0" VerticalAlignment="Top" Background="Transparent">
                                    <Path Margin="-1,3,0,0" Fill="#FFDC000C" Data="M 1,0 L6,0 A 2,2 90 0 1 8,2 L8,7 Z" />
                                    <Path Margin="-1,3,0,0" Fill="#FFFFFFFF" Data="M 0,0 L2,0 L 8,6 L8,8" />
                                </Grid>
                            </Border>
                        </Grid>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

But the problem with that is I don't know how to access the ScrollViewer from the code behind... so I can't call ScrollView.setScrollOffset(0d,0d) or anything like that.

Any ideas? Thanks a million.

One last thing, I'd like to try to avoid implementing a new control that extends treeview. I'm really hoping there is a way to access/modify and use functions associated with the control template from c# codebehind.

A: 

I'd just set up an attached property for this and create the logic you want in there. Then you would decorate your treeview with the attached property. We do something similar with other controls that contain scrollviewers:

public class ScrollResetService
{
    public static DependencyProperty IsScrollResetProperty = DependencyProperty.RegisterAttached("IsScrollReset",
                                                                                                 typeof(bool),
                                                                                                 typeof(ScrollResetService),
                                                                                                 new PropertyMetadata(false,
                                                                                                      OnIsScrollResetChanged));
    public static void SetIsScrollReset(DependencyObject d, bool value)
    {
        d.SetValue(IsScrollResetProperty, value);
    }

    public static bool GetIsScrollReset(DependencyObject d)
    {
        return d.GetValue(IsScrollResetProperty) == null ? false : (bool)d.GetValue(IsScrollResetProperty);
    }

    private static void OnIsScrollResetChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var treeView = d as TreeView;
        bool isScrollReset;
        if (e.NewValue!= null && bool.TryParse(e.NewValue.ToString(), out isScrollReset) && treeView != null)
        {

            treeView.SelectedItemChanged += (sender, args) =>
                                               {
                                                   var scrolls =
                                                       treeView.GetAllLogicalChildrenOfType<IScrollInfo>();
                                                   scrolls.ForEach(i => i.SetVerticalOffset(0));
                                               };

        }
    }

}

public static class Extensions
    {

public static IEnumerable<T> GetAllLogicalChildrenOfType<T>(this FrameworkElement parent)
        {
            Debug.Assert(parent != null, "The parent cannot be null.");
            return parent.GetVisualChildren().Flatten(item => item.GetVisualChildren()).OfType<T>();
        }

public static IEnumerable<T> Flatten<T>(this IEnumerable<T> items, Func<T, IEnumerable<T>> childSelector)
        {
            if (items == null) return Enumerable.Empty<T>();
            return items.Concat(items.SelectMany(i => childSelector(i).Flatten(childSelector)));
        }

internal static IEnumerable<DependencyObject> GetVisualChildren(this DependencyObject parent)
        {
            int childCount = VisualTreeHelper.GetChildrenCount(parent);
            for (int counter = 0; counter < childCount; counter++)
            {
                yield return VisualTreeHelper.GetChild(parent, counter);
            }
        }
}
Justice
Sorry, sounds like that could work, but you're going to have to help me a little more.Could you show how I use those? Thanks, if this works I owe you my life!
JGord