2013-05-04 26 views
21

mam ten flipview:Jak uzyskać dostęp do formantu wewnątrz obiektu XAML DataTemplate?

<FlipView x:Name="models_list" SelectionChanged="selectionChanged"> 
<FlipView.ItemTemplate> 
      <DataTemplate> 
       <Grid x:Name="cv"> 
         <Image x:Name="img1" Source = "{Binding ModelImage}" Stretch="Fill" Tag="{Binding ModelTag}"/> 
       </Grid> 
      </DataTemplate> 
    </FlipView.ItemTemplate> 

Chcę znaleźć img1 aktualnie wybranego indeksu. Podczas poszukiwania nim znalazłem tę metodę na jakiś post tutaj:

private DependencyObject FindChildControl<T>(DependencyObject control, string ctrlName) 
    { 
     int childNumber = VisualTreeHelper.GetChildrenCount(control); 
     for (int i = 0; i < childNumber; i++) 
     { 
      DependencyObject child = VisualTreeHelper.GetChild(control, i); 
      FrameworkElement fe = child as FrameworkElement; 
      // Not a framework element or is null 
      if (fe == null) return null; 

      if (child is T && fe.Name== ctrlName) 
      { 
       // Found the control so return 
       return child; 
      } 
      else 
      { 
       // Not found it - search children 
       DependencyObject nextLevel = FindChildControl<T>(child, ctrlName); 
       if (nextLevel != null) 
        return nextLevel; 
      } 
     } 
     return null; 
    } 

Zwraca mi obraz na pierwszym indeksem flipview ale muszę jeden prezent od aktualnie wybranego indeksu .. Próbowałem edytować tę metodę ale nie jestem w stanie znaleźć wymaganej kontroli. Czy ktoś może mi pomóc?

+1

To zwykle jest złe podejście. Co konkretnie chcesz zrobić z tym obrazem? Zwróć uwagę, że FlipView wirtualizuje swoje dzieci, aby obraz mógł nie istnieć. –

+0

@FilipSkakun Chcę uzyskać współrzędne tego obrazu. Czy mogę to zrobić w jakikolwiek inny sposób? – Tehreem

+0

Do czego potrzebne są współrzędne ekranu? –

Odpowiedz

49

Występuje problem polegający na tym, że numer DataTemplate powtarza się, a treść jest generowana przez FlipView. Obiekt Name nie został ujawniony, ponieważ byłby niezgodny z poprzednim rodzeństwem, które zostało wygenerowane (lub następnym).

Aby uzyskać nazwany element w DataTemplate, należy najpierw uzyskać wygenerowany element, a następnie wyszukać wewnątrz wygenerowanego elementu dla potrzebnego elementu. Pamiętaj, że Drzewo logiczne w XAML to sposób uzyskiwania dostępu do rzeczy po nazwie. Wygenerowane elementy nie znajdują się w drzewie logicznym. Zamiast tego są one w Visual Tree (wszystkie kontrolki są w Visual Tree). Oznacza to, że znajduje się w Visual Tree, należy szukać kontroli, którą chcesz odwołać. VisualTreeHelper pozwala to zrobić.

Teraz, jak to zrobić?

napisałem artykuł na ten temat, bo to takie powtarzające się pytanie: http://blog.jerrynixon.com/2012/09/how-to-access-named-control-inside-xaml.html ale mięso w roztworze jest rekurencyjna metoda, która wygląda mniej więcej tak:

public void TestFirstName() 
{ 
    foreach (var item in MyFlipView.Items) 
    { 
     var _Container = MyFlipView.ItemContainerGenerator 
      .ContainerFromItem(item); 
     var _Children = AllChildren(_Container); 

     var _FirstName = _Children 
      // only interested in TextBoxes 
      .OfType<TextBox>() 
      // only interested in FirstName 
      .First(x => x.Name.Equals("FirstName")); 

     // test & set color 
     _FirstName.Background = 
      (string.IsNullOrWhiteSpace(_FirstName.Text)) 
      ? new SolidColorBrush(Colors.Red) 
      : new SolidColorBrush(Colors.White); 
    } 
} 

public List<Control> AllChildren(DependencyObject parent) 
{ 
    var _List = new List<Control>(); 
    for (int i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++) 
    { 
     var _Child = VisualTreeHelper.GetChild(parent, i); 
     if (_Child is Control) 
      _List.Add(_Child as Control); 
     _List.AddRange(AllChildren(_Child)); 
    } 
    return _List; 
} 

Kluczową kwestią jest to, że Ta metoda pobiera wszystkie dzieci, a następnie w wynikowej liście podrzędnych elementów sterujących można wyszukać określoną kontrolkę. Ma sens?

A teraz, aby odpowiedzieć na twoje pytanie!

Bo konkretnie chcemy aktualnie wybranego elementu, można po prostu zaktualizować kodu:

if (MyFlipView.SelectedItem == null) 
    return; 
var _Container = MyFlipView.ItemContainerGenerator 
    .ContainerFromItem(MyFlipView.SelectedItem); 
// then the same as above... 
+0

Jerry - Wydaje się, że działa to tylko wtedy, gdy masz SelectedItem. Jak kierować element za pomocą kliknięcia przycisku poza granicami elementu szablonu? Zobacz http://stackoverflow.com/questions/23645331/how-to-accessing-elements-in-xaml-datatemplate-listview-without-interacting- with – Rob

+0

Nie. To zawsze działa. –

+0

@ JerryNixon-MSFT Próbuję użyć Twojego kodu w aplikacji Windows Phone 8.1, ale nie mogę znaleźć odwołania do VisualTreeHelperClass. Ale kiedy szukam go w przeglądarce obiektów, mogę go znaleźć w System.Windows.Media i Windows.UI.Xaml.Media. Również 'OfType ()' daje błąd Systems.Generic.Connections.List nie zawiera definicji OfType(). [Struktura mojego FlipView] (http://pastebin.com/9ud7sCyv) – user3263192

2

Prostym sposobem na uzyskanie dostępu do elementów w DataTemplate jest zawinięcie zawartości DataTemplate w UserControl, gdzie uzyskasz dostęp do wszystkich elementów interfejsu w elemencie ItemsControl. Myślę, że FlipView zwykle wirtualizuje swoje elementy, więc nawet jeśli masz 100 elementów związanych z nim - tylko 2-3 może rzeczywiście mieć bieżącą reprezentację w interfejsie użytkownika (1-2 ukryte), więc musisz pamiętać, że kiedy chcesz Zastąp wszystko i tylko faktycznie wprowadzaj zmiany, gdy element zostanie załadowany do formantu.

Jeśli naprawdę potrzebujesz zidentyfikować pojemnik z artykułami, który reprezentuje przedmiot w ItemSource - możesz sprawdzić właściwość FlipView o wartości ItemContainerGenerator i jej metodę ContainerFromItem().

Aby uzyskać współrzędne elementu, można skorzystać z metody rozszerzenia GetBoundingRect() w WinRT XAML Toolkit.

Ogólnie rzecz biorąc, na podstawie Twojego komentarza może się okazać, że najlepsze podejście jest zupełnie inne. Jeśli wiążisz swój FlipView ze źródłem - zazwyczaj możesz kontrolować wyświetlane lub nakładane obrazy, zmieniając właściwości powiązanych elementów kolekcji.

+0

Rozwiązałem problem, pobierając wszystkie obrazy w FlipView na liście, a następnie przeszedłem iterację przez tę listę, aby znaleźć wymagane zdjęcie. Tak, masz rację, mogłem mieć dostęp tylko do 3 elementów FlipView na raz, ale ponieważ potrzebowałem aktualnie skupionego przedmiotu, zawsze jest obecny w tych trzech przedmiotach. Dziękuję za pomoc – Tehreem

+0

@Tehreem czy możesz podać rozwiązanie, w obliczu tej samej sytuacji. –

+0

Możesz przechodzić przez wizualne drzewo używając 'VisualTreeHelper', ale słyszałem, że może nie być najbardziej wydajnym sposobem uzyskania dostępu do elementów, więc owijanie' DataTemplate' w 'UserControl' może działać lepiej. Cokolwiek jednak działa, jest w porządku. –

0

Jeśli chcesz tylko współrzędne ekran na punkcie kliknięcia ... Można zarejestrować obsługi kliknij na obraz, a następnie użyj senderimg.transform tovisual (null), który daje ogólne przekierowanie, z którego możesz uzyskać aktualne współrzędne punktu.

9

może trochę bardziej ogólne podejście może być coś takiego:

private List<Control> AllChildren(DependencyObject parent) 
{ 
    var _List = new List<Control>(); 
    for (int i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++) 
    { 
     var _Child = VisualTreeHelper.GetChild(parent, i); 
     if (_Child is Control) 
     { 
     _List.Add(_Child as Control); 
     } 
     _List.AddRange(AllChildren(_Child)); 
    } 
    return _List; 
} 


private T FindControl<T> (DependencyObject parentContainer, string controlName) 
{    
     var childControls = AllChildren(parentContainer); 
     var control = childControls.OfType<Control>().Where(x => x.Name.Equals(controlName)).Cast<T>().First();   
     return control; 
} 

Można by powołać FindControl tak:

var parentContainer = this.flipView.ItemContainerGenerator.ContainerFromItem(this.flipView.SelectedItem); 
var myImage = FindControl<Image>(parentContainer, "img1"); 

//suppose you want to change the visibility 
myImage.Visibility = Windows.UI.Xaml.Visibility.Collapsed;   
0

Miałem problemy odrobina tego cały dzień, i wydaje się, że kontrola musi zostać załadowana (wyrenderowana), aby uzyskać elementy sterujące potomne z DataTemplate. Oznacza to, że nie możesz użyć tego kodu ani żadnego kodu (w tym samym celu) w załadowanym, zainicjowanym oknie ... Możesz go używać po zainicjowaniu kontroli, na przykład w SelectedItem.

Proponuję użyć konwerterów i zdefiniować żądane działanie w konwerterze, zamiast bezpośredniego dostępu sterowania.

0

Więc jeśli Ty przypisane źródło poprzez wiązanie dlaczego nie chcesz zrobić to samo z resztą: <FlipView SelectedIndex="{Binding SIndex}" SelectedItem="{Binding SItem}" SelectedValue="{Binding SValue}"/>

Najpierw należy przygotować miejsce dla tej właściwości. Może to być klasa pochodna od INotifyPropertyChanged.

Zatrudnij MVVM do pracy dla Ciebie, zrób większość w XAML. Oczywiście na początku wydaje się, że jest to więcej pracy, ale przy bardziej wyrafinowanym projekcie z MVVM będzie spójny i elastyczny.