2013-05-04 4 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つの存在を必要とする..私は、このメソッドを編集してみました私は必要なコントロールを見つけることができません。誰でも助けてくれますか?

+1

これは通常、間違ったアプローチです。あなたはそのイメージで何をしたいのですか? FlipViewは、Imageが存在しないように子を仮想化することに注意してください。 –

+0

@FilipSkakunその画像の画面座標を取得します。他の方法でそれをすることはできますか? – Tehreem

+0

画面の座標は何にする必要がありますか? –

答えて

49

FlipViewによってコンテンツが生成されており、DataTemplateが繰り返し再生されているという問題が発生しています。 Nameは、生成された以前の兄弟(または次の兄弟)と競合するため、公開されません。

DataTemplateで名前付き要素を取得するには、最初に生成された項目を取得してから、その要素内で目的の要素を検索する必要があります。 XAMLの論理ツリーは、名前で物事にアクセスする方法です。生成された項目は論理ツリーにありません。代わりに、それらはビジュアルツリーにあります(すべてのコントロールはビジュアルツリーにあります)。つまり、ビジュアルツリーには参照するコントロールを検索する必要があります。 VisualTreeHelperでこれを行うことができます。

今、それを行う方法は?

それは、このような定期的な質問ですので、私はこの記事を書いた:ここで重要な問題があることである

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

http://blog.jerrynixon.com/2012/09/how-to-access-named-control-inside-xaml.htmlが、溶液の肉は次のようになります再帰的な方法であり、このようなメソッドはすべての子を取得し、子コントロールの結果のリストで、必要な特定のコントロールを検索することができます。理にかなっている?

あなたの質問にお答えください。

あなたが特に現在選択されている項目をしたいので、あなたは、単にこのようなコードを更新することができます。

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

+0

Nopeを参照してください。それは常に動作します。 –

+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

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つのアイテムにしかアクセスできませんでしたが、現在フォーカスが置かれているアイテムが必要なので、常に3つのアイテムに存在します。あなたの助けをありがとう – Tehreem

+0

@Tehreem私は同じ状況に直面している解決策を提供することができます。 –

+0

あなたは 'VisualTreeHelper'を使ってビジュアルツリーを走査することができますが、これは要素へのアクセスを得る最も効果的な方法ではないかもしれないと聞いてきましたので、' UserControl'で 'DataTemplate'をラップする方がうまくいくかもしれません。どんな作品でもうまくいく。 –

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を使ったより洗練されたプロジェクトでは、一貫性と柔軟性が実現します。

関連する問題