2012-04-24 25 views
12

Chciałbym zmienić właściwości ScrollViewer z ListBox z C#.Uzyskiwanie dostępu do ScrollViewer ListBox z C#

Znalazłem this question tutaj na Stackoverflow. Przyjąłem akceptowaną radę i ujawniłem ScrollViewer jako własność podklasy. Jednak nie wygląda to tak, jakby działało w przykładzie pokazanym poniżej. Niektóre komentarze w tym pytaniu również stwierdzają, że ta technika nie działa.

XAML:

<Window x:Class="StackoverflowListBoxScrollViewer.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     Title="MainWindow" Height="350" Width="525"> 

</Window> 

C#:

using System; 
using System.Windows; 
using System.Windows.Controls; 

namespace StackoverflowListBoxScrollViewer 
{ 
    public class MyListBox : ListBox 
    { 
     public ScrollViewer ScrollViewer 
     { get { return (ScrollViewer)GetTemplateChild("ScrollViewer"); } } 
    } 

    public partial class MainWindow : Window 
    { 
     public MainWindow() 
     { 
      InitializeComponent(); 

      var myListBox = new MyListBox(); 

      Content = myListBox; 

      myListBox.Items.Add(new Button() { Content = "abc" }); 
      myListBox.Items.Add(new Button() { Content = "abc" }); 
      myListBox.Items.Add(new Button() { Content = "abc" }); 
      myListBox.Items.Add(new Button() { Content = "abc" }); 
      myListBox.Items.Add(new Button() { Content = "abc" }); 

      var button = new Button() { Content = "Check ScrollViewer" }; 
      button.Click += (s, e) => 
       { 
        if (myListBox.ScrollViewer == null) 
         Console.WriteLine("null"); 
       }; 
      myListBox.Items.Add(button); 
     } 
    } 
} 

Po kliknięciu przycisku "Sprawdź ScrollViewer" drukuje "null". Tj. ScrollViewer nie został pobrany.

Jak się dostać do tego cholernie ScrollViewer? :-)

+0

Sprawdź także to http://stackoverflow.com/questions/3963341/get-reference-to-my-wpf-listboxs-scrollviewer-in-c – Klaus78

+0

... i naprawdę nie powinieneś wywoływać swojej ScrollViewer-Property "ScrollViewer". – basti

+2

@chiffre: dlaczego nie? W rzeczywistości jest to zgodne z wytycznymi dotyczącymi nazewnictwa .NET dla właściwości: ** Należy rozważyć nadanie właściwości tej samej nazwy co jej typ. ** (http://msdn.microsoft.com/en-us/library/ms229012.aspx) –

Odpowiedz

6

Jeśli użyjesz standardowego ListBox, tak możesz zmienić swój getter na ten:

public class MyListBox : ListBox 
{ 
    public ScrollViewer ScrollViewer 
    { 
     get 
     { 
      Border border = (Border)VisualTreeHelper.GetChild(this, 0); 

      return (ScrollViewer)VisualTreeHelper.GetChild(border, 0); 
     } 
    } 
} 
+1

... i naprawdę nie powinieneś nazywać swojego ScrollViewer-Property "ScrollViewer". – basti

+0

powiedz to @dharmatech :) – stukselbax

+0

Miałem nadzieję, że @dharmatech również zobaczy to w tym komentarzu. Ale: "Zrobione". ;) – basti

20

można spróbować ten mały funkcji pomocnika

Wykorzystanie

var scrollViewer = GetDescendantByType(yourListBox, typeof(ScrollViewer)) as ScrollViewer; 

funkcja pomocnika

public static Visual GetDescendantByType(Visual element, Type type) 
{ 
    if (element == null) { 
    return null; 
    } 
    if (element.GetType() == type) { 
    return element; 
    } 
    Visual foundElement = null; 
    if (element is FrameworkElement) { 
    (element as FrameworkElement).ApplyTemplate(); 
    } 
    for (int i = 0; i < VisualTreeHelper.GetChildrenCount(element); i++) { 
    Visual visual = VisualTreeHelper.GetChild(element, i) as Visual; 
    foundElement = GetDescendantByType(visual, type); 
    if (foundElement != null) { 
     break; 
    } 
    } 
    return foundElement; 
} 

Nadzieja to pomaga

+0

Wow, to jest dobre rozwiązanie @ punker76. Nie wymaga podklasy 'ListBox' tylko po to, aby dostać się do' ScrollViewer'. Kusi mnie, aby oznaczyć tę akceptowaną odpowiedź. Debata powitalna! :-) – dharmatech

+0

Świetna wersja agnostyczna. Podałem nieco zmodyfikowaną metodę rozszerzenia z zabezpieczeniem typu. (Wiem, że ten temat jest stary) – Samuel

+0

'publiczny statyczny Tracownik GetDescendant (ten element wizualny)' wyglądał ładnie tutaj, D –

1

Jeśli chodzi o mnie, ujawnienie ScrollViewera jako własności jest złym pomysłem. Po pierwsze, nie ma gwarancji, że ScrollViewer istnieje w szablonie. Po drugie, ScrollViewer działa zsynchronizowany z ItemsPanel i ItemContainerGenerator. Przesłonięcie tego jest prostą drogą do rzadkich zachowań.

Kontrolki WPF używają innego wzoru. Ich klasy są jak mediatory między zewnętrznym użyciem logicznym a wewnętrzną reprezentacją wizualną. Twój ListBox powinien eksponować właściwości, które mogą być używane przez ScrollViewer w szablonie, ale nie ScrollViewer. W ten sposób łamiecie standardy WPF, ograniczacie kontrolę do określonego szablonu i pozwalacie hakerowi włamać się do wewnętrznej implementacji ListBox.

4

Mam zmodyfikowany wielką odpowiedź @ punker76 stworzyć metodę rozszerzenia dla wizualne i zapewniają wyraźny Zwraca typ:

public static class Extensions 
    { 
     public static T GetDescendantByType<T>(this Visual element) where T:class 
     { 
     if (element == null) 
     { 
      return default(T); 
     } 
     if (element.GetType() == typeof(T)) 
     { 
      return element as T; 
     } 
     T foundElement = null; 
     if (element is FrameworkElement) 
     { 
      (element as FrameworkElement).ApplyTemplate(); 
     } 
     for (var i = 0; i < VisualTreeHelper.GetChildrenCount(element); i++) 
     { 
      var visual = VisualTreeHelper.GetChild(element, i) as Visual; 
      foundElement = visual.GetDescendantByType<T>(); 
      if (foundElement != null) 
      { 
       break; 
      } 
     } 
     return foundElement; 
     } 

    } 

Teraz można nazwać go SomeVisual.GetDescendantByType i zwraca albo już prawidłowa wpisany ScrollViewer lub zerowy (który jest domyślny (T))

0

Oto kolejny przerobione i generycznych wersji użytkownika @ punker76 odpowiedź dla C# 6:

public static class VisualExtensions 
{ 
    public static T FindVisualDescendant<T>(this Visual element) where T : Visual 
    { 
     if (element == null) 
      return null; 

     var e = element as T; 

     if (e != null) 
      return e; 

     (element as FrameworkElement)?.ApplyTemplate(); 

     var childrenCount = VisualTreeHelper.GetChildrenCount(element); 

     for (var i = 0; i < childrenCount; i++) 
     { 
      var visual = VisualTreeHelper.GetChild(element, i) as Visual; 

      var foundElement = visual.FindVisualDescendant<T>(); 

      if (foundElement != null) 
       return foundElement; 
     } 

     return null; 
    } 
} 
Powiązane problemy