2013-05-04 103 views
21

我有這個flipview:如何訪問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> 

我想找到當前選定的指數IMG1。雖然尋找它,我發現了一些張貼在這裏這個方法:

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

它返回我的圖像flipview的第一指標,但我需要對當前選定的指數中所存在..我試圖修改此方法但我無法找到所需的控制。誰能幫我?

+1

這通常是錯誤的方法。你想用這個圖像做什麼?請注意,FlipView會對其子項進行虛擬化,以便Image可能不存在。 – 2013-05-04 14:37:24

+0

@FilipSkakun我想獲得該圖像的屏幕座標。我能以其他方式做到嗎? – Tehreem 2013-05-04 14:42:24

+0

你需要什麼屏幕座標? – 2013-05-04 16:16:42

回答

49

您遇到的問題是DataTemplate正在重複且內容由FlipView生成。 Name未公開,因爲它會與之前生成的兄弟(或下一個兄弟)衝突。

因此,要獲得DataTemplate中的命名元素,您必須先獲取生成的項目,然後在生成的項目內搜索所需的元素。記住,XAML中的邏輯樹就是你如何通過名字訪問事物。生成的項目不在邏輯樹中。相反,它們位於可視樹中(所有控件均位於可視樹中)。這意味着它在Visual Tree中必須搜索想要引用的控件。 VisualTreeHelper可以讓你這樣做。

現在,該怎麼做呢?

我寫了這一篇文章,因爲它是這樣一個反覆出現的問題:http://blog.jerrynixon.com/2012/09/how-to-access-named-control-inside-xaml.html但解決方案的肉是一種遞歸方法,看起來是這樣的:

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

這裏的關鍵問題是,像這樣的方法獲取所有孩子,然後在子控件的結果列表中搜索您想要的特定控件。合理?

現在來回答你的問題!

因爲你特別想要當前選中的項目,你可以簡單地更新這樣的代碼:

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

Jerry - 看起來這隻有在您擁有SelectedItem時纔有效。如何通過點擊按鈕點擊模板項目邊界之外的元素?參見http://stackoverflow.com/questions/23645331/how-to-accessing-elements-in-xaml-datatemplate-listview-without-interacting-with – Rob 2014-05-14 16:03:14

+0

沒有。它始終有效。 – 2014-09-04 15:12:24

+0

@ JerryNixon-MSFT我試圖在Windows Phone 8.1應用程序中使用您的代碼,但它無法找到對VisualTreeHelperClass的引用。但是當我在對象瀏覽器中搜索它時,我可以在System.Windows.Media和Windows.UI.Xaml.Media中找到它。 也'OfType ()'給出錯誤Systems.Generic.Connections.List不包含OfType()的定義。 [我的FlipView結構](http://pastebin.com/9ud7sCyv) – user3263192 2014-10-07 11:25:34

2

訪問DataTemplate中的元素的簡單方法是將DataTemplate的內容封裝在UserControl中,在其中您可以訪問ItemsControl項目中的所有UI元素。我認爲FlipView通常虛擬化它的項目,所以即使你有100個項目綁定到它 - 只有2-3可能實際上在UI中有一個當前的表示(其中1-2個隱藏),所以你必須記住,當你想要取代任何東西,只有在物品加載到控件時才實際進行更改。

如果您確實需要識別代表ItemsSource中項目的項目容器 - 您可以檢查FlipView的ItemContainerGenerator屬性及其ContainerFromItem()方法。

要獲得項目的座標,您可以在WinRT XAML Toolkit中使用GetBoundingRect()擴展方法。

總的來說,根據你的評論,最好的方法可能是完全不同的。如果您將FlipView綁定到源代碼 - 通常可以通過更改綁定的源收集項目的屬性來控制顯示或覆蓋的圖像。

+0

我通過在列表中獲取FlipView中的所有圖像來解決該問題,然後遍歷該列表以找到我需要的圖像。是的,你是對的我一次只能訪問FlipView的3個項目,但由於我需要目前的重點項目,它總是出現在這三個項目中。謝謝你的幫助 – Tehreem 2013-05-05 08:47:08

+0

@Tehreem你能否提供解決方案我正面臨同樣的情況。 – 2013-05-06 10:17:01

+0

您可以使用'VisualTreeHelper'遍歷可視化樹,但我一直認爲它可能不是訪問元素的最高性能方式,所以將'DataTemplate'封裝在'UserControl'中可能會更好。無論什麼作品都很好。 – 2013-05-06 16:40:46

0

如果你只是想在項目點擊屏幕座標...你可以上註冊一個點擊事件處理圖像,然後使用senderimg.transform tovisual(null)這會給你一個通用的轉換,你可以從中獲得當前的點座標。

9

也許有點更通用的方法可能是這樣的:

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

你會調用的FindControl這樣的:

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

我掙扎絲毫這一整天,似乎控件必須加載(呈現)才能從DataTemplate獲取它的子控件。這意味着你不能在窗口加載,初始化的時候使用這段代碼或任何代碼(出於同樣的目的)... 你可以在控制初始化後如何使用它,例如在SelectedItem上。

我建議使用轉換器並在轉換器中定義請求的操作,而不是直接控制訪問。

0

所以,如果你通過結合你爲什麼不這樣做休息分配來源: <FlipView SelectedIndex="{Binding SIndex}" SelectedItem="{Binding SItem}" SelectedValue="{Binding SValue}"/>

您必須先爲這個特性準備到位。它可能是從INotifyPropertyChanged派生的類。

僱用MVVM爲您工作,在XAML中做的最多。當然在開始時似乎是更多的工作,但MVVM的更復雜的項目將是連貫和靈活的。

相關問題