トップ回答者
動的に生成したコントロールの指定

質問
回答
-
GridなりStackPanelなり何らかPanelコントロールに追加したのであればChildrenを辿って探すことができるでしょうし
FindNameメソッドを使用するという手もあります。
// foreachでChildrenを走査 foreach (var textbox1 in this.StackPanel1.Children.OfType<Control>().Where(x => x.Name == "TextBox1")) { // ここに処理を記述 } // findnameで探す var textbox1 = (TextBox)this.FindName("TextBox1");
お好きな方法でどうぞ。
※FindName
http://msdn.microsoft.com/ja-jp/library/system.windows.frameworkelement.findname(v=VS.95).aspx
- 回答としてマーク 山本春海 2010年5月14日 0:49
2010年4月13日 5:09 -
解決されたようですが、VisualTreeHelperクラスを使う方法もあります。
(参考)
Get Child, Parent, or Children Objects in Silverlight
http://www.mostlydevelopers.com/mostlydevelopers/blog/post/2009/06/17/Get-Child-Parent-or-Children-Objects-in-Silverlight.aspx
#OfTypeはIEnumerable.OfTypeです。Linqです。
★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://blogs.wankuma.com/trapemiya/- 回答としてマーク 山本春海 2010年5月14日 0:49
2010年4月13日 6:53モデレータ -
UserControl内のTextBoxのインスタンスを外部から取得したいのなら
そのプロパティを用意しておけばいいと思います。
外からのアクセスを許可することを明示しているわけですから精神衛生上(?)いいと思います。
// UserControl1内でプロパティを設定 public TextBox InnerTextBox { get{return this.TextBox1;} }
もしくは先にあげられていたVisualTreeHelperを使用して取得することもできます。
// VisualTreeHelperを最後まで取得するメソッドを作ってみる private List<DependencyObject> GetChildren(DependencyObject obj) { List<DependencyObject> list = new List<DependencyObject>(); int childcount = VisualTreeHelper.GetChildrenCount(obj); for (int i = 0; i < childcount; i++) { var child = VisualTreeHelper.GetChild(obj, i); list.Add(child); foreach (var grandchild in this.GetChildren(child)) { list.Add(grandchild); } } return list; } // UserControl内のTextBoxを取得する foreach (var textbox1 in this.GetChildren(this.UserControl1).OfType<TextBox>().Where(x => x.Name == "TextBox1")) { // お好きな処理をどうぞ }
この場合は内部のTextBoxにつけられた名前を知っている必要があるのでどうかな、という気がしますが…
UserControl内部のインスタンスを取得したいコントロールを一意に識別する方法を考えるよりは
プロパティを用意するほうが手軽だと思います。
- 回答としてマーク 山本春海 2010年5月14日 0:50
2010年4月14日 5:32 -
<ItemsControl x:Name="ic"> <ItemsControl.ItemTemplate> <DataTemplate> <TextBox Text="{Binding TaskName, Mode=TwoWay}" /> </DataTemplate> </ItemsControl.ItemTemplate> </ItemsControl>
のようにしておいて
// データを表示するところ var tasks = ... 配列かリストあたりを取得 ...; // ItemsControlにデータを表示 ic.ItemsSource = tasks; // データを取得するところ foreach (var task in tasks) { // TextBoxの中身がTaskNameに設定されてる MessageBox.Show(task.TaskName); }
とすれば、多分VisualTreeをいじくったりしなくても良いような気がするのですがどうでしょうか?
かずき Blog:http://blogs.wankuma.com/kazuki/- 回答としてマーク 山本春海 2010年5月14日 0:50
2010年4月15日 15:23
すべての返信
-
GridなりStackPanelなり何らかPanelコントロールに追加したのであればChildrenを辿って探すことができるでしょうし
FindNameメソッドを使用するという手もあります。
// foreachでChildrenを走査 foreach (var textbox1 in this.StackPanel1.Children.OfType<Control>().Where(x => x.Name == "TextBox1")) { // ここに処理を記述 } // findnameで探す var textbox1 = (TextBox)this.FindName("TextBox1");
お好きな方法でどうぞ。
※FindName
http://msdn.microsoft.com/ja-jp/library/system.windows.frameworkelement.findname(v=VS.95).aspx
- 回答としてマーク 山本春海 2010年5月14日 0:49
2010年4月13日 5:09 -
ありがとうございます。
FindNameで値をとることはできました。
しかし、ループ文の
this.StackPanel1.Children.OfType<Control>().Where(x => x.Name == "TextBox1")
の部分の仕様がわかりません。
StackPanel1内の子要素に対してx.Name == "TextBox1"で検索し、該当するものを
取得しているだろうということはわかるのですが
Children.OfType< Control >
の部分がChildren.OfTypeなどで検索しても必要な情報を得られませんでした。
よろしければこの部分が何をしているのか教えていただけないでしょうか。
2010年4月13日 5:49 -
解決されたようですが、VisualTreeHelperクラスを使う方法もあります。
(参考)
Get Child, Parent, or Children Objects in Silverlight
http://www.mostlydevelopers.com/mostlydevelopers/blog/post/2009/06/17/Get-Child-Parent-or-Children-Objects-in-Silverlight.aspx
#OfTypeはIEnumerable.OfTypeです。Linqです。
★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://blogs.wankuma.com/trapemiya/- 回答としてマーク 山本春海 2010年5月14日 0:49
2010年4月13日 6:53モデレータ -
ありがとうございます。
>#OfTypeはIEnumerable.OfTypeです。Linqです。
OfTypeはcastのようなもの、であっているのかな。
指定した型のデータだけ抜き出してくれるもののようですね。
まずループの方ですが、
var tb = this.LayoutRoot2.Children.OfType<Control>()
.Where(x => x.Name == "TextBox" + Index .ToString());
とし、var型のデータとして抽出したは良いものの、
TextBoxとして扱えないため値がとれません。
TextBox tb = (TextBox)this.LayoutRoot2.Children.OfType<TextBox>()
としてもエラーとなり駄目でした。
VisualTreeHelperクラスもStackPanelの子要素まではとれました。
しかしこれも同様に、名前を指定して特定のオブジェクトを取得する方法がわかりません。
CType(parent, T).Name = name
この辺りで条件を絞れているような気がするのですが・・・
2010年4月13日 7:56 -
ChildrenやVisualTreeをたどる方法もあると思いますが、ご自身のコードでコントロールを作成しているのでしたら
List<TextBox> textBoxList = new List(); // フィールドあたりに作成しておく
// 追加処理
TextBox txt = new TextBox();
txt.Name = ....; // 何か名前を適当につける
textBoxList.Add(txt); // 自分で動的に生成したオブジェクトを管理するためのListに入れる
grid.Children.Add(txt); // そしてGUIに表示するといったようにListあたりを別に作って、そこで管理してしまうのが手っ取り早いと思います。
(Nameをキーにアクセスするような使いかたをしたいならDictionary<T,K>を使うとか)コントロールを動的に生成する部分のコードに変更が入ってしまいますが、1つのやり方として検討してみては如何でしょうか。
かずき Blog:http://blogs.wankuma.com/kazuki/2010年4月14日 1:56 -
var tb = this.LayoutRoot2.Children.OfType<Control>()
.Where(x => x.Name == "TextBox" + Index .ToString());
とし、var型のデータとして抽出したは良いものの、
TextBoxとして扱えないため値がとれません。
TextBox tb = (TextBox)this.LayoutRoot2.Children.OfType<TextBox>()
としてもエラーとなり駄目でした。
Enumerable.OfType<T>の結果はIEnumerable<T>なので、OfType<Control>でフィルターすればIEnumerable<Control>だし、OfType<TextBox>だったらIEnumerable<TextBox>になりますよね。あとは、foreachなんかで回して処理すればいいんじゃないですか?
Visual Studioを使っているなら、ブレークポイントをおいてウォッチ式で値を確認してみたらどうでしょう。
2010年4月14日 3:25 -
ありがとうございます。
メンバのListで管理する方法は考えていました。
ただDataGridとListの二つに同じインスタンス(?)を持つことになってしまいますので
ソースレビューで弾かれないかな、と思っています。
IEnumerable<TextBox>型ですか、ようやく理解できました。
最初に提示されたforeach文を使用して
StackPanel1の子要素TextBox1
をとることができました。
ただ、もう一点要件を追加したいのですが、
StackPanel1の子要素ContentControl1に入ったUserControl1のTextBox1と
StackPanel1の子要素UserControl1のTextBox1を取る方法はありますでしょうか。
現状のforeachですと一件も取得できませんでした。
2010年4月14日 4:09 -
UserControl内のTextBoxのインスタンスを外部から取得したいのなら
そのプロパティを用意しておけばいいと思います。
外からのアクセスを許可することを明示しているわけですから精神衛生上(?)いいと思います。
// UserControl1内でプロパティを設定 public TextBox InnerTextBox { get{return this.TextBox1;} }
もしくは先にあげられていたVisualTreeHelperを使用して取得することもできます。
// VisualTreeHelperを最後まで取得するメソッドを作ってみる private List<DependencyObject> GetChildren(DependencyObject obj) { List<DependencyObject> list = new List<DependencyObject>(); int childcount = VisualTreeHelper.GetChildrenCount(obj); for (int i = 0; i < childcount; i++) { var child = VisualTreeHelper.GetChild(obj, i); list.Add(child); foreach (var grandchild in this.GetChildren(child)) { list.Add(grandchild); } } return list; } // UserControl内のTextBoxを取得する foreach (var textbox1 in this.GetChildren(this.UserControl1).OfType<TextBox>().Where(x => x.Name == "TextBox1")) { // お好きな処理をどうぞ }
この場合は内部のTextBoxにつけられた名前を知っている必要があるのでどうかな、という気がしますが…
UserControl内部のインスタンスを取得したいコントロールを一意に識別する方法を考えるよりは
プロパティを用意するほうが手軽だと思います。
- 回答としてマーク 山本春海 2010年5月14日 0:50
2010年4月14日 5:32 -
そもそも論てきなことを言ってしまって悪いのですが何かのインスタンスの配列があって、その件数分縦にTextBoxを並べて、あるプロパティの値を表示したいというときは、ItemsControlを使ってItemTemplateにTextBoxだけもったDataTemplateを作ってTextBoxのTextプロパティとTowWayでバインドします。
こうしておくと、わざわざコントロールのプロパティからデータを拾わなくても、バインドしてるオブジェクトのプロパティに直接アクセスしてデータを拾ってくることが出来ます。
かずき Blog:http://blogs.wankuma.com/kazuki/2010年4月14日 12:39 -
ありがとうございます。
>//UserControl1内でプロパティを設定
なぜ気づかなかったのか・・・かなり簡単に取れるようになりました。
VisualTreeHelperはメソッドをそのまま使わせていただきました。
DependencyObject 型というものが今ひとつ良くわかりませんでしたが。
>var textbox1 in this.GetChildren(this.UserControl1).OfType<TextBox>()
GetChildrenで子要素を特定してからフィルタを掛けるんですか。
this.LayoutRoot1.Children.OfType<UserContorol1>()で抜き出してから
自作したプロパティで引っ張ってくるのが今の所一番簡単かな、と思っています。
ItemControlの使い方がよくわかりません。
<ItemsControl x:Name="ic"> <ItemsControl.ItemTemplate> <DataTemplate> <StackPanel x:Name="st"> <TextBlock x:Name="a" Text="{Binding Path=TaskName}" />
<TextBlock x:Name="b" Text=""/> </StackPanel> </DataTemplate> </ItemsControl.ItemTemplate> </ItemsControl>
DataTemplateの内容をItemControlにAddしていくイメージなんでしょうか?
2010年4月15日 3:02 -
<ItemsControl x:Name="ic"> <ItemsControl.ItemTemplate> <DataTemplate> <TextBox Text="{Binding TaskName, Mode=TwoWay}" /> </DataTemplate> </ItemsControl.ItemTemplate> </ItemsControl>
のようにしておいて
// データを表示するところ var tasks = ... 配列かリストあたりを取得 ...; // ItemsControlにデータを表示 ic.ItemsSource = tasks; // データを取得するところ foreach (var task in tasks) { // TextBoxの中身がTaskNameに設定されてる MessageBox.Show(task.TaskName); }
とすれば、多分VisualTreeをいじくったりしなくても良いような気がするのですがどうでしょうか?
かずき Blog:http://blogs.wankuma.com/kazuki/- 回答としてマーク 山本春海 2010年5月14日 0:50
2010年4月15日 15:23 -
ありがとうございます。
テンプレートを用意し、Lsitの数分テンプレート内の要素を増やしていくイメージですね。
> ... 配列かリストあたりを取得 ...;
List<String> Array = new List<String>();
Array.Add("あ");
Array.Add("い");
var tasks = Array;
~
という形で試してみましたが、tasksにはTaskNameプロパティが存在せずエラーとなりました。
適当なクラスを作成してみましたがこちらもうまくいきませんでした。
private class hoge{
public String TaskName = "あ";
}
~
hoge aaa = new hoge();
var tasks = aaa;
ic.ItemsSource = tasks;
型がcollectionらしいのでキャストは出来ないそうです。
配列かリストあたりとは何のことを示していますか?
2010年4月16日 6:15 -
ありがとうございます。
>他の疑問はまた新しく質問をしたほうがいいと思いますよ。
要件を追加した時点で新しく質問しなおすべきでしたね。
今後はそうさせていただきます。
ただ宜しければItemsControl だけ解決させてください。
>tasks.add(new hoge());
で無事TextBoxは動的に追加出来たのですが、中身が表示されません。
List<hoge> tasks = new List<hoge>(); hoge ho = new hoge(); ho.TascName = "1です";
tasks.Add(ho); ic.ItemsSource = tasks; //バインドに失敗してる?
TextBoxに「あ」と表示されなかったので初期化後にも「1です」と入れてみたのですが、
これで実行しても空欄のままでした。
tasksの中にはちゃんとho.TascName = "1です"が入ってます。
TextBoxの初期値はどのように追加すればよいでしょうか。
2010年4月16日 8:52