C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[5]: 別スレッドの連想配列をフォームに追加・取得


(過去ログ 106 を表示中)

[トピック内 7 記事 (1 - 7 表示)]  << 0 >>

■63348 / inTopicNo.1)  別スレッドの連想配列をフォームに追加・取得
  
□投稿者/ es (1回)-(2012/08/17(Fri) 23:14:36)

分類:[C#] 

初めまして、いろいろと検索をかけましたが、解決に至りませんでしたので質問させて頂きます。
よろしくお願いします。

開発環境:VS2010

別スレッドで作成したDictionary<string,string>のキーだけを、フォームのComboBox.Itemsに追加した後
選択されたキーの値を取得、までしたいのですが

下記のサンプルコードだと取得できませんでした。
汚くて申し訳ございません。


//Thread.cs
class SampleThread
    {
        public Form1 form;
        Thread startThread;

        public void start()
        {
            this.startThread = new Thread(new ThreadStart(this.main));
            this.startThread.IsBackground = true;
            this.startThread.Start();
        }

        public void main()
        {
            Dictionary<string, string> data = new Dictionary<string, string>();

            data.Add("abc", "123");
            data.Add("def", "456");
            data.Add("ghi", "789");

            this.form = new Form1();
            foreach (string key in data.Keys)
            {
                form.SetComboData(string.Format(key, data[key]));
            }
        }
    }

//form.cs
public partial class Form1 : Form
    {
        public delegate void ComboControl(string dText);
        public ComboControl SetComboData;

        public Form1()
        {
            InitializeComponent();
            this.SetComboData = new ComboControl(this.ComboData);
        }

        public void ComboData(string dText)
        {
            if (this.InvokeRequired)
            {
                this.Invoke(SetComboData, dText);
            }
            else
            {
                this.comboBox1.Items.Add(dText);
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            SampleThread a = new SampleThread();
            a.start();
        }
    }

引用返信 編集キー/
■63349 / inTopicNo.2)  Re[1]: 別スレッドの連想配列をフォームに追加・取得
□投稿者/ Azulean (19回)-(2012/08/18(Sat) 00:04:05)
2012/08/18(Sat) 00:04:46 編集(投稿者)

No63348 (es さん) に返信
> 下記のサンプルコードだと取得できませんでした。
> 汚くて申し訳ございません。

すでに表示してある Form1 とは別にスレッドで Form1 を作っていますので、表示には影響しません。
この手のケースではイベントを作るとよいでしょう。

クラスとインスタンスについても勉強してみてください。


// 安直に button1_Click で a.Form = this; とすればできるけど。
// 相互参照でよくわからなくなるのであんまりおすすめしません。
引用返信 編集キー/
■63350 / inTopicNo.3)  Re[1]: 別スレッドの連想配列をフォームに追加・取得
□投稿者/ shu (34回)-(2012/08/18(Sat) 00:06:03)
No63348 (es さん) に返信

> this.form = new Form1();
これ不要。表示されているForm1とは別のインスタンスになります。

> foreach (string key in data.Keys)
> {
> form.SetComboData(string.Format(key, data[key]));
> }
> }
> }


> //form.cs
> public partial class Form1 : Form
> {
> public delegate void ComboControl(string dText);
> public ComboControl SetComboData;
>
> public Form1()
> {
> InitializeComponent();
> this.SetComboData = new ComboControl(this.ComboData);
> }
>
> public void ComboData(string dText)
> {
> if (this.InvokeRequired)
> {
> this.Invoke(SetComboData, dText);
> }
> else
> {
> this.comboBox1.Items.Add(dText);
> }
> }
>
> private void button1_Click(object sender, EventArgs e)
> {
> SampleThread a = new SampleThread();
a.form = this;
を追加

> a.start();
> }
> }
>
引用返信 編集キー/
■63356 / inTopicNo.4)  Re[2]: 別スレッドの連想配列をフォームに追加・取得
□投稿者/ es (3回)-(2012/08/19(Sun) 17:14:32)
Azuleanさん、shuさん
ご回答ありがとうございます。
初歩的なミスで申し訳ございません。
あれからなんとか、ComboBoxにキーだけを追加まではできたのですが
別スレッドからのSelectedItemの取得ができません。

//SampleThread.cs
class SampleThread
    {
        public Form1 form;
        Thread startThread;

        public void start()
        {
            this.startThread = new Thread(new ThreadStart(this.main));
            this.startThread.IsBackground = true;
            this.startThread.Start();
        }

        public void main()
        {
            //本来このスレッドは常時反復しています。
            //ComboBoxに追加するのは一度だけです。
            string key = "abc";
            string value = "123";
            form.SetComboData(key, value);
            
            //常時取得しています。
            MessageBox.Show(form.GetSelectedCode);
        }
    }

//form.cs
public partial class Form1 : Form
    {
        public delegate void ComboControl(string name, string code);
        public ComboControl SetComboData;

        public Form1()
        {
            InitializeComponent();
            this.SetComboData = new ComboControl(this.ComboData);
        }

        public void ComboData(string name, string code)
        {
            if (this.InvokeRequired)
            {
                this.Invoke(SetComboData, name, code);
            }
            else
            {
                this.comboBox1.Items.Add(new Combo(name, code));
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            SampleThread a = new SampleThread();
            a.form = this;
            a.start();
        }

        public string GetSelectedCode
        {
            //ここをInvokeで処理する方法がわかりません。
            get
            {
                Combo data = (Combo)comboBox1.SelectedItem;
                return data.GetComboCode();
            }
        }
    }

    public class Combo
    {
        public String ComboName;
        public String ComboCode;
        public Combo(String ComboName, String ComboCode)
        {
            this.ComboName = ComboName;
            this.ComboCode = ComboCode;
        }
        public override string ToString()
        {
            return ComboName;
        }
        public string GetComboCode()
        {
            return ComboCode;
        }

    }

引用返信 編集キー/
■63357 / inTopicNo.5)  Re[3]: 別スレッドの連想配列をフォームに追加・取得
□投稿者/ Azulean (20回)-(2012/08/19(Sun) 18:56:56)
2012/08/19(Sun) 18:57:30 編集(投稿者)

No63356 (es さん) に返信
> あれからなんとか、ComboBoxにキーだけを追加まではできたのですが
> 別スレッドからのSelectedItemの取得ができません。

問題を的確に表せていません。
「SelectedItem が取得できない」ではなく、「プロパティの場合に Invoke の書き方がわからない」ですよね?

Invoke に渡すのはデリゲートです。
デリゲートは、メソッドの引数・戻り値の組み合わせを定義した型とも言えます。
戻り値を持つデリゲートを自分で定義し、プロパティを取得するメソッドを作り、Invoke の戻り値をキャストすればいいとは思います。

// 個人的にはワーカースレッドでメッセージボックスを表示するという流れに、
// さらなる懸念を感じています。(以前よりも悪化していると言える)
// そういう状況なので、具体的なコードは書きません、あしからず。
引用返信 編集キー/
■63359 / inTopicNo.6)  Re[4]: 別スレッドの連想配列をフォームに追加・取得
□投稿者/ es (5回)-(2012/08/20(Mon) 12:36:44)
No63357 (Azulean さん) に返信
とてもわかりやすい説明をありがとうございます。
お陰様で解決しました。
引用返信 編集キー/
■63438 / inTopicNo.7)  Re[5]: 別スレッドの連想配列をフォームに追加・取得
□投稿者/ Jitta (2回)-(2012/08/25(Sat) 15:09:53)
Jitta さんの Web サイト
No63359 (es さん) に返信
> ■No63357 (Azulean さん) に返信
> とてもわかりやすい説明をありがとうございます。
> お陰様で解決しました。

本当に解決しました?


> // 個人的にはワーカースレッドでメッセージボックスを表示するという流れに、
> // さらなる懸念を感じています。(以前よりも悪化していると言える)

 というか、デバッグ実行しているなら、GetSelectedCode が例外を出さなくなる次に
MessageBox.Show が例外を出しますよね。

 この流れなら、スレッドの側で Invoke 要否を判定するほうが良くない?
 あるいは、「ユーザー介入が必要なタイミング」をスレッド側からイベントとして
通知して、フォーム側で受け入れてやるとか。

// sample
class SampleThread
{
    public event DataCompletedEventHandler DataCompleted;
    public event StartCalcEventHandler StartCalc;

    private void DataCollect()
    {
        List<KeyValuePair<string, string>> data;
        data = new List<...>();
        data.Add(new KeyValuePair<string, string>(...));
        ...
        if (DataCompleted != null)
        {
            DataCompleted(this, new DataCompletedEventArgs(data));
        }
    }
}

class Form1
{
    public Form1()
    {
        InitializeComponent();
        sampleThread.DataCompleted += this.DataCompleted;
    }

    private void DataCompleted(object sender, DataCompletedEventArgs e)
    {
        if (this.InvokeRequired)
        {
            this.Invoke(
                new Action<object, DataCompletedEventArgs>(this.DataCompleted),
                sender,
                e);
            return;
        }

        // 追加処理
    }
}

イベント ハンドラは別途作っておく。

引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -