WPF的ContentPresenter的Angular值是多少?

时间:2019-10-27 14:56:09

标签: angular wpf angular-ui-router

关于使用TypeScript的Angular。

我来自WPF世界,现在我正在尝试一些Angular开发。

我的应用程序中有一个地方,我想要在其中建立一个选项卡控件以包含各种“打开”文档(Angular组件)。也许我认为这是完全错误的,但让我们考虑一下,其中有一个包含TabItem的数组的可注射对象,其中TabItem的属性之一是类的字符串,工厂或类型的名称我的应用程序的组件(待确定)。

export class TabItem {
    public title : string;
    public disabled : boolean;
    public active : boolean;
    public factory: any; // or class name or object
}
@Injectable()
export class OpenDocumentService {
    openTabs: Array<TabItem> = [];
    addTab(t:TabItem){ openTabs.push(t); }
}

在WPF中,我将创建一个内容演示者,并将其绑定到要显示的名称或对象。

我将在Angular世界中做什么。备注:要显示的组件可能在其他模块中。

添加到服务中后,如何* ngFor它并显示任意组件? (替换ng-contentpresenter)

     <tabset>
        <tab *ngFor="let tabz of tabservice.openTabs"
[heading]="tabz.titel">
           <ng-contentpresenter use={{tabz?.factory}}/>
        </tab>
    </tabset>

1 个答案:

答案 0 :(得分:1)

对于任何在这里结束的人:

简短的回答-角度不赞成此类的Shinnigan,因此,对于具有项浏览器的复杂情况,您最好坚持建议的构造ui的方法-如templates injection,正确使用路由ngSwitch树添加@ ngrx / store等。

长答案-look here。 您必须首先建立基础设施:

  • 您将需要创建将为模型保存组件的服务。将数据类型的构造函数用作键,并将组件构造函数类型用作值(DataTemplateService)
import { Injectable, Type } from '@angular/core';

/**
 * This service allows dynamically bind viewModel and component in configuration stage and then resolve it in render stage.
 * Service for dynamic component registration and detection. Component to be used are determined based on view model they have to render.
 */
@Injectable()
export class DataTemplateService {

    private dictionary: Map<Type<any>, Type<any>>;

    constructor() {
        this.dictionary = new Map<Type<any>, Type<any>>();

    }
    /**
     * Determines component class, searching in registered components.
     * @param data ViewModel that will be used for component, returns undefined if not found.
     */
    public determine(data: any): Type<any> | undefined {
        return data ? this.dictionary.get(data.constructor) : undefined;
    }

    /**
     * Registers binding of certain view model towards certain component.
     * @param viewModelType Type of ViewModel to be registered.
     * @param componentType Type of Component to be registered.
     */
    public register(viewModelType: Type<any>, componentType: Type<any>) {
        this.dictionary.set(viewModelType, componentType);
    }
}
  • 您将需要使用ComponentFactoryResolver从构造函数创建组件并在其中设置viewModel的服务(ComponentRendererService)

import { ComponentFactoryResolver, Injectable } from '@angular/core';

/**
 * Service fro rendering dynamic components.
 */
@Injectable()
export class ComponentRendererService {

    constructor(private componentFactoryResolver: ComponentFactoryResolver,
        private dataTemplateService: DataTemplateService) {
    }
    public render(data: any, containerComponent: any) {
        setTimeout(() => {
            this.doRender(data, containerComponent);
        }, 0);
    }

    /**
     * Renders dynamic components based on ViewModel they have to use.
     * @param data Collection of ViewModels that have to be used to render all child components.
     * @param containerComponent Parent component, that have to host dynamic child components.
     */
    public renderAll(data: Array<any>, containerComponent: any) {
        setTimeout(() => {
            if (data) {
                data.forEach(item => {
                    this.doRender(item, containerComponent);
                });
            }
        }, 0);
    }

    private doRender(data: any, containerComponent: any) {
        if (!data) {
            console.debug('No data (viewModel) for ComponentRendererService to render.');
            return;
        }
        const viewContainerRef = containerComponent.viewContainerRef;
        const dataItem = data;
        const component = this.dataTemplateService.determine(dataItem);
        if (component) {
            const componentFactory = this.componentFactoryResolver.resolveComponentFactory(component);
            const componentRef = viewContainerRef.createComponent(componentFactory);
            (<any>componentRef.instance).data = data;
        } else {
            console.warn('Failed to find component for viewmodel of type' + dataItem.constructor);
        }
    }
}
  • 您将需要使用Directive作为动态组件和将要调用服务的组件的标记。
import { Directive, ViewContainerRef, Component, Input, OnChanges, SimpleChanges, ViewChild } from '@angular/core';

/**
 *  Directive that enables construction of dynamic child components.
 */
@Directive({
    selector: '[dynamic-component-host]',
})
export class DynamicComponentHostDirective {
    constructor(public viewContainerRef: ViewContainerRef) { }
}

/**
 * Component that represents extention point for rendering dynamic child components.
 */
@Component({
    selector: 'ext-point-single-host',
    template: `
              <div class="ext-point-host">
                <ng-template dynamic-component-host></ng-template>
              </div>
            `
})
export class ExtPointSingleHostComponent implements OnChanges {
    @ViewChild(DynamicComponentHostDirective) public hostDirective: DynamicComponentHostDirective;
    @Input() public viewModel: any;

    constructor(private componentRenderer: ComponentRendererService) { }

    /**
     * Loads nested components.
     */
    public loadComponent() {
        const viewModel = this.viewModel;
        this.componentRenderer.render(viewModel, this.hostDirective);
    }

    public ngOnChanges(changes: SimpleChanges) {
        this.hostDirective.viewContainerRef.clear();
        this.loadComponent();
    }
}

之后,您可以将模型绑定到模块中的组件:


@Component({
    template: '<button type="button" class="">Custom style 2</button>'
})
export class CustomButton1Component  {
    public data: CustomButton1ViewModel;
}

export class CustomButton1ViewModel {

}
@Component({
    template: '<button type="button" class="">Custom style 2</button>'
})
export class CustomButton2Component  {
    public data: CustomButton2ViewModel;
}

export class CustomButton2ViewModel {

}

@NgModule({
    ...
    providers: [..., DataTemplateService]
})
export class DemoModule {
    constructor(dataTemplateService: DataTemplateService) {
        dataTemplateService.register(CustomButton2ViewModel, CustomButton2Component);
        dataTemplateService.register(CustomButton1ViewModel, CustomButton1Component);
    }
}

就是这样!

现在,我们可以使用其viewModel属性并将其绑定到CustomButton1ViewModel或CustomButton2ViewModel,以实际呈现CustomButton2Component或CustomButton1Component。为什么需要那么多代码?好吧,寻找简短答案:(