ArcObjects(ArcGIS for DesktopおよびC#):ArcMap COM UIとカスタム.Net UserControlオブジェクトの間をキャストする方法は?


8

ArcObjects(9.3.1 SDK)とC#.Netを使用して、ArcGIS for Desktopで実行するユーティリティを作成しています。私のプロトタイプには、2つのコンボボックスとツールを備えたツールバーが含まれています。最初のコンボは目次のレイヤーを選択し、2番目のコンボは選択したレイヤーからフィールドを選択します。このツールは、地図を操作するために使用されます。

基本的に、レイヤーを選択し、有効なフィールドを選択してから、マップ内のフィーチャをクリックして、選択したフィールドの値を取得します。役立つ場合は、ツールバーの画像を次に示します。

ここに画像の説明を入力してください

[質問はここからほぼ完全に書き直されました]

私が抱えている問題は、ネイティブCOM UIパーツとカスタム.Netコントロールの間で状態を渡すことです。たとえば、レイヤーコンボボックスでDropDownClosedイベントをキャッチし、そのレイヤーに関連する列の有効なリストをアセンブルし、フィールド名のリストを(IFieldsを介して)フィールドコンボボックスに適用します。

RagiYaserBurhamとblah238による最初のコメントを適用し、これらをこのページの詳細とマージした後、次のDropDownClosedイベントハンドラーはコンボボックスからツールバー(ICommandBar)に戻りますが、ICommandItemからキャストする方法がわかりませんUserControlのFieldsコンボボックスの実装に:

private void layerSelectCBO_DropDownClosed(object sender, EventArgs e)
{
    _completionNotify.SetComplete();

    string layerName = (sender as ComboBox).SelectedItem as string;

    // These two lines are a combination of initial commenter suggestions.
    ICommandItem toolbar = _iApp.Document.CommandBars.Find("ArcProject.UI.AngryToolbar", false, false);
    ICommandItem fieldsItem = (toolbar as ICommandBar).Find("ArcProject.UI.FieldSelectUC", false);

}

では、ここに来たので、fieldsItemをFieldSelectUCにキャストするにはどうすればよいですか。

[ ソリューション ]

blah238が示唆したように、私はICommandItem.CommandをカスタムのUserControl実装にキャストしてみましたが、それでうまくいきました。

まず、FieldSelectUCComboBoxへの参照を返すために、UserControlにパブリックアクセサーを追加する必要がありました。その単純なアクセサーは次のようになります。

// fieldSelectCBO is the name of the combobox control in the design view..
public ComboBox FieldsComboBox { get { return fieldSelectCBO; } }

その変更を行った後、選択したレイヤーのすべてのフィールドをフィールドコンボボックスに入力するDropDownClosedイベントハンドラーを次に示します。

private void layerSelectCBO_DropDownClosed(object sender, EventArgs e)
{
    _completionNotify.SetComplete();

    string layerName = (sender as ComboBox).SelectedItem as string;

    // get the toolbar..
    ICommandItem toolbar = _iApp.Document.CommandBars.Find("ArcProject.UI.AngryToolbar", false, false);

    // get my fields combo by way of CommandItem.Command..
    ICommandItem fieldsCI = (toolbar as ICommandBar).Find("ArcProject.UI.FieldSelectUC", false);
    FieldSelectUC fieldsUC = fieldsCI.Command as FieldSelectUC;
    ComboBox fieldsComboBox = fieldsUC.FieldsComboBox;

    // get the fields for the selected layer..
    IFields fields = null;
    int layerCount = _iDoc.FocusMap.LayerCount;
    int i;
    for (i = 0; i < layerCount; i++)
    {
        if (_iDoc.FocusMap.get_Layer(i).Name == layerName)
        {
            if (_iDoc.FocusMap.get_Layer(i) is FeatureLayer)
            {
                fields = (_iDoc.FocusMap.get_Layer(i) as FeatureLayer).FeatureClass.Fields;
            }
        }
    }

    // Build a list of field names for the combobox items..
    List<string> fieldNameList = new List<string>();
    if (fields != null)
    {
        int fieldCount = fields.FieldCount;
        int j;
        for (j = 0; j < fieldCount; j++)
        {
            string oneFieldName = fields.get_Field(j).Name;
            fieldNameList.Add(oneFieldName);
        }
    }

    // Populate the combobox items..  
    if (fieldNameList.Count > 0)
    {
        fieldsComboBox.Items.Clear();

        foreach (string fieldName in fieldNameList)
        {
            fieldsComboBox.Items.Add(fieldName);
        }

        fieldsComboBox.SelectedItem = fieldsComboBox.Items[0];
    }
    else
    {
        fieldsComboBox.Items.Add("Error: No fields!");
    }
}

これはまだ汚いテストベッドです(したがってAngryToolbar)。しかし、このソリューションは、ICommandとIToolControlを実装する拡張されたUserControlから開始し、.Netコンポーネントにドリルダウンする方法を示しています。私は提案を提供してくれたすべての人の支援に本当に感謝しています。本当にありがとう。:)


layerName変数をpublic staticスコープにするのはどうですか?
アートワーク21

@ artwork21、それは良さそうに聞こえますが、ツールバーの対応するものからいずれかのコンボボックスのインスタンスにアクセスする方法がまだわかりませんか?わかる?それは私が気づいていない単純な基本的なことだと思います。
elrobis

これは別の質問のように聞こえます。なぜそうする必要があるのか​​、私にはよくわかりません。レイヤーコンボに基づいて、フィールドコンボボックスをクリアして再入力する必要があるようです。レイヤーコンボボックスは、ドキュメントイベントリスナーに基づいて入力する必要があります。
Rich Wawrzonek

まさに正しい@RichWawrzonek。しかし、レイヤーコンボからフィールドコンボの既存のインスタンスにアクセスする方法がわかりません。そのためには、ツールで両方の値を読み取る必要があります。
elrobis

回答:


4

私が理解しているように、ICommandとIToolControlを実装するUserControlに2つの.NET ComboBoxがあり、コンボボックスの1つへの参照を他から取得したいとします。それらが同じスコープ内にある限り、変数名でそれらを参照できるはずです(コントロールの名前については、UserControlデザイナーを確認してください)。

2つのコンボボックスが別々のUserControlにある場合はICommandItem.Command、他のUserControlにキャストしてみてください。

いくつかの例については、9.3ヘルプのこのサンプルを参照してください。最近使用したファイル-Command、MultiItem、およびToolControl

また、この問題を説明するESRIフォーラムの投稿もあります。http://forums.esri.com/Thread.asp?c = 93&f = 993&t = 170088


ビンゴ。この行は、インスタンスから私が実装ICommandItemしたUserControlクラスに戻るためのトリックを実行しFieldSelectUC fs = fieldsItem.Command as FieldSelectUC;ました。これで、すべてのプロップがデバッガーに表示されます。どうもありがとうございました。
elrobis

やったー!私はしばらくアドインを特別に使用していたので、それがどのように機能したかを覚えておくためにいくつかの古いものを掘り下げる必要がありました:)この種類のことは10のアドインを使うとはるかに簡単になります(確かに柔軟性が低くなります)は特定のComboBoxタイプであり、静的変数とメソッドを使用して他のアドインコンポーネントを参照するだけで済みます。
blah238

1
うん、確かに新しいアドインを使用する方が簡単に思えました。これを調査したところ、アドインthisとアドインが見つかりましたが、私の実装では使用できませんでした。.NetヘルプのGraphicsLayerToolControlの例(アドレスがである私のシステム上C:\Program Files (x86)\ArcGIS\DeveloperKit\SamplesNET\Desktop\GraphicsLayerToolControl\CSharp\GraphicsLayerToolControl2008.sln)は、UserControlやイベントに関するものを処理するのに役立ちましたが、COMコントロールから.Netに穴を開ける方法を理解できませんでした。私がどれほど感謝しているか誇張することはできません。心から。
elrobis

2

このようなことをするときはいつでも、ツールバーに含まれる静的プロパティセットにレイヤー名とフィールド名を保存します。次に、ドキュメントイベントハンドラーを使用して、レイヤーがArcMapに追加/削除されているかどうか、またはドキュメントが変更されているかどうかを確認します。レイヤーとフィールドのプロパティは、ユーザーがドロップダウンで変更するたびに更新されます。レイヤーがArcMapから削除されるか、ドキュメントが閉じられると、それらはnullにリセットされます。次に、プログラムを実行する前にnull値を確認します。

ICommandItemインターフェイスを介してコンボボックスへの参照を取得します。

ICommandItem toolbar = _iApp.Document.CommandBars.Find( "ArcProject.UI.AngryToolbar"、false、false);
ICommandItem fieldsItem =(ICommandBarとしてのツールバー).Find( "ArcProject.UI.FieldSelectUC"、false); IComboBox cbo =(IComboBox)fieldsItem; //ESRI.ArcGIS.SystemUIへの参照が必要です。


+1すると、簡単に聞こえます。:)しかし、私が持っている問題は、他のコントロールの観点から、すでにインスタンス化されたコントロールのプロパティにアクセスすることです。それらの共有プロパティをツールバーに配置するという考えが気に入っています。回答を更新して、コンボボックスの1つの観点から、含まれているツールバーのプロパティを実際に読み取る方法を示していただけますか?'Cosは基本的に私が求めているものです。ドキュメントイベントを使用して目次への変更をリッスンする方法を既に知っているので、その側面についてのヘルプは必要ありません。お返事をありがとうございます。
elrobis

@elrobisまた、共有状態をICommand自体に配置し(常に1つのインスタンスしかないため)、コントロールにhelp.arcgis.com/en/sdk/10.0/arcobjects_net/componenthelpを
Ragi Yaser Burhum

ラギは正しいです。COMツールバーを使用しているため、コンボボックスのuidをICommandBar.Findメソッドに渡すだけで、参照を取得できます。彼のリンクはそれをすべて説明しています。
Rich Wawrzonek

ラギのアイデアも好きです。しかし、欠けている根本的なものがあります。たとえば、次の行はnullツールバーを返します(thisは、UserControlラベルとコンボボックスを含む)ICommandBar toolbar = this.Parent as ICommandBar;。私を殺しているのは、この種の基本的なUIオブジェクトトラバーサルです。いずれかの提案を実装するためにツールバーに戻る方法がわかりません。(そして、実際には、ツールバーのこれらの変数のアイデアが少し良いです。おそらく、Ragiのアイデアを適用するパブリックゲッターをツールバーに追加することで実現します)。今後ともよろしくお願いいたします。
elrobis

2
this.ParentCOMインターフェイスには有効ではないと思います-これは.NET / Windowsフォームの概念です。「UIをトラバース」するのではなく、IDでICommandにアクセスする必要があります。
blah238

1

カスタムツールで同様の問題が発生しました。ArcGis 10.xのアドインツールバーのボタンで開くカスタムフォームがあります。このフォームには、マップ内のクリックの座標を取得するボタンがあり、スナップが含まれています。ツールを起動してマップ内のクリックを処理することはできましたが、カスタムツールへのキャストが常に失敗したため、フォームに値を返すことができませんでした。解決策は、ESRI.ArcGIS.Desktop.AddInsのAddInを使用することでした。これにより、私のカスタムツールのすべてのプロパティとメソッドに簡単にアクセスできました。ESRIのドキュメントはここにあります:http ://resources.arcgis.com/en/help/arcobjects-net/conceptualhelp/index.html#/Add_in_coding_patterns/0001000000zz000000/

次に、カスタムフォームのボタンのOnClick-Eventからのコードスニペットを示します。

//DESCRIPTION:
//Connect a tool embedded in a Windows Form with the ArcGIS Application Framework.

ESRI.ArcGIS.esriSystem.IUID UIDCls = new ESRI.ArcGIS.esriSystem.UIDClass();
UIDCls.Value = "MyNamespace_MyCustomTool";
IDocument actDoc = (IDocument)ArcMap.Document;
//Finding the customTool
ESRI.ArcGIS.Framework.ICommandItem commandItem = actDoc.CommandBars.Find(UIDCls, false, false); 

if (commandItem == null) 
{ 
   return; 
}

//This cast would fail:
//MyCustomTool_Class actCustomTool2 = (MyCustomTool_Class)commandItem.Command;

MyCustomTool_Class actCustomTool = AddIn.FromID<MyCustomTool_Class (ThisAddIn.IDs.MyCustomTool);
actCustomTool.actFrm = this;

ArcMap.Application.CurrentTool = commandItem;
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.