为 Power BI 视觉对象创建对话框

创建视觉对象时,有时最好在单独的窗口中向客户显示附加消息。 例如,您可能希望:

  • 显示附加消息 - 例如文本注释或视频
  • 显示输入数据对话框 - 例如日期对话框

为此,可以创建一个对话视觉对象弹出窗口,在本文中称为“对话框”。

对话框注意事项

为视觉对象创建对话框时,请注意以下事项:

  • 在开发过程中,可以指定对话框的大小和位置。
  • 当触发对话框时,报表背景将灰显。
  • 对话框标题包含视觉对象的图标及其显示名称作为标题。
  • 此对话框最多可以有三个操作按钮。 你可以选择要在给定选择中显示的按钮。
  • 此对话框使用 Rich HTML iframe
  • 显示对话框时,无法在报表中执行任何操作,直到关闭对话框。
  • 对话框代码可以使用外部 npm 库,就像视觉对象一样。

重要

不应自发触发对话框。 它应是用户操作的直接结果。

为视觉对象设计对话框

若要配置对话框,需要将两个组件添加到代码中:

创建对话框实现文件

建议为创建的每个对话框创建实现文件。 将对话框文件置于 src 文件夹中:

屏幕截图显示了 Power BI 视觉对象项目中名为 DatePickerDialog.ts 的对话框实现文件的位置。

每个对话框实现文件应包括以下组件:

创建对话框类

为对话框创建对话框类。 openModalDialog 中的 initialState 参数在创建时便传递给对话框承包商。 使用 initialState 对象将参数传递给对话框,以影响其行为或外观。

对话代码可以使用以下 IDialogHost 方法:

  • IDialogHost.setResult(result:object) - 对话代码会返回一个结果对象,该对象会被传回发起调用的视觉对象。
  • IDialogHost.close(actionId: DialogAction, result?:object) - 对话代码可以编程方式关闭对话,并将结果对象提供回其调用视觉对象。

在文件顶部导入:

import powerbi from "powerbi-visuals-api";
import DialogConstructorOptions = powerbi.extensibility.visual.DialogConstructorOptions;
import DialogAction = powerbi.DialogAction;
// React imports as an example
import * as ReactDOM from 'react-dom';
import * as React from 'react';
import reactDatepicker from 'react-datepicker';
import 'react-datepicker/dist/react-datepicker.css';

此示例需要安装以下包:

    npm i react-dom react react-datepicker

类实现:

export class DatePickerDialog {
    static id = "DatePickerDialog";

    constructor(options: DialogConstructorOptions, initialState: object) {
        const host = options.host;
        let pickedDate: Date;
        const startDate = new Date(initialState['startDate']);
        
        // Dialog rendering implementation
        ReactDOM.render(
            React.createElement(
                reactDatepicker,
                {
                    inline: true,
                    openToDate: startDate,
                    onChange: (date: Date) => {
                        pickedDate = date
                        host.setResult({ date: pickedDate })
                    }
                },
                null),
            options.element
        );

        document.addEventListener('keydown', e => {
            if (e.code == 'Enter' && pickedDate) {
                host.close(DialogAction.Close, {date: pickedDate});
            }
        });
    }
}

创建结果类

创建返回对话框结果的类,然后将其添加到对话框实现文件。

在下面的示例中,DatePickerDialogResult 类返回日期字符串。

export class DatePickerDialogResult {
    date: string;
}

将对话框添加到注册表列表

每个对话框实现文件都需要包含注册表引用。 将以下示例中的两行添加到你的对话框实现文件的末尾。 每个对话框实现文件的第一行应该是相同的。 第二行列出对话框;可根据对话框类的名称进行修改。

globalThis.dialogRegistry = globalThis.dialogRegistry || {};
globalThis.dialogRegistry[DatePickerDialog.id] = DatePickerDialog;

调用对话框

在创建对话框之前,需决定它将包含哪些按钮。 Power BI 视觉对象支持以下六个对话框按钮:

export enum DialogAction {
        Close = 0,
        OK = 1,
        Cancel = 2,
        Continue = 3,
        No = 4,
        Yes = 5
    }

需在 visual.ts 文件中调用所创建的每个对话框。 在本例中,对话框由两个操作按钮定义。

import powerbi from "powerbi-visuals-api";
import DialogAction = powerbi.DialogAction;
const dialogActionsButtons = [DialogAction.OK, DialogAction.Cancel];

在本例中,通过单击视觉对象按钮调用对话框。 视觉对象按钮被定义为 visual.ts 文件中视觉对象构造函数的一部分。

定义对话框的大小和位置

在 API 版本 4.0 或更高版本中,可使用 openModalDialogDialogOpenOptions 参数定义对话框的大小和位置。 若要了解正在使用的版本,请检查 pbiviz.json 文件中的 apiVersion

    export interface RectSize {
        width: number;
        height: number;
    }

    export interface DialogOpenOptions {
        title: string;
        size?: RectSize;
        position?: VisualDialogPosition;
        actionButtons: DialogAction[];
    }

position 参数可用于确定对话框应在屏幕上打开的位置。 可选择在屏幕中心打开对话框,也可定义相对于视觉对象的不同位置。

    const enum VisualDialogPositionType {
        Center = 0,
        RelativeToVisual = 1
    }

    export interface VisualDialogPosition {
        type: VisualDialogPositionType;
        left?: number;
        top?: number;
    }
  • 如果未指定类型,则默认在中间打开对话框。
  • 位置以像素为单位,与视觉对象的左上角相对。

此示例显示一个 250 x 300 像素的日期选择对话框,该对话框左侧为 100 像素,视觉对象顶部下方为 30 像素:

export class Visual implements IVisual {
    private target: HTMLElement;
    private host: IVisualHost;
 
    constructor(options: VisualConstructorOptions) {
        this.host = options.host;
        this.target = options.element;
        const dialogActionsButtons = [DialogAction.OK, DialogAction.Cancel];

        const sectionDiv = document.createElement("div");

        const span = document.createElement("span");
        span.id = "datePicker";

        let button = document.createElement("button");
        button.id = "DateButton";
        button.innerText = "Date";

        button.onclick = (event) => {
            const initialDialogState = { startDate: new Date() };
            const position = {
                    type: VisualDialogPositionType.RelativeToVisual,
                    left: 100,
                    top: 30
            };

            const size = {width: 250, height: 300};
            const dialogOptions = {
                actionButtons: dialogActionsButtons,
                size: size,
                position: position,
                title: "Select a date"
            };
            this.host.openModalDialog(DatePickerDialog.id, dialogOptions, initialDialogState).
                then(ret => this.handleDialogResult(ret, span)).
                catch(error => this.handleDialogError(error, span));
        }
        sectionDiv.appendChild(button);
        sectionDiv.appendChild(span);
        this.target.appendChild(sectionDiv)
    }

    // Custom logic to handle dialog results
    private handleDialogResult( result: ModalDialogResult, targetElement: HTMLElement){
        if ( result.actionId === DialogAction.OK || result.actionId === DialogAction.Close) {
            const resultState = <DatePickerDialogResult> result.resultState;
            const selectedDate = new Date(resultState.date);
            targetElement.textContent = selectedDate.toDateString();
        }
    }

    // Custom logic to handle errors in dialog
    private handleDialogError( error: any, targetElement: HTMLElement ) {
        targetElement.textContent = "Error: " + JSON.stringify(error);
    }
}

定义如何关闭对话框

关闭对话框的首选方法是最终用户单击 [x] 按钮、操作按钮之一或报表背景。

还可以通过调用 IDialogHost close 方法将对话框编程为自动关闭。 对话框打开后,此方法将被阻止五秒,因此,最早可以在对话框启动后五秒自动关闭该对话框。

“不显示”对话框

对话框与复选框一起出现,该复选框为用户提供了用于阻止对话框的选项。

显示复选框的屏幕截图,提供了用于阻止对话框的选项。

此复选框是一项安全功能,可防止视觉对象在用户不同意的情况下创建模式对话框(无论是有意还是无意)。

此阻止仅对当前会话有效。 因此,如果用户阻止了 CV 模式对话,但后来改变了主意,他们可以重新启用对话。 要执行此操作,他们需要启动新会话(刷新 Power BI 服务中的报表页或重启 Power BI Desktop)。

注意事项和限制

  • 自 powerbi-visuals-API 3.8 起,对话框图标和标题由视觉对象的图标和显示名称决定,且无法更改。

  • 对话框的大小限制如下表所示。

    最大/最小 宽度 高度
    最大值 浏览器宽度的 90% 浏览器高度的 90%
    最小值 240 磅 210 px
  • 定义对话框的位置时,水平位置可以是正整数或负整数,具体取决于你希望框位于视觉对象的哪一侧。 垂直位置不能为负,以避免放在视觉对象的上方。

  • 以下功能不支持 Power BI 视觉对象对话框:

    • 嵌入式分析
    • 发布到 Web
    • 仪表板

可以通过检查布尔值 this.host.hostCapabilities.allowModalDialog 来对视觉对象进行编程,以检测当前环境是否允许打开对话框。