保護されたシートでは、Excel テーブル (ListObjects) の並べ替えは許可されていません。次のエラー メッセージが表示されます。
私は解決策を探すのに何週間も費やしましたが、成功しませんでした。そこにあるものはすべて、Excel 2007 のコード サンプルでは古くなっています。この制限を回避する方法に関するチュートリアルやガイドはありません。
最終的に克服できた方法はこちら..
保護されたシートでは、Excel テーブル (ListObjects) の並べ替えは許可されていません。次のエラー メッセージが表示されます。
私は解決策を探すのに何週間も費やしましたが、成功しませんでした。そこにあるものはすべて、Excel 2007 のコード サンプルでは古くなっています。この制限を回避する方法に関するチュートリアルやガイドはありません。
最終的に克服できた方法はこちら..
テーブルの Excel のフィルタ ドロップダウン メニューからソートする場合、トラップ可能なイベントはありません。ただし、昇順、降順、または並べ替えのダイアログ コマンドがリボンの [ホーム] タブおよび [データ] タブから呼び出されたときに、イベントをトラップすることはできます。
Excel 2016 相互運用機能 (ドキュメント レベルのカスタマイズ)、Visual Studio 2015、および C# を使用:
プロジェクトを右クリック -> 追加 -> 新しいアイテム -> リボン (XML)
あなたの Ribbon.xml で:
<?xml version="1.0" encoding="UTF-8"?>
<customUI xmlns="http://schemas.microsoft.com/office/2009/07/customui" onLoad="Ribbon_Load">
<commands>
<command idMso="SortAscendingExcel" onAction="SortNoAlerts" />
<command idMso="SortDescendingExcel" onAction="SortNoAlerts" />
<command idMso="SortCustomExcel" onAction="SortDialogNoAlerts" /><!--TabHome-->
<command idMso="SortDialog" onAction="SortDialogNoAlerts" /><!--TabData-->
</commands>
</customUI>
次に、イベントのコールバック関数を追加します。SortNoAlerts
昇順/降順ボタンのクリックに対してシートの保護を解除します。ただし、ユーザーが [カスタム ソート] ([ホーム] タブ) または [並べ替え] ([データ] タブ) を選択すると、ダイアログが表示され、シートの保護が解除され、[OK] を押すとシートが保護されますが、ユーザーがキャンセルした場合、ThisWorkbook_SheetCalculate
シートを保護しないままにすることは決してありません。SortDialogNoAlerts
そのため、シートの保護を解除するだけでなく、p/Invoke を使用FindWindow
して並べ替えダイアログ ウィンドウを探すタイマーを開始するを追加します。ウィンドウが見つからなくなると、まだ保護されていなければ保護されます。
- Ribbon.cs コールバックで:
public void SortNoAlerts(Office.IRibbonControl control, ref bool cancelDefault)
{
Excel.Worksheet ws = null;
try
{
ws = (Excel.Worksheet)Globals.ThisWorkbook.ActiveSheet;
ws.Unprotect("your password");
cancelDefault = false;
}
catch (Exception) { }
finally
{
if (ws != null) Marshal.ReleaseComObject(ws); ws = null;
}
}
public void SortDialogNoAlerts(Office.IRibbonControl control, ref bool cancelDefault)
{
Excel.Worksheet ws = null;
try
{
ws = (Excel.Worksheet)Globals.ThisWorkbook.ActiveSheet;
ws.Unprotect("your password");
Globals.ThisWorkbook._myActionPane.tmrWaitSortWinClose.Enabled = true;
cancelDefault = false;
}
catch (Exception) {
Globals.ThisWorkbook._myActionPane.tmrWaitSortWinClose.Enabled = false;
}
finally
{
if (ws != null) Marshal.ReleaseComObject(ws); ws = null;
}
}
- ThisWorkbook.cs -> InternalStartup() にこれを追加します。
this.SheetCalculate += new Excel.WorkbookEvents_SheetCalculateEventHandler(ThisWorkbook_SheetCalculate);
- ThisWorkbook.cs で -> これを追加します。
public bool sortDialogVisible;
private void ThisWorkbook_SheetCalculate(object sh)
{
Excel.Worksheet ws = (Excel.Worksheet)sh;
ws.EnableOutlining = true;
ws.Protect("your password", true, Type.Missing, Type.Missing, true, true, true, Type.Missing, Type.Missing, true, Type.Missing, Type.Missing, true, true, true, Type.Missing);
Marshal.ReleaseComObject(ws); ws = null;
}
- tmrWaitSortWinClose という名前のタイマーを追加し、Interval = 750 に設定します。
private void tmrWaitSortWinClose_Tick(object sender, EventArgs e)
{
Globals.ThisWorkbook.sortDialogVisible = Native.FindWindow("NUIDialog", "Sort") == IntPtr.Zero;
if (Globals.ThisWorkbook.sortDialogVisible)
{
Excel.Worksheet ws = null;
try
{
ws = (Excel.Worksheet)Globals.ThisWorkbook.ActiveSheet;
if (!ws.ProtectContents)
{
ws.Protect("your password", true, Type.Missing, Type.Missing, true, true, true, Type.Missing, Type.Missing, true, Type.Missing, Type.Missing, true, true, true, Type.Missing);
}
tmrWaitSortWinClose.Enabled = false;
}
catch (Exception) { tmrWaitSortWinClose.Enabled = false; }
finally
{
if (ws != null) Marshal.ReleaseComObject(ws); ws = null;
}
}
}
- Native.cs という名前のクラスを追加します。
public class Native
{
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
}
これにより、保護されたシートでテーブルを並べ替えることができます。混乱しないでください。このAllowSort
オプションはworksheet.Protect()
、テーブル (ListObject) の一部ではないシートのセルのみを対象としています。