簡介
- Custom Tool 是一種通用 Spotfire 擴充類型,用於在特定文本中(spotfire app, docuemnt, visual, …)執行某些動作,且可顯示或隱藏於菜單中。
概要
- 開發者需新建一個類別,並繼承並實作
CustomTool
類別。然後這個類別會在AddIn
類別的RegisterTools
方法中註冊。此時,也可以使用CustomMenuGroup
類別指定將工具放置在自訂菜單組中。 - 在創建 CustomTool 類別時,工具文本被指定為類型參數,例如對於 Document 需使用使用
CustomTool<Document>
,對於 Page 需使用CustomTool<Page>
。 - 可以將提示添加到工具中。提示對話框可以添加到 Windows 客戶端和 Web 客戶端。
- 在實作 custom tool 時,需注意到以下的特性:
- Tools 是靜態的(static):工具只有一個實例,該實例從調用
Execute()
方法的文本引數中接收其文本的處理。 - Tools 是無狀態的(stateless):一個狀態只能從一個繼承自
DocumentNode
類別並附加到文件模型的實例中保存在文件中。使用CustomNode
類別和Document.CustomNodes
屬性。 - Tools 只執行一個動作。:通常,該動作需要在一個 undo stack 上產生一個 undo state。因此,所有更改文檔狀態的工具都應該被包裝在其 Transaction 中。
- Tools 是靜態的(static):工具只有一個實例,該實例從調用
Tools 文本
1. Application
public sealed class MyApplicationTool : CustomTool<AnalysisApplication>
- AnalysisApplication tools 可從「Tools」選單中取得,在啟動 Spotfire 後即可啟用。
2. Document
public sealed class MyDocumentTool : CustomTool<Document>
- Document tools 可從「工具」選單中取得,在文件開啟時啟用。
3. Page
public sealed class MyPageTool : CustomTool<Page>
- Page tools 可從頁面文本選單中使用,但 web client 無法使用。
4. Visual
public sealed class MyVisualTool : CustomTool<VisualContent>
- VisualContent 文本為頁面上的所有視覺工具提供了一個工具。還有針對特定可視化類型應用的視覺工具的子文本:
- Visualization: 所有可視區,不包括繪圖區(plot area)。
- BarChart: 僅限長條圖。
- BoxPlot: 僅限箱形圖。
- CombinationChart: 僅限組合圖表。
- CrossTablePlot: 僅限交叉圖表。
- GraphicalTable: 僅限圖形表格繪圖。
- KPIChart: 僅限KPI圖表。
- LineChart: 僅限折線圖。
- MapChart: 僅限地圖圖表。
- ParallelCoordinatePlot
- PieChart: 僅限圓餅圖。
- ScatterPlot: 僅限散佈圖。
- ScatterPlot3D: 僅限3D散佈圖。
- SummaryTable: 僅限摘要表格。
- TablePlot: 僅限表格繪圖。
- TextArea: 僅限文字區域。
- WaterfallChart: 僅限瀑布圖表。
- 通過覆寫
IsVisibleCore
方法,可以將多個子文本結合起來,從而隱藏除了有明確定的子文本以外的工具。例如,擁有一個僅對散點圖和條形圖可用的工具,並在有標記(marking)時啟用。
5. TablePlot
TablePlotColumn
public sealed class MyTablePlotColumnTool : CustomTool<TablePlotColumnContext>
- 當右鍵點擊列標題時,可在文本菜單中找到。
TablePlotCell
public sealed class MyTablePlotCellTool : CustomTool<TablePlotCellContext>
- 在表格中右鍵點擊單元格時顯示的文本菜單選單中可用。
TablePlotCopyCellValue
public sealed class MyTablePlotCopyCellValueTool : CustomTool<TablePlotCopyCellValueContext>
在表格中右鍵點擊單元格時,可以在文本菜單的「Copy Cell」子菜單中找到。根據右鍵點擊的儲存格內容,且沒有添加任何擴展功能,子菜單標題可能包含以下一個或多個項目:
- Value: 當所點擊的儲存格包含文字時可用。文字會被放置在剪貼簿上。
- Link: 當列渲染器為所點擊的儲存格提供了連結時可用。
- Image: 當渲染器為單元格提供了圖像時可用。放置在剪貼板上的圖像與表格中看到的圖像相同。
TablePlotCopyCellValue 在 web client 無法使用。
6. Map Chart Coordinates Context
public sealed class MyMapChartCoordinatesTool : CustomTool<MapChartCoordinatesContext>
- 當使用者在地圖圖表上按右鍵時,具有 MapChartCoordinatesContext 的自訂工具將自動被呼叫。座標可在上下文物件的屬性中取得。
7. Filter
public sealed class MyFilterTool : CustomTool<FilterBase>
- FilterBase 文本使篩選器面板中的所有篩選器工具可用。還有針對特定篩選器類型應用的篩選器工具的子文本:
- CheckboxFilter
- ItemFilter
- ListBoxFilter
- RadioButtonFilter
- RangeFilte
- TextFilter
- HierarchyFilter
- ColumnFilter: 所有 filter 類型,但不包括層次篩選。
- SingleValueColumnFilter: 選擇一個值的 filter 類型,即 ItemFilter 和 RadioButtonFilter.
Grouping Tools、註冊
- Tools 可以按它們出現的位置分類:
- 未指定 menu group,它將出現在「工具」菜單中。
- 指定 menu group,因此它將出現在「工具」選單中的自訂工具群組中。
- 為了防止意外或未經管理的從其他專案添加工具,只有在相同的 Spotfire 擴充專案中實現的工具才能在菜單子組中分組。通過將工具收集在一個
AddIn
中,創建該組,然後在註冊它們時將其傳遞給要包含在該組中的工具。使用AddIn.ToolRegistrar.Register
方法註冊工具:
public sealed class CustomToolAddIn : AddIn
{
protected override void RegisterTools(ToolRegistrar registrar)
{
base.RegisterTools(registrar);
CustomMenuGroup menuGroup = new CustomMenuGroup("My menu sub group");
registrar.Register(new MyTool(), menuGroup);
}
...
}
- 自訂頂層選單
[ApiVersion("10.10.0")]
public static MenuCategory CreateCustom(params string[] path);
範例:
MenuCategory.CreateCustom("First", "Second");
- First 作為最上層的菜單標題, Second 為子菜單 或在實作 customTool 時指定
public MyTool()
: base(menuText, requiredLicense, MenuCategory.CreateCustom("First", "Second")) {}
Custom Tool 建構子
- CustomTool 類別的建構式有一個必要的字串參數
menuText
,該字串會顯示在選單和工具提示中。可以使用GetMenuTextCore
覆寫此文字,以獲取適應 Web Client 端本地化設置的文字。建構函式的可選參數包括運行該工具所需的許可證requiredLicense
、選單類別menuCategory
和要顯示在選單中的自訂圖示image
。
protected CustomTool(string menuText, LicensedFunction requiredLicense, MenuCategory menuCategory, Image image)
ExecuteCore
- 工具邏輯是透過覆寫
ExecuteCore
或ExecuteAndPromptCore
方法來實現的,當工具需要提示使用者輸入時,後者會被使用。
protected virtual void ExecuteCore(TContext context);
protected virtual IEnumerable<Object> ExecuteAndPromptCore(TContext context);
- 文本參數將使工具能夠訪問文件、頁面、視覺或其他對象,具體取決於工具操作的文本。
ExecuteAnPromptCore
方法的簽名需要額外解釋:注意它應該返回可枚舉物件(enumerable objects)。這是通過 yield 構造實現的,以返回用作提示模型的任何對象。使用AddIn.RegisterViews
為工具使用的任何提示模型註冊相應的提示視圖。- 如果該工具使用提示,則需要覆寫
GetSupportsPromptingCore
以返回true
。 - Web Client 中的 Tools:
- 預期 Web Client 端中的工具支援提示,並且必須實現
ExecuteAndPromptCore
(ExecuteCore
永遠不會被框架呼叫)。但是,可以使用以下解決方法在ExecuteAndPromptCore
中實現不提示的 Web 客戶端工具,該方法調用ExecuteCore
並返回沒有提示模型:
protected override IEnumerable<object> ExecuteAndPromptCore(Visualization context) { this.ExecuteCore(context); yield break; }
- 預期 Web Client 端中的工具支援提示,並且必須實現
IsEnabledCore
有兩種方法可以覆寫,以指定何時應該顯示工具,以及何時應該啟用工具。
IsEnabledCore
回傳一個布林值,以指定該工具是否應該在選單中啟用。
protected override bool IsEnabledCore(TContext context)
IsVisibleCore
回傳一個布林值,指定該工具是否應該在選單中顯示。
protected override bool IsVisibleCore(TContext context)
範例1: 將當下的頁籤移至最後。
public sealed class PageTool : CustomTool<Page>
{
public PageTool()
: base(Properties.Resources.PageToolTitle) {}
protected override void ExecuteCore(Page page)
{
Document document = page.Context.GetAncestor<Document>();
int index = document.Pages.IndexOf(page);
document.Pages.Move(index, document.Pages.Count - 1);
}
protected override bool IsEnabledCore(Page page)
{
Document document = page.Context.GetAncestor<Document>();
int index = document.Pages.IndexOf(page);
return index >= 0 && index < document.Pages.Count - 1;
}
}
- 範例2: 將 visualization 中標記的值寫出來。
public sealed class PlotTool : CustomTool<VisualContent>
{
public PlotTool()
: base(Properties.Resources.PlotToolTitle) {}
protected override void ExecuteCore(VisualContent context)
{
Visualization plot = (Visualization)context;
DataManager dataManager = context.Context.GetSertvice<DataManager>();
DataTable dataTable = plot.Data.DataTableReference;
DataColumn firstColumn = dataManager.Tables[dataTable.Id].Columns[0];
IndexSet markedRows = dataManager.Markings.DefaultMarkingReference.GetSelection(dataTable).AsIndexSet();
var cursor = DataValueCursor.Create(firstColumn);
foreach (var row in dataTable.GetRows(markedRows, cursor))
{
Trace.WriteLine(cursor.CurrentDataValue.ValidValue);
}
}
protected override bool IsEnabledCore(VisualContent context)
{
Visualization plot = context as Visualization;
DataManager dataManager = context.Context.GetService<DataManager>();
DataMarkingSelection marking = dataManager.Markings.DefaultMarkingReference;
if (plot.Data.DataReference == null)
{
return false;
}
else
{
RowSelection selectedRows = marking.GetSelection(plot.Data.DataTableReference);
return !selectedRows.IsEmpty;
}
}
protected override bool IsVisibleCore(VisualContent context)
{
return context is BarChart || context is ScatterPlot;
}
}
範例3: 在 Spotfire 表格中右鍵點擊顯示圖像的儲存格,選擇「複製儲存格 > 圖像」,將圖像按比例縮放後添加到剪貼簿中。此範例實現了一個工具,可將全尺寸圖像複製到剪貼簿中。它可以從通用的 Spotfire 圖像複製工具相同的位置訪問:
public sealed class CopyCellValueTool : CustomTool<CopyCellValueContext>
{
public CopyCellValueTool() : base("Image (fullsize)") {}
protected override void ExecuteCore(CopyCellValueContext context)
{
BinaryLargeObject blob = context.DataValue.Value as BinaryLargeObject;
if (blob != null)
{
try
{
Image img = Image.FromStream(blob.GetByteStream());
Clipboard.Clear();
Clipboard.SetImage(img);
}
catch (ArgumentException)
{
// Unable to convert to image, ignore
}
}
}
protected override bool IsVisibleCore(CopyCellValueContext context)
{
return context.DataType != null &&
context.ContentType != null &&
!context.DataType.IsSimple &&
context.ContentType.StartsWith("image/", true, CultureInfo.InvariantCulture);
}
protected override bool IsEnabledCore(CopyCellValueContext context)
{
return context.DataValue != null && context.DataValue.IsValid;
}
}
範例4: 將「顯示儲存格資訊」項目添加到儲存格內容選單中。該工具會顯示一個訊息方塊,顯示所選儲存格的欄位名稱和儲存格值。
public sealed class TablePlotCellContextExampleTool : CustomTool<TablePlotCellContext>
{
public TablePlotCellContextExampleTool() : base(Properties.Resources.TablePlotCellToolTitle) {}
protected override void ExecuteCore(TablePlotCellContext tablePlotCellContext)
{
string dataValue = tablePlotCellContext.DataValue.Value.ToString();
string info = string.Format(
System.Threading.Thread.CurrentThread.CurrentCulture,
Properties.Resources.TablePlotCellToolInfo,
new object[] { tablePlotCellContext.TableColumn.Name,
dataValue });
System.Windows.Forms.MessageBox.Show(info, Properties.Resources.TablePlotCellToolTitle);
}
protected override bool IsEnabledCore(TablePlotCellContext context)
{
return context.DataValue != null && context.DataValue.IsValid;
}
}