0

ObjectListViewコントロールのデモには、カスタムエディター(ComboBox)を使用できるようにするための次のコード([複雑な例]タブページ)があります(私の場合に適合し、わかりやすくするために編集しました)。

EventHandler CurrentEH;
private void ObjectListView_CellEditStarting(object sender,
                                             CellEditEventArgs e)
{
    if (e.Column == SomeCol)
    {
        ISomeInterface M = (e.RowObject as ObjectListView1Row).SomeObject; //(1)
        ComboBox cb = new ComboBox();
        cb.Bounds = e.CellBounds;
        cb.DropDownStyle = ComboBoxStyle.DropDownList;
        cb.DataSource = ISomeOtherObjectCollection;
        cb.DisplayMember = "propertyName";
        cb.DataBindings.Add("SelectedItem", 
                            M, "ISomeOtherObject", false,
                            DataSourceUpdateMode.Never);
        e.Control = cb;
        cb.SelectedIndexChanged += 
            CurrentEH = (object sender2, EventArgs e2) =>
                M.ISomeOtherObject = 
                    (ISomeOtherObject)((ComboBox)sender2).SelectedValue;   //(2)
    }
}

private void ObjectListView_CellEditFinishing(object sender,
                                               CellEditEventArgs e)
{
    if (e.Column == SomeCol)
    {
        // Stop listening for change events
        ((ComboBox)e.Control).SelectedIndexChanged -= CurrentEH;
        // Any updating will have been down in the SelectedIndexChanged
        // event handler.
        // Here we simply make the list redraw the involved ListViewItem
        ((ObjectListView)sender).RefreshItem(e.ListViewItem);
        // We have updated the model object, so we cancel the auto update
        e.Cancel = true;
    }
}

objectlistviews内にコンボエディターを備えた他の列が多すぎて、コピーアンドペースト戦略を使用できません(さらに、コピーアンドペーストは深刻なバグの原因です)。そのため、コードの重複を最小限に抑えるためにコードをパラメーター化しようとしました。ObjectListView_CellEditFinishingは簡単です。

HashSet<OLVColumn> cbColumns = new HashSet<OLVColumn> (new OLVColumn[] { SomeCol, SomeCol2, ...};

private void ObjectListView_CellEditFinishing(object sender,
                                               CellEditEventArgs e)
{
    if (cbColumns.Contains(e.Column)) ...

しかし、ObjectListView_CellEditStartingには問題があります。

CellEditStartingでは、それぞれのケースを個別に区別する必要があると思います。

private void ObjectListView_CellEditStarting(object sender,
                                             CellEditEventArgs e)
{
    if (e.Column == SomeCol)
        // code to create the combo, put the correct list as the datasource, etc.
    else if (e.Column == SomeOtherCol)  
        // code to create the combo, put the correct list as the datasource, etc.

等々。

しかし、「コンボを作成するコード、データソースとして正しいリストを配置するコードなど」をパラメーター化するにはどうすればよいでしょうか。問題のある行は

(1)SomeObjectを取得します。プロパティNAMEは異なります。

(2)ISomeOtherObjectを設定します。プロパティ名も異なります。

タイプもさまざまですが、それほど「タイプセーフ」ではないAPIと組み合わせたジェネリックメソッドでこれらのケースをカバーできます(たとえば、cb.DataBindings.Addとcb.DataSourceは両方ともを使用しますobject

反射?より多くのラムダ?何か案は?同じことをする他の方法はありますか?

PS:私はこのようなことをしたいです:

private void ObjectListView_CellEditStarting(object sender,
                                             CellEditEventArgs e)
{
    if (e.Column == SomeCol)
        SetUpCombo<ISomeInterface>(ISomeOtherObjectCollection,
                                   "propertyName",
                                   SomeObject,
                                   ISomeOtherObject);

    else if (e.Column == SomeOtherCol)  
        SetUpCombo<ISomeInterface2>(ISomeOtherObject2Collection,
                                   "propertyName2",
                                   SomeObject2
                                   ISomeOtherObject2);

等々。またはそのようなもの。

パラメータSomeObjectとISomeOtherObjectは、実際のパラメータではありませんが、私が何を求めているかはわかります。同じコードスケルトンを何度も繰り返さないようにしたい。

1つの解決策は、CのDEFINEのような「プリプロセッサジェネリック」ですが、c#にそのようなものがあるとは思いません。

それで、誰かがこれを解決するためのいくつかの代替案を持っていますか?

4

1 に答える 1

0

それを見つけた。Tejsに称賛を!

private void SetUpCombo(CellEditEventArgs e, 
                        object ComboItems, string DisplayMember,
                        object DataSource, string PropertyName,
                        EventHandler evt)
{
    ComboBox cb = new ComboBox();
    cb.Bounds = e.CellBounds;
    cb.DropDownStyle = ComboBoxStyle.DropDownList;
    cb.DataSource = ComboItems;
    cb.DisplayMember = DisplayMember;
    cb.DataBindings.Add("SelectedItem", DataSource, PropertyName,
                            false, DataSourceUpdateMode.Never);
    e.Control = cb;
    cb.SelectedIndexChanged += CurrentEH = evt;
}

そして書き直された CellEditStarting:

private void ObjectListView_CellEditStarting(object sender,
                                             CellEditEventArgs e)
{
    if (e.Column == SomeCol)
    {
        ISomeInterface M = (e.RowObject as ObjectListView1Row).SomeObject; 
        SetUpCombo(e, 
                   ISomeOtherObjectCollection,"propertyName",
                   M, "ISomeOtherObject",
                   (sender2, e2) =>
                       M.ISomeOtherObject = 
                           (ISomeOtherObject)((ComboBox)sender2).SelectedValue);
    }
    else if (e.Column == SomeOtherCol)  
    {
        ISomeInterface2 M = (e.RowObject as ObjectListView1Row).SomeObject2; 
        SetUpCombo(e, 
                   ISomeOtherObjectCollection2,"propertyName2",
                   M, "ISomeOtherObject2",
                   (sender2, e2) =>
                       M.ISomeOtherObject2 = 
                           (ISomeOtherObject)((ComboBox)sender2).SelectedValue);
    }

などなど… まだ気に入らないところがあります。例: M.ISomeOtherObject (メソッド呼び出しの外側)、「ISomeOtherObject」 (パラメーター)、および M.ISomeOtherObject の設定 (ラムダの内側) の間の切断。

しかし、すべてのことを考慮すると、同じコードを何度もコピーして貼り付けるよりもはるかに優れています)。

于 2012-11-07T16:58:24.293 に答える