C#、listboxについての質問です。

二つのリストボックスがあるとします。
・listBox1
・listBox2

listBox1にはアイテムが複数セットされている状態です。
アイテムが選択されいている状態でrightbuttonをクリックすると
listBox2にアイテムが移動します(lisytBox1でそのアイテムはremove)

もしかしたら間違えてlistBox2に移動する可能性もあるので2から1へ
アイテムを戻すlefghtbuttonも用意します。

そこで質問です。
そのときに2から1へ戻ったとき、普通にAdd()するのではなく、移動する前の状態の位置に戻したいのです。

普通にやると末端に追加されます。

ロジックが思いつきません。
お力添えのほどよろしくお願いいたします。

A 回答 (4件)

listBox1に追加するオブジェクトに,本来の並び順を保持させておいて,


戻す時にはオブジェクトの並び順を見てInsertする位置を決めればよいでしょう。

ListBoxに追加できるのは文字列だけでなく,どんなオブジェクトでも追加できます。
また,要素の表示はListBoxのDisplayMemberで決定されますが,DisplayMemberを指定していない場合はToStringが使われます。

なので,
class Item : IComparable<Item>
{
public Item (string display, int defaultOrder)
{
Display = display;
DefaultOrder = defaultOrder;
}

public string Display { get; private set; }
public int DefaultOrder { get; private set; }

int IComparable<Item>.CompareTo (Item other)
{
if (other == null) { return 1; }
return DefaultOrder.CompareTo(other.DefaultOrder);
}

public override string ToString ()
{
return Display;
}
}
というようなクラスを作り,このItemクラスをlistBox1, listBox2の要素としておけば,
var pos = listBox1.Items.Cast<Item>().ToList().BinarySearch(addItem);
if (pos < 0) { pos = ~pos; }
listBox1.Items.Insert(pos, addItem);
で戻すことができます。
    • good
    • 0

というワケで…簡単に作ってみました。


検証不十分と思われますので、地道に検証してくださいな。

ちなみに、プロパティでbutton1(rightbutton相当)とbutton2(lefghtbutton相当)のEnabledはfalseに、
listBox1のItemsにはあらかじめデータ入れておいてください。
あと、全角空白でインデントしていますのでよろしく処理してください。
コメントも特に入れていないので自力で読んでください。

public partial class Form1 : Form
{
 private Stack<MoveItemHistory> History;
 public Form1()
 {
  InitializeComponent();
  History = new Stack<MoveItemHistory>();
 }
 private void button1_Click(object sender, EventArgs e)
 {
  MoveItemHistory temp = new MoveItemHistory();

  temp.Index = listBox1.SelectedIndex;
  temp.ItemString = (string)listBox1.Items[temp.Index];
  listBox2.Items.Add(temp.ItemString);
  listBox1.Items.RemoveAt(temp.Index);
  listBox1.SelectedIndex = -1;
  History.Push(temp);
  button2.Enabled = true;
 }
 private void button2_Click(object sender, EventArgs e)
 {
  MoveItemHistory temp = History.Pop();

  button2.Enabled = (History.Count > 0);
  listBox2.Items.Remove(temp.ItemString);
  listBox1.Items.Insert(temp.Index, temp.ItemString);
 }
 private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
 {
  button1.Enabled = (listBox1.SelectedIndex != -1);
 }
}
public class MoveItemHistory
{
 public int Index;
 public string ItemString;
}
    • good
    • 0

>そうするとlistBox1の5番目[りんご]


>をlistBox2に移動し、他のアイテムも複数移動したら
>listBox1の配列のCountは(例えば)2つとかになりますよね。
>listBox2からlistBox1に戻すときに5番目、(移動するときに持っていたindex=5)にインサートしたら、配列範囲外になりませんか?

だから、「最後の1つだけ…とか制限付くと思いますけども。」と書いたのですが……。

そういう制限なしでやりたいというのであれば、履歴を持ち続けるしかないでしょうね。
で、lefghtbuttonのたびに履歴から操作することに。
# 履歴を格納する構造体なり作って、List構造として記録…でしょうかねぇ。
# List<T>とかで。
# スタック構造でもいいのか…そういうのがあったかはちょっと不明ですが。
# 「C# アンドゥ 実装」辺りで検索するとよさげなものが見つかるかも知れませんね。
    • good
    • 0

>そこで質問です。


>そのときに2から1へ戻ったとき、普通にAdd()するのではなく、移動する前の状態の位置に戻したいのです。

ListBox.Items.Insert()ですかね。

最後の1つだけ…とか制限付くと思いますけども。
rightbuttonで移動(というかlistBox1から削除)する前にインデックスを記憶…
lefghtbuttonで戻す時に記録していたインデックスを元にInsert()
ってところでしょうかね。

listBox1の先頭のアイテムや最後のアイテムだった場合に正しく動作するか?
というのはちゃんと確認してくださいな。

この回答への補足

listBox1の総数を5こだとします。
そうするとlistBox1の5番目[りんご]
をlistBox2に移動し、他のアイテムも複数移動したら
listBox1の配列のCountは(例えば)2つとかになりますよね。
listBox2からlistBox1に戻すときに5番目、(移動するときに持っていたindex=5)にインサートしたら、配列範囲外になりませんか?

また、listbox1から2へいくつか移動した後から戻したとすると、
indexは混同しませんか?

という感じで悩んでおります。。。
未熟者故、うまいロジックが思いつかないのです。

せっかく教えて下さったのですが、今一度お力添えをお願いいたします><

補足日時:2014/08/20 16:31
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人が検索しているワード

このQ&Aと関連する良く見られている質問

QDelphi .net ListBoxで上下キーで移動したい

Delphi .net WEB版での作成です。

LISTBOXを作成するソースがあります。

---
while 条件 do
begin
LstBox1.Items.Insert(Row,Text);
LstList.Items.Item[Row].value := LstValue;
end;
---

リストボックスは作成されますが、
上下キーで項目の移動ができません。
この作成をPage_Load の度に行えばできるのですが
作成処理は重いので、作成は1回のみで行いたいです。

どのようにすればよろしいのでしょうか?

Aベストアンサー

一般的なユーザインタフェースの観点からアドバイス申し上げます。

「項目の移動」というのは項目の位置を変える(項目が1234と並んでいるのを2134のようにする)ことだと推察しますけれども、通常、上下キーは項目の選択に使いますので、移動には使わない方がよいのではないでしょうか。ListBox内の項目を移動するインタフェースでよくあるのは、選択した項目を上移動ボタン、下移動ボタンで動かすというものです。

具体的には、例えばWindowsXP + Delphi2007 VCLフォームアプリケーションでは下記のようになります。WEB版でも同様な考え方でできると思います。

-----
procedure TForm1.UpButtonClick(Sender: TObject); // 上移動ボタンの処理
var
ItemIndex: integer;
begin
ItemIndex:=ListBox1.ItemIndex;
if ItemIndex>=1 then
ListBox1.Items.Exchange(ItemIndex, ItemIndex-1); // 上の項目と交換
end;

procedure TForm1.DownButtonClick(Sender: TObject); // 下移動ボタンの処理
var
ItemIndex: integer;
begin
ItemIndex:=ListBox1.ItemIndex;
if (ItemIndex<>-1) and (ItemIndex<(ListBox1.Items.Count-1)) then
ListBox1.Items.Exchange(ItemIndex, ItemIndex+1); // 下の項目と交換
end;
-----

更に、項目が選択されていて移動できるときだけボタンをEnableにすれば、洗練されたインタフェースになるでしょう。

また、同じ項目を指定することが多いのでしたら選択した項目を自動的に一番上に移動しておく等も考えられます。(そもそも項目の位置が変わる/変えられることが使いやすいかどうかはよく考えた方がよいと思いますが)

一般的なユーザインタフェースの観点からアドバイス申し上げます。

「項目の移動」というのは項目の位置を変える(項目が1234と並んでいるのを2134のようにする)ことだと推察しますけれども、通常、上下キーは項目の選択に使いますので、移動には使わない方がよいのではないでしょうか。ListBox内の項目を移動するインタフェースでよくあるのは、選択した項目を上移動ボタン、下移動ボタンで動かすというものです。

具体的には、例えばWindowsXP + Delphi2007 VCLフォームアプリケーションでは下記のように...続きを読む

QC# ListBoxのキーボードマッチを無効にしたい

お世話になります。
.NET FW2.0+C#でListBoxを使用しています。

ListBox(ドロップダウンリスト)にはフォーカスしている状態でキーボードの英数キーを押すとリスト内のValue先頭値と自動的にマッチするものを選択状態とする機能が標準で備わっていますが、これを無効とする方法はありますでしょうか。

プロパティでは該当するものがなかったようです。
http://msdn.microsoft.com/ja-jp/library/system.windows.forms.listbox_properties(VS.80).aspx#

イベント処理で何とかするしかないのでしょうか。それともプロパティの見落としか・・・・

可能であれば方法など教えて頂けると助かります。

Aベストアンサー

ListBoxのKeyPressイベントを処理するようにしましょう

イベントハンドラを
private void listBox1_KeyPress(object sender, KeyPressEventArgs e)
{
  // キーは処理済ですといったことになる
  e.Handled = true;
}
といった具合で定義しておきます

this.listBox1.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.listBox1_KeyPress);
といった具合で イベントハンドラをInitializeComponentなどで接続します

QMATLAB 正規化近似式をもとの状態に戻すには?

MATLAB初心者です。
データを正規化し(各々のデータからデータの平均値を引き、データの標準偏差で割る)多項式の近似式を求めた後、もとの状態(正規化を外した状態)の近似式にしたいのですが、どのようにすれば良いのか分かりません。

どのようにすれば良いのか教えて下さい。

Aベストアンサー

>各々のデータからデータの平均値を引き、データの標準偏差で割る
って操作をしたなら、
近似式にデータの標準偏差を掛けて、データの平均値を足せば、いいのでは。

QListBoxの最大表示項目数について

お世話になります。

vbaのフォーム上にListBoxを配置し、ColumnCountを13と定義しましたが、
ColumnHeadsをTrueにし、項目数を見てみると10項目しか表示されません。

実際に実行してみて、仮の値を設定してみても、10項目しか表示されません。

Webで検索してみましたが、「255文字の上限では」と似たような質問の回答を確認しましたが、
13項目の値を全て足しても200文字に届きません。

11項目以上は表示できないのでしょうか。

環境はExcel2000,2002で確認をいたしました。

原因をご存知の方、ご教授下さいますようよろしくお願いいたします。

Aベストアンサー

ListBoxのヘルプには次のような文言があります
-------------------------------------------------
●非連結データ ソースの場合は、最大 10 列 (0 ~ 9) までの制限があります。
------------------------------------------------

で、リストのソースをシートに用意して
例えば、Sheet1 の A1~M34 にリストソースがある場合

ListBox1.RowSource = "Sheet1!A1:M34"

 とか

ListBox1.List = Sheets("Sheet1").Range("A1:M34").Value

それか、リストソースを配列に用意して

ListBox1.List = myArray

以上。
 

QC# LISTBOXの複数項目取得

お世話になります。
WindowsFormで、リストボックスを使い開発をしています。
状況としては、Bindingsourceとデータセットを使用し、検索してきたものを表示。
この時、DisplayMenberとValueには違う値を設定しています。
やりたいことは
ボタンクリック時に、複数選択している項目のValueを取得したいと思っています。
よろしくお願いします。

Aベストアンサー

確かに、これはわかりにくいですね・・・。

using System;
using System.Data;
using System.Diagnostics;
using System.Windows.Forms;

namespace CsListBoxTest
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

private void Form1_Load(object sender, EventArgs e)
{
this.table1TableAdapter.Fill(this.tESTDataSet2.Table1);
}

private void button1_Click(object sender, EventArgs e)
{
foreach (DataRowView drv in listBox1.SelectedItems)
{
Debug.WriteLine(drv.Row.ItemArray[1]);
}
}
}
}

確かに、これはわかりにくいですね・・・。

using System;
using System.Data;
using System.Diagnostics;
using System.Windows.Forms;

namespace CsListBoxTest
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

private void Form1_Load(object sender, EventArgs e)
{
this.table1TableAdapter.Fill(this.tESTDataSet2.Table1);
}

private void button1_Click(object sender,...続きを読む


人気Q&Aランキング

おすすめ情報