2010-08-03 5 views
2

Hey SO, vous avez une question sur le contrôle TreeView dans Silverlight.Silverlight TreeView ScrollViewer Problème

J'ai une application qui ajoute dynamiquement des éléments à une arborescence. Certains éléments sont assez longs pour nécessiter un défilement horizontal. Quand ils sont ajoutés à l'arborescence, ma vue d'arborescence reste correctement défilée à gauche, donc vous devez faire défiler pour voir la fin de l'élément. Cependant, si je clique sur un de mes objets (qui cache l'arborescence), puis que j'utilise le bouton "retour aux résultats" (notez que cela ne concerne que les changements de visibilité), l'arborescence devient visible et défile automatiquement centre.

Est-ce que quelqu'un sait comment je peux faire en sorte que l'arborescence défile tout le chemin à gauche quand je reviens aux résultats?

J'ai essayé de jouer avec le modèle de TreeView:

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

Mais le problème avec cela est que je ne sais pas comment accéder au ScrollViewer du code derrière ... donc je ne peux pas appeler ScrollView.setScrollOffset (0d, 0d) ou quelque chose comme ça.

Des idées? Merci un million. Une dernière chose, je voudrais essayer d'éviter d'implémenter un nouveau contrôle qui étend treeview. J'espère vraiment qu'il existe un moyen d'accéder/modifier et utiliser les fonctions associées au modèle de contrôle de C# codebehind.

Répondre

0

Je viens de créer une propriété jointe pour cela et créer la logique que vous voulez là-bas. Ensuite, vous décorer votre arbre avec la propriété ci-jointe. Nous faisons quelque chose de similaire avec d'autres contrôles qui contiennent 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); 
      } 
     } 
} 
+0

Désolé, ça sonne peut fonctionner, mais vous allez devoir m'aider un peu plus. Pourriez-vous montrer comment je les utilise? Merci, si cela fonctionne, je vous dois ma vie! – NickHalden

0

Je mets ce code dans un comportement (fonctionne également dans le code derrière) après avoir manipulé l'événement SelectedItemChanged du TreeView:

var offset = this.HorizontalScrollOffsetAfterSelect; // would be 0 if you don't want to make that adjustable 
if (!Double.IsNaN(offset)) 
{ 
    var scrollViewer = trv.GetVisualDescendants().OfType<ScrollViewer>().FirstOrDefault(); 
    if (scrollViewer != null) 
    { 
     scrollViewer.ScrollToHorizontalOffset(offset); 
     // and because that wasn't enough because of timing issues: 
     var scrollBar = scrollViewer.GetVisualDescendants().OfType<ScrollBar>().Where(cur => cur.Orientation == Orientation.Horizontal).FirstOrDefault(); 
     if (scrollBar != null) 
     { 
      RoutedPropertyChangedEventHandler<double> handler = null; 
      handler = (sender, e) => 
       { 
        scrollBar.ValueChanged -= handler; 

        scrollViewer.ScrollToHorizontalOffset(offset); 
       }; 
      scrollBar.ValueChanged += handler; 
     } 
    } 
} 

requis using System.Linq; et using System.Windows.Controls.Primitives; et le Toolkit ofc.

Fonctionne assez bien pour moi jusqu'ici.