質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Q&A

解決済

1回答

568閲覧

アクティブなコントロールとテキストボックスのバインド

kaisen

総合スコア28

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

0グッド

0クリップ

投稿2017/12/26 02:06

編集2017/12/26 09:17

###追記と注意書き。2017/12/26 Tue 18:07:23
バインドの問題について悩む人が、
この投稿内容について読む前に、
まず、この質問投稿の解決が
バインドの問題ではなくなってしまっていることを
お伝えしておきます。

これは、私がバインドという言葉を勘違いして使ってしまっていたせいです。
いまでもわかっていません。

それでも回答者様の回答の中には、
C#によるwindowsフォームのバインドについて
有用な情報があると思います。
回答者様の力のみによってこの投稿の価値が維持されているとおもいます。

しかし、質問内容がそもそもズレているので投稿については、
いずれ一部削除かあるいは全削除する可能性はあります。
そして私自身の投稿内容については、あてにしないでください。お騒がせしました。。

###前提・実現したいこと
こんにちは。
C#でフォームを作成しているのですが、
データバインドで二日ほど詰まっています。
昨日質問を投稿し、回答をいただいて、
DataBindingsの構文については知ることができたので
エラーが出ることはなくなりました。
しかし、目的とする動作が達成できない状況は変わりませんでした。

実現したいことは、

現在アクティブなコントロールであるTextBox[A]にて、
テキスト入力中にEnterキーを押すことで、
あらたなTextBox[B]を生成する。

この生成時に、
public Directory Addによって、
TextBox[A]はTextBox[B]の親として登録される。

そうして
登録された情報をもとにして、
public static void LinkGraphによって、
フォーム上のtextboxすべての親子間に赤い線を描画する。

というような動作をする
フォームアプリを作ることです。

###発生している問題の概要
TextBox[B]生成時点での
アクティブなコントロールをpublic Directory Addに引数として渡します。
そして、
全てのTextBoxの内(directory)から、アクティブなコントロールに一致するものを
TextBox[B]の親としてArrayListインスタンスsupnode内のsup要素とバインドさせます。
しかし、おそらくこのバインドに何かしらの問題があって、
描画時にsup.Top,sup.Leftの値が共に「0」になってしまっています。
###該当のソースコード

C#

1///Directory.cs//textboxから継承したクラス 2 public Directory Add(Directory sub, Directory supar, Control c)//subは新しく生成したtextbox,suparとcはアクティブなコントロール 3 { 4 int i = 0; 5 Directory sup = new Directory("sup", Form1.k); 6 foreach (Directory supe in directory)//directoryはstaticですべての新しく生成したtextboxを格納するArrayList 7 { 8 if (supe.Name == ((WindowsFormsApp1.Directory)c).Name) 9 { 10 break; 11 } 12 i++; 13 } 14 directory.Add(sub); 15 cop.Add(sub);//copはstaticで、directoryのバックアップのArrayList 16 cont = (Control)cop[i];//contはDirectory.csのグローバルなコントロールインスタンス 17 sup.DataBindings.Add(new Binding("Top", cont, "Top"));//contをソースにして、supのTopを変えたいのだけど、それができていない? 18 sup.DataBindings.Add(new Binding("Left", cont, "Left")); 19 sub.supnode.Add(sup);//supnodeは、subの親にあたるtextboxのArrayList 20 con.Add(cont);//conはcontのバックアップのためのArrayList。contがGCされてしまうせいで、Topがバインドできていないのではないかと思ったときに追加した。 21 return this; 22 }

C#

1///Directory.cs//textboxから継承したクラス 2 public static void LinkGraph() 3 { 4 Graphics f = Form1.ActiveForm.CreateGraphics(); 5 Graphics g = Form1.ActiveForm.CreateGraphics(); 6 7 // 背景色を更新 8 f.Clear(color: SystemColors.Control); 9 10 //penを作る 11 Pen redPen = new Pen(Color.Red, 10); 12 foreach (Directory sub in directory) 13 { 14 foreach (Directory sup in sub.supnode)//フォーム上にあるすべてのtextboxの親子関係を取得して、描画しているはず。 15 { 16 //始点と終点 17 Point Start_point = new Point(sub.Left + sub.Width / 2, sub.Top + sub.Height / 2); 18 Point End_point = new Point(sup.Left + sup.Width / 2, sup.Top + sup.Height / 2); 19 //描画 20 g.DrawLine(redPen, Start_point, End_point); 21 } 22 } 23 //penを解放 24 redPen.Dispose(); 25 }

###補足情報(言語/FW/ツール等のバージョンなど)
環境は、
visualstudio2017 C# windowsフォームアプリケーション
です。
C言語は自作でいくつかプログラムを書いたことがありますが、
データ構造あたりまでの学習しか進んでいません。
C#は初心者です。

作りながら学ぼうとしているので、頓珍漢なことばかりして
読みづらくしてしまっていると思います。

ぜひ
知恵をお貸しいただきたいです。
よろしくお願いします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

バインドする方とされる方を逆にしてください。

コメントを受けて追記

Form1.cs

C#

1using System.Collections.Generic; 2using System.Drawing; 3using System.Windows.Forms; 4 5 6public delegate void tb_Click(object sender, KeyPressEventArgs e); 7 8namespace WindowsFormsApp1 9{ 10 public partial class Form1 : Form 11 { 12 public Form1() 13 { 14 InitializeComponent(); 15 } 16 17 public static int k = 0; 18 public Directory temp = new Directory("tb", 0); 19 public Form t = new Form(); 20 21 // tempを格納しておく動的リスト 22 public static List<Directory> tempa = new List<Directory>(); 23 24 public Directory supar = new Directory("supar", k); 25 26 public List<Point> spoint = new List<Point>(); 27 public List<Point> epoint = new List<Point>(); 28 29 private void button1_KeyPress(object sender, KeyPressEventArgs e) 30 { 31 32 if (e.KeyChar == (char)Keys.T)//Tキーが押されたとき 33 { 34 Control c = this.ActiveControl; 35 Directory tb = new Directory("tb", k); 36 tb.Add(tb, supar, c); 37 tb.Multiline = true; 38 tb.Top = 100; 39 tb.Left = 100; 40 tb.Height = 100; 41 tb.Width = 100; 42 tb.Text = "hello"; 43 this.Controls.Add(tb); 44 tb.KeyDown += new KeyEventHandler(tb_KeyDown); 45 tb.Focus(); 46 tb.BringToFront(); 47 temp = tb; 48 supar = tb; 49 this.Controls.Add(temp); 50 tempa.Add(temp); 51 e.Handled = true; 52 k++; 53 } 54 } 55 private void tb_KeyDown(object sender, System.Windows.Forms.KeyEventArgs e) 56 { 57 Directory temp = new Directory("temp", k); 58 59 Control d = this.ActiveControl; 60 t.Width = d.Left; 61 t.Height = d.Top; 62 if (t.Width >= this.Width) 63 { 64 this.Width += 100; 65 } 66 if (t.Height >= this.Height) 67 { 68 this.Height += 100; 69 } 70 71 if (e.KeyCode == Keys.Enter) 72 { 73 if (e.Shift == true) 74 { 75 this.SelectNextControl(this.ActiveControl, false, true, true, true); 76 e.Handled = true; 77 Control c = this.ActiveControl; 78 c.BringToFront(); 79 } 80 else //メインの動作 81 { 82 int th = 0; 83 int tw = 0; 84 Control c = this.ActiveControl; 85 th = c.Top + c.Height; 86 tw = c.Left + c.Width; 87 Directory tb = new Directory("tb", k); 88 tb.Add(tb, (TextBox)sender, c); 89 tb.Multiline = true; 90 tb.Top = th; 91 tb.Left = tw; 92 tb.Height = tb.HeightS(k); 93 tb.Width = 50; 94 tb.Text = "hello"; 95 this.Controls.Add(tb); 96 tb.KeyDown += new KeyEventHandler(tb_KeyDown); 97 tb.Focus(); 98 tb.BringToFront(); 99 temp = tb; 100 supar = tb; 101 this.Controls.Add(temp); 102 tempa.Add(temp); 103 e.Handled = true; 104 k++; 105 } 106 if (e.Alt) 107 { 108 e.Handled = true; 109 } 110 } 111 if (e.Alt) 112 { 113 if (e.KeyCode == Keys.Up || e.KeyCode == Keys.Down || e.KeyCode == Keys.Left || e.KeyCode == Keys.Right) 114 { 115 Directory.LinkGraph(); 116 } 117 //移動 118 if (e.KeyCode == Keys.Up) 119 { 120 Control c = this.ActiveControl; 121 c.Top -= 5; 122 e.Handled = true; 123 } 124 if (e.KeyCode == Keys.Down) 125 { 126 Control c = this.ActiveControl; 127 c.Top += 5; 128 e.Handled = true; 129 } 130 if (e.KeyCode == Keys.Left) 131 { 132 Control c = this.ActiveControl; 133 c.Left -= 5; 134 e.Handled = true; 135 } 136 if (e.KeyCode == Keys.Right) 137 { 138 Control c = this.ActiveControl; 139 c.Left += 5; 140 e.Handled = true; 141 } 142 143 if (e.Control)//移動 144 { 145 146 if (e.KeyCode == Keys.Up) 147 { 148 Control c = this.ActiveControl; 149 c.Top -= 50; 150 e.Handled = true; 151 } 152 if (e.KeyCode == Keys.Down) 153 { 154 Control c = this.ActiveControl; 155 c.Top += 50; 156 e.Handled = true; 157 } 158 if (e.KeyCode == Keys.Left) 159 { 160 Control c = this.ActiveControl; 161 c.Left -= 50; 162 e.Handled = true; 163 } 164 if (e.KeyCode == Keys.Right) 165 { 166 Control c = this.ActiveControl; 167 c.Left += 50; 168 e.Handled = true; 169 } 170 } 171 } 172 if (e.Control) 173 { 174 foreach (Control l in Controls) 175 { 176 l.Top += 100; 177 l.Left += 100; 178 } 179 } 180 } 181 182 private void button1_Click(object sender, System.EventArgs e) 183 { 184 } 185 } 186}

Directory.cs

C#

1using System.Collections; 2using System.Drawing; 3using System.Windows.Forms; 4 5namespace WindowsFormsApp1 6{ 7 8 public class Directory : Entry 9 { 10 public string name; // ディレクトリの名前 11 public int num; //ディレクトリの識別番号 12 private static ArrayList directory = new ArrayList(); // ディレクトリエントリの集合 13 public new ArrayList supnode = new ArrayList();//子ノードの集合 14 public static ArrayList _su = new ArrayList(); 15 public static ArrayList cop = new ArrayList(); 16 public static ArrayList con = new ArrayList(); 17 18 Directory cont; 19 20 string supename = ""; 21 22 // 名前 23 override public string Name 24 { 25 set { this.name = value; } 26 get { return name; } 27 } 28 29 // サイズ 30 override public int Size 31 { 32 get 33 { 34 int size = 0; 35 foreach (Entry entry in directory) 36 { 37 size += entry.Size; 38 } 39 return size; 40 } 41 } 42 43 // コンストラクタ 44 public Directory(string name, int k) : base(name, k) 45 { 46 string s = k.ToString("D"); 47 name = name + s; 48 this.name = name; 49 this.num = k; 50 } 51 52 // 追加 53 public Directory Add(Directory sub, TextBox supar, Control c) 54 { 55 int i = 0; 56 Directory su = new Directory("su", Form1.k); 57 foreach (Directory supe in directory) 58 { 59 if (supe.Name == ((WindowsFormsApp1.Directory)c).Name) 60 { 61 break; 62 } 63 i++; 64 } 65 directory.Add(sub); 66 cop.Add(sub); 67 cont = (Directory)cop[i]; 68 sub.supnode.Add(supar); 69 con.Add(cont); 70 return this; 71 } 72 73 public int HeightS(int k) 74 { 75 string nam; 76 int h = 0; 77 string s = k.ToString("D"); 78 nam = "tb" + s; 79 foreach (Directory tbs in directory) 80 { 81 82 if (tbs.name == nam) 83 { 84 h += 50; 85 } 86 } 87 return h; 88 } 89 90 public static void LinkGraph() 91 { 92 Graphics f = Form1.ActiveForm.CreateGraphics(); 93 Graphics g = Form1.ActiveForm.CreateGraphics(); 94 95 //背景色を更新 96 f.Clear(color: SystemColors.Control); 97 98 //pen作成 99 Pen redPen = new Pen(Color.Red, 10); 100 foreach (Directory sub in directory) 101 { 102 foreach (TextBox sup in sub.supnode) 103 { 104 //始点と終点 105 Point Start_point = new Point(sub.Left + sub.Width / 2, sub.Top + sub.Height / 2); 106 Point End_point = new Point(sup.Left + sup.Width / 2, sup.Top + sup.Height / 2); 107 //描画 108 g.DrawLine(redPen, Start_point, End_point); 109 } 110 } 111 redPen.Dispose(); 112 } 113 } 114}

他にもまずいところは多くありますが、直していません。

一応説明通りに動くはずです。

投稿2017/12/26 02:32

編集2017/12/26 08:22
Zuishin

総合スコア28660

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kaisen

2017/12/26 02:53 編集

Zuishinさん。お世話になっております。 回答ありがとうございます。 >バインドする方とされる方を逆にしてください。 cont.DataBindings.Add(new Binding("Top", sup, "Top")); cont.DataBindings.Add(new Binding("Left",sup , "Left")); のようにしたところ、 ”” 例外がスローされました: 'System.ArgumentException' (System.Windows.Forms.dll の中) 型 'System.ArgumentException' のハンドルされていない例外が System.Windows.Forms.dll で発生しました これにより、コレクション内の 2 つのバインドが同じプロパティにバインドされます。 ”” というエラーが出てしまいました。 重ね重ね質問して申し訳ありません。 どうすればうまくいくでしょうか?
kaisen

2017/12/26 02:54

回答ありがとうございます。 試してきます。
kaisen

2017/12/26 03:15 編集

すこし、調べてきたのですが、 WPFに関するBindingModeの設定の仕方の情報はたくさんあるみたいなのですが、 Windowsフォームアプリケーションにおける設定の仕方が見当たりませんでした。 OneWayの指定の方法についても、できれば教えていただきたいです。。お願いします。
Zuishin

2017/12/26 03:15

リンクしましたが…… コンストラクタで指定したいのであれば関連項目を読んでみてください。
kaisen

2017/12/26 03:33

回答ありがとうございます。 新しいリンク先と、関連項目を調べました。 どうやら、 コンストラクタに方向を指定するためのパラメータはないように見えます。 なにか、ほかに方法があるのでしょうか。。
Zuishin

2017/12/26 03:37

WPF の Binding とごっちゃにしてしまったようです。 このようにしてください。 https://stackoverflow.com/questions/39129557/one-way-binding myForm.DataBindings.Add(new Binding("Items", ItemsController.Singleton, "Items") { DataSourceUpdateMode = DataSourceUpdateMode.OnPropertyChanged, ControlUpdateMode = ControlUpdateMode.Never });
kaisen

2017/12/26 03:38

回答ありがとうございます。 さっそく試してきます。
kaisen

2017/12/26 03:47

試してきました。 cont.DataBindings.Add(new Binding("Top", sup , "Top") { DataSourceUpdateMode = DataSourceUpdateMode.OnPropertyChanged, ControlUpdateMode = ControlUpdateMode.Never }); cont.DataBindings.Add(new Binding("Left", sup, "Left") { DataSourceUpdateMode = DataSourceUpdateMode.OnPropertyChanged, ControlUpdateMode = ControlUpdateMode.Never }); のようにしました。 しかし、さきほどと同じ例外がでてしまいました。 リンク先の方ではこれで解決しているようですが、 なにか、変更の仕方がまずかったのでしょうか。。
Zuishin

2017/12/26 03:53

DataSourceUpdateMode を Never に ControlUpdateMode を OnPropertyChanged にしてみたらどうですか? DataSource はバインドする側(sup)で Control はバインドされる側(cont)です。 これにより sup のプロパティを変更しても cont のプロパティは変更されなくなります。 しかし cont のプロパティを変更すると sup のプロパティは変更されます。
kaisen

2017/12/26 03:56

回答ありがとうございます。 どうやら理解が追い付いてなかったみたいです。 失礼しました。 試してきます。
kaisen

2017/12/26 04:03

試してきました。 cont.DataBindings.Add(new Binding("Top", sup , "Top") { DataSourceUpdateMode = DataSourceUpdateMode.Never, ControlUpdateMode = ControlUpdateMode.OnPropertyChanged }); cont.DataBindings.Add(new Binding("Left", sup, "Left") { DataSourceUpdateMode = DataSourceUpdateMode.Never, ControlUpdateMode = ControlUpdateMode.OnPropertyChanged }); に変更しました。 同じ例外です。理解できたと思ったのですが。。
Zuishin

2017/12/26 04:06

ダメでしたか。 後で実際に試してから書きます。
kaisen

2017/12/26 04:08

とても助かります、ありがとうございます。
Zuishin

2017/12/26 04:23

Form1.k, directory, cop, supnode などが未定義です。 コンパイルの通るソースをお願いします。
kaisen

2017/12/26 04:49

わかりました。少々お待ちください。
kaisen

2017/12/26 23:21 編集

//program.cs 編集削除済み。
kaisen

2017/12/26 23:21 編集

//Form1.cs 編集削除済み。
kaisen

2017/12/26 23:21 編集

//Entry.cs 編集削除済み。
kaisen

2017/12/26 23:22 編集

//Directory.cs 編集削除済み。 いずれも ひどいスパゲティソースでしたので。。17/12/27/8:00
kaisen

2017/12/26 04:58

以上になります。
kaisen

2017/12/26 05:01

どれを抜き出せばいいのか よくわからないので、 ソースコードのすべてをコピペしてしまいました。
Zuishin

2017/12/26 07:49

ちょっと言葉の確認をさせてください。 Top と Left をバインドするとすべての Directory が同じ位置になってしまいますが、そうすると質問本文の意味と異なってきます。 また親子関係についてもそうです。 「バインド」「親子」の意味を確認しつつ質問を整理してもらえますか? 現状では、テキストボックスで Enter を押すと、その右下に新たなテキストボックスができて「Hello」と表示されます。 本来ならどうなる予定ですか?
kaisen

2017/12/26 08:02 編集

言葉についての整理は時間がかかりそうなので、少し待ってください。 申し訳ありません。 ただ、今達成しようとしている動作についてはお話しできます。 テキストボックスでEnterを押して、新しいテキストボックスが生成されたら、 その状態で、Alt+矢印キーを押してみてください。 そうすると、フォーム左上に対して、そのテキストボックスから 赤い線が伸びるはずです。 その赤い線をフォーム左上ではなく、 テキストボックスを生成する際にフォーカスがあった もう一つのテキストボックスから伸びるようにしたいです。
kaisen

2017/12/26 08:02

まず説明しやすそうなところから順番に書きます。 親子関係についてですが、 これは、テキストボックスを生成する際にフォーカスが当たっていたほうを 親とし、フォーカスが移ったほうの新しいテキストボックスを子とします。
kaisen

2017/12/26 08:18 編集

1.Addメソッド時に取得したアクティブなContrlolを入れるための リストとして、DirectoryのグローバルにArrayListを作る. 2.LinkGraphメソッドにおいて、 そのリストをforeachをしようとする. 3.失敗する. ので、 LinkGraphのために、Controlの配列ではなく、 そのControlのTop、LeftをバインドさせたArrayList.supnodeを 作ろうと思ったことがきっかけで実装しようとしました。 Arraylist.supnodeはstaticではないことと、 Arraylist.directoryは逆にstaticであることによって、 全てのDirectoryのTop,Leftが同じ位置になることはないと思います。
Zuishin

2017/12/26 08:18

了解しました。バインドという言葉が私の思っていたものと違いました。 言葉が共通していないとコミュニケーションが取れませんので、次回からは独自の用語は説明してください。 回答を編集します。
kaisen

2017/12/26 08:20

失礼しました。。 バインドという用語を私は間違っていたことにすら気づけず、 恥ずかしい限りです。 手間をかけさせてしまって申し訳ありません。
kaisen

2017/12/26 08:30

編集後のコードを実行しました。 言葉足らずで失礼しました。。 大変申し訳ないのですが、 いくつかテキストボックスを生成した後に、 shift+Enterキーで、一つ前に生成したテキストボックスAに戻って、 Enterキーを入力していただいた後、 生成されたテキストボックスBを動かしてみてもらえないでしょうか? このときに、生成されたテキストボックスBがテキストボックスAに 対して、赤い線を伸ばすのが私の目標とする動作です。 長々とお付き合いいただいて恐縮です。
Zuishin

2017/12/26 08:33

最初にフォームに張り付けたのは TextBox です。 Directory ではありません。 これが親になれるように TextBox にキャストしています。 これを Directory にしてソース中の TextBox にキャストしているところを Directory にすれば直るのではないかと思います。 私はこれから出かけなければならないので見ておいてください。
kaisen

2017/12/26 08:35

回答ありがとうございます。 はい、見ておきます。
Zuishin

2017/12/26 08:37

あと、他に直さなければならないところは多くあると言いました。 正直このスパゲッティソースを完全なものになるようメンテナンスする気にはなれません。 最初から書き直したいくらいですが、そこまでする気もありません。 やっつけで応急処置だけしました。 当面質問された問題は解決したと思うので、他の問題についてはまた改めてください。
kaisen

2017/12/26 09:02 編集

ごめんなさい! 焦っていて部分的にしか回答していただいたコードを取り込んいなかったようです。 Zuishinさんにいただいたとおりのコードを丸々全部コピーして 動かしたところ、 まさに私がここ最近、ずっと取り組んでいた課題のうちでも 核心的な部分が解決できているのを見ることができました!! すこし、目線が足元に向きすぎていたようです。 Zuishin様、 改めて、応答が拙くて申し訳ありませんでした。 本当に助かりました、 ありがとうございました!!!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問