11

「最も簡単な答えは見つけるのが最も難しい」というケースに遭遇していると思いますが、これを簡単な方法で提供する検索に出くわしたことはありません. これは、既存の VSTO (C#) プロジェクト内のExcel 2010およびVS 2010用です。

DataGridView のソースとして使用したい 4 列のデータを含む Excel ワークシートがあります。(1) 特定のワークシートからデータを取得し、それをカスタム オブジェクトに入力するための C# コード スニペットを提供してもらえますか? (2) オブジェクト (IEnumerable リストなど) を Datagridview にバインドし、(3) グリッドに固有でソース ワークシートにフィードバックする更新および削除機能の一部のスニペット。

ここで多くの情報を求めていることは承知していますが、VSTO 情報の多くはまとまりがなく、必ずしも簡単に見つけられるとは限りません。ありがとう!

4

4 に答える 4

17

編集:すばらしい、ワークシートに更新と削除を戻して、質問の大部分を見逃していることに気付きました。それが可能かどうかはまったくわかりませんが、それによって私のソリューションは価値がないと思います。とにかくここに残しておきます。何らかの形で役立つかもしれません。


なぜVSTOが必要なのですか? 私の知る限り、VSTO は Office アドインに使用されています。しかし、DataGridView にデータを表示したいので、ワークブックにアクセスするだけの WinForms アプリケーションがあると仮定します。この場合、Office Interop を使用してブックを開くだけです。Microsoft.Office.Interop.Excel への参照をプロジェクトに追加し、using Microsoft.Office.Interop.Excel;ステートメントを追加するだけです。

Excel Interop の MSDN リファレンス ドキュメントは、http: //msdn.microsoft.com/en-us/library/ms262200%28v=office.14%29.aspxにあります。

エクセルの部分だけあげますが、残りは他の人がやってくれるかもしれません。

まず、Excel とブックを開きます。

Application app = new Application();
// Optional, but recommended if the user shouldn't see Excel.
app.Visible = false;
app.ScreenUpdating = false;
// AddToMru parameter is optional, but recommended in automation scenarios.
Workbook workbook = app.Workbooks.Open(filepath, AddToMru: false);

次に、どういうわけか正しいワークシートを取得します。いくつかの可能性があります:

// Active sheet (should be the one which was active the last time the workbook was saved).
Worksheet sheet = workbook.ActiveSheet;
// First sheet (notice that the first is actually 1 and not 0).
Worksheet sheet = workbook.Worksheets[1];
// Specific sheet.
// Caution: Default sheet names differ for different localized versions of Excel.
Worksheet sheet = workbook.Worksheets["Sheet1"];

次に、正しい範囲を取得します。必要なデータがどこにあるかを知る方法を指定しなかったので、固定列にあると仮定します。

// If you also know the row count.
Range range = sheet.Range["A1", "D20"];
// If you want to get all rows until the last one that has some data.
Range lastUsedCell = sheet.Cells.SpecialCells(XlCellType.xlCellTypeLastCell);
string columnName = "D" + lastUsedCell.Row;
Range range = sheet.Range["A1", columnName];

値を取得します。

// Possible types of the return value:
// If a single cell is in the range: Different types depending on the cell content
// (string, DateTime, double, ...)
// If multiple cells are in the range: Two dimensional array that exactly represents
// the range from Excel and also has different types in its elements depending on the
// value of the Excel cell (should always be that one in your case)
object[,] values = range.Value;

この 2 次元オブジェクト配列は、DataGridView のデータ ソースとして使用できます。私は何年も WinForms を使用していないので、直接バインドできるのか、最初にデータを特定の形式にする必要があるのか​​ わかりません。

最後にもう一度 Excel を閉じます。

workbook.Close(SaveChanges: false);
workbook = null;
app.Quit();
app = null;
// Yes, we really want to call those two methods twice to make sure all
// COM objects AND all RCWs are collected.
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
GC.WaitForPendingFinalizers();

COM オブジェクトへのすべての参照が解放されていることを確認する必要があるため、Interop を使用した後に Excel を正しく閉じること自体がタスクです。これを行う最も簡単な方法は、Excel とワークブック (最初と最後のコード ブロック) を開いたり閉じたりする以外のすべての作業を別の方法で行うことです。これにより、そのメソッドで使用されるすべての COM オブジェクトは、Quitが呼び出されたときにスコープ外になります。

于 2013-06-07T06:40:29.880 に答える
4

アップデート:

より迅速なアプローチのために、以前の方法を新しいコードに置き換えました。System.Arrayデータを読み取ってExcelにバインドするための非常に効率的で高速な方法です。このリンクからデモをダウンロードできます。


Excel 2003 Workbook で VSTO アプリケーションを開発しました。構文的には大きな違いはありませんので、2007/2010でも問題なく使えます。

ここに画像の説明を入力

データを表示するウィンドウを開くためにどのイベントを使用するのかわかりませんでした。

SheetFollowHyperlink

Showdata.cs で宣言された静的ワークブック オブジェクトを使用します。これがあなたのコードですThisworkbook.cs

 private void ThisWorkbook_Startup(object sender, System.EventArgs e)
        {
            ShowData._WORKBOOK = this;
        }
private void ThisWorkbook_SheetFollowHyperlink(object Sh, Microsoft.Office.Interop.Excel.Hyperlink Target)
        {
            System.Data.DataTable dTable =  GenerateDatatable();
            showData sh = new showData(dTable);
            sh.Show(); // You can also use ShowDialog()
        }

現在のシートにリンクを追加すると、ウィンドウにデータグリッドビューがポップアップ表示されます。

         private System.Data.DataTable GenerateDatatable()
    {
        Range oRng = null;
        // It takes the current activesheet from the workbook. You can always pass any sheet as an argument

        Worksheet ws = this.ActiveSheet as Worksheet;

        // set this value using your own function to read last used column, There are simple function to find last used column
        int col = 4;
        // set this value using your own function to read last used row, There are simple function to find last used rows
        int row = 5;

// メソッド string strRange = "A1"; によって 4 と 5 が返されたと仮定します。文字列 andRange = "D5";

        System.Array arr = (System.Array)ws.get_Range(strRange, andRange).get_Value(Type.Missing);
        System.Data.DataTable dt = new System.Data.DataTable();
        for (int cnt = 1;
            cnt <= col; cnt++)
            dt.Columns.Add(cnt.Chr(), typeof(string));
        for (int i = 1; i <= row; i++)
        {
            DataRow dr = dt.NewRow();
            for (int j = 1; j <= col; j++)
            {
                dr[j - 1] = arr.GetValue(i, j).ToString();
            }
            dt.Rows.Add(dr);
        }
        return dt;
    }

ユーザーが値を表示および編集できるようにするフォームを次に示します。拡張メソッドs と Chr() を追加して、数値をそれぞれのアルファベットに変換すると便利です。

public partial class ShowData : Form
    {
        //use static workbook object to access Worksheets
        public static ThisWorkbook _WORKBOOK;

        public ShowData(System.Data.DataTable dt)
        {
            InitializeComponent();
            // binding value to datagrid
            this.dataGridView1.DataSource = dt;
        }

        private void RefreshExcel_Click(object sender, EventArgs e)
        {
            Worksheet ws = ShowData._WORKBOOK.ActiveSheet as Worksheet;
            System.Data.DataTable dTable = dataGridView1.DataSource as System.Data.DataTable;

            // Write values back to Excel sheet
            // you can pass any worksheet of your choice in ws
            WriteToExcel(dTable,ws);
        }

       private void WriteToExcel(System.Data.DataTable dTable,Worksheet ws)
    {
        int col = dTable.Columns.Count; ; 
        int row = dTable.Rows.Count;

        string strRange = "A1";
        string andRange = "D5";

        System.Array arr = Array.CreateInstance(typeof(object),5,4);
        for (int i = 0; i < row; i++)
        {
            for (int j = 0; j < col; j++)
            {
                try
                {
                    arr.SetValue(dTable.Rows[i][j].ToString(), i, j);
                }
                catch { }
            }

        }
        ws.get_Range(strRange, andRange).Value2 = arr;
        this.Close();
    }
    public static class ExtensionMethods
    {
        static string alphabets = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        public static string Chr(this int p_intByte)
        {

            if (p_intByte > 0 && p_intByte <= 26)
            {
                return alphabets[p_intByte - 1].ToString();
            }
            else if (p_intByte > 26 && p_intByte <= 700)
            {
                int firstChrIndx = Convert.ToInt32(Math.Floor((p_intByte - 1) / 26.0));
                int scndIndx = p_intByte % 26;
                if (scndIndx == 0) scndIndx = 26;
                return alphabets[firstChrIndx - 1].ToString() + alphabets[scndIndx - 1].ToString();
            }

            return "NA";
        }

    }
于 2013-06-13T08:26:36.220 に答える
1

そのため、Sheet1_Startup イベントで

Excel.Range range1 = this.Range["A1", missing];
var obj = range1.Value2.ToString();

次に、次のセルに移動する必要があります

    range1 = this.Range["A2", missing];
    obj = New list(range1.Value2.ToString());
于 2013-06-04T20:50:23.857 に答える