メインコンテンツまでスキップ

カスタム UI の組み込み

プレビュー公開

本機能および本機能で利用する API は先行公開しているものです。 現時点で品質保証しておりませんので、ご利用される場合はユーザー様の責任でご利用ください。 また、これらの仕様は予告なく変更する場合がありますのでご了承ください。

概要

Next Design に標準搭載されている UI 以外に、ユーザーが独自に開発した UI を次の部分に組み込んでモデル編集機能を拡張できます。

  • エディタ
  • ナビゲータ
  • インスペクタ

カスタム UI を組み込むには次の実装と手順が必要です。

  • カスタム UI のユーザコントロールの実装
  • カスタム UI のインタフェースの実装
  • カスタム UI の登録処理と登録解除処理の実装
  • カスタム UI の利用方法
注記

カスタム UI は、MVVM モデル(Model-View-ViewModel)のアーキテクチャにしたがって実装します。

カスタム UI のユーザコントロールの実装

View クラスで、UI として表示するユーザコントロールを WPF で実装します。

注記

本機能では、独自 UI を組み込むための手段を提供しています。
ユーザコントロール自体の作成を支援する機能は提供していない点にご注意ください。

カスタム UI のインタフェースの実装

ViewModel クラスで、UI の種類に応じてインタフェースを実装します。
UI の種類に応じたインタフェースを実装することで、Next Design のモデルと ViewModel クラスを繋ぐことができます。

  • UI の種類と実装するインタフェース

    UI 種類ViewModel で実装するインタフェース実装が必要なプロパティ/メソッド
    カスタムエディタICustomEditorViewDescriptor プロパティ
    OnInitialized メソッド
    OnBeforeDispose メソッド
    ViewDefinitionId プロパティ
    SelectedItem プロパティ
    SelectedItems プロパティ
    SetModel メソッド
    GetDocumentContent メソッド(※)
    カスタムナビゲータICustomNavigatorDescriptor プロパティ
    OnInitialized メソッド
    OnBeforeDispose メソッド
    SelectedItem プロパティ
    SelectedItems プロパティ
    OnShow メソッド
    OnHide メソッド
    カスタムインスペクタICustomInspectorDescriptor プロパティ
    OnInitialized メソッド
    OnBeforeDispose メソッド
    SetModel メソッド

    ※:GetDocumentContent メソッドは、将来の機能拡張のために用意した API です。現行バージョンでは、null を返すのみとしてください。

カスタム UI の登録処理と登録解除処理の実装

IExtention を実装したメインクラスの公開メソッドである Activate メソッドにカスタム UI の登録処理を実装します。そして、メインクラスの公開メソッドである Deactviate メソッドにカスタム UI の登録解除処理を実装します。

カスタム UI の利用方法

エディタ

カスタム UI の種類がエディタの場合は、次の手順で対象モデルのビューにカスタム UI を追加します。

操作手順
  1. モデルナビゲータで カスタム UI の対象モデルを選択します。
  2. コンテキストメニューの [ビューの追加] を実行します。
  3. 組み込んだカスタム UI のエディタ名を選択し、ビューを追加します。
  4. 追加されたビューに切り替えると、組み込んだカスタム UI で対象モデルを表示・編集できます。

ナビゲータ、インスペクタ

カスタム UI の種類がナビゲータ、インスペクタの場合は、それぞれ対応するウィンドウに UI が表示されるので直接操作します。


サンプル:カスタムエディタ/ナビゲータ/インスペクタの追加

カスタム UI のサンプルとして、Next Design に標準で組み込まれている UI とは表示内容の異なるカスタムエディタ/ナビゲータ/インスペクタを追加します。 以下では、Visual Studio プロジェクトの新規作成から、実際にカスタム UI を組み込むところまでを説明します。

全体の流れ

  • Visual Studio プロジェクトの新規作成
  • カスタムエディタの追加
    • ユーザコントロールの実装
    • インタフェースの実装
  • カスタムナビゲータの追加
    • ユーザコントロールの実装
    • インタフェースの実装
  • カスタムインスペクタの追加
    • ユーザコントロールの実装
    • インタフェースの実装
  • カスタム UI 登録処理と登録解除処理の実装
  • カスタム UI の利用方法

公開サンプル

  • 以下の手順で作成されるサンプルのソースコード一式を GitHub で公開しています。

    外部リンク: CustomUISample

ゴールイメージ

画面キャプチャ or GIFアニメ

  • ナビゲータにカスタムナビゲータが追加され、独自の UI でモデルを選択できます。
  • ビューの種類にカスタムエディタが追加され、モデルエディタのビューをカスタムエディタに切り替えて、独自の UI でモデルを表示・編集できます。
  • インスペクタのタブにカスタムインスペクタが追加され、独自の UI で編集対象のモデルに関する詳細情報を表示・編集できます。

Visual Studio プロジェクトの新規作成

Visual Studio プロジェクトは次のページを参考に新規作成します。

チュートリアル > モデル一括検証

ただし、ユーザーコントロールを配置できるようにするために、プロジェクト新規作成時のプロジェクトの種類には [WPF クラスライブラリ] を設定します。

なお、モデル追加時の初期化処理の追加では、マニフェストに以下の定義は不要です。

  • UI の拡張ポイント定義(リボンタブ・グループ・ボタン)
  • コマンドの拡張ポイント定義

実装例

manifest.json

{
// エクステンション定義
"name": "DensoCreate.NextDesign.Extensions.CustomUISample",
"displayName": "%Extension.DisplayNameKey%",
"description": "%Extension.DescriptionKey%",
"version": "1.0.0",
"publisher": "DENSO CREATE Inc.",

"license": "Indio本体アプリケーションと同等のライセンスを必要とします。",

"env": {
"nextdesign": "1.1.0", // 対応するNext Designのバージョン

"engine": {
"engine": "dotnetdll", // "clearscript" , "dotnetdll"
"version": "^0.9.0"
}
},

"main": "CustomUISample.dll", // エントリーポイントとしてビルド結果の DLL ファイル名を指定します。
"lifecycle": "application", // ライフサイクルとしてアプリケーションライフサイクルを指定します。
"baseProfile": "" // プロファイル名の条件を指定しません。
}

クラスファイルの作成

カスタム UI の追加に必要な View クラスと ViewModel クラスを Visual Studio プロジェクトに追加します。

View クラス

Visual Studio のソリューション エクスプローラーで、プロジェクトに新しい項目としてユーザーコントロール(WPF)を選択します。

ViewModel クラス

Visual Studio のソリューション エクスプローラーで、プロジェクトに新しい項目としてクラスを追加します。

今回追加するクラス名は次の通りです。

追加する UI 種類View クラスViewModel クラス
カスタムエディタCustomEditorCustomEditorViewModel
カスタムナビゲータCustomNavigatorCustomNavigatorViewModel, CustomNavigatorItemViewModel(※)
カスタムインスペクタCustomInspectorCustomInspectorViewModel

※:CustomNavigatorItemViewModel は、カスタムナビゲータ内に表示する表示要素のクラスです。

プロジェクトのファイル構成

ファイルを追加した後の Visual Studio のプロジェクトの構成は以下になります。

CustomUISample/
CustomUISample.sln
CustomUISample/
CustomUISample.csproj
manifest.json
View/
Editor/
CustomEditor.xaml
CustomEditor.xaml.cs
Inspector/
CustomInspector.xaml
CustomInspector.xaml.cs
Navigator
CustomNavigator.xaml
CustomNavigator.xaml.cs
ViewModel/
Editor/
CustomEditorViewModel.cs
Inspector/
CustomInspectorViewModel.cs
Navigator
CustomNavigatorItemViewModel.cs
CustomNavigatorViewModel.cs
CustomUISampleEntryPoint.cs(※)

※:CustomUISampleEntryPoint は、IExtension のインタフェースを実装するメインクラスです。

カスタムエディタの追加

ユーザコントロールの実装

カスタムエディタのビューを定義します。

実装例

CustomEditor.xaml

<UserControl x:Class="CustomUISample.View.Editor.CustomEditor"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:CustomUISample.View.Editor"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<UserControl.Resources>

<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>

</UserControl.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="30"/>
<RowDefinition Height="40"/>
<RowDefinition Height="1"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>

<Grid VerticalAlignment="Center" Margin="5,0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal">
<Label Content="ビュー:" />
<ComboBox Height="23" Width="150" Margin="5,0" >
<ComboBoxItem Name="m_FormItem" Content="フォーム" IsSelected="True"/>
<ComboBoxItem Name="m_GridItem" Content="グリッド" />
</ComboBox>
</StackPanel>
</Grid>

<StackPanel Grid.Row="1" Orientation="Horizontal" VerticalAlignment="Center" Margin="10,0">
<TextBlock Text="名前:" />
<TextBlock Text="{Binding Path=Name}" Margin="5,0" />
</StackPanel>

<Border Grid.Row="2" BorderThickness="0,1,0,0" BorderBrush="LightGray" HorizontalAlignment="Stretch" />

<!--フォーム風ビュー-->
<Grid Grid.Row="3" Visibility="{Binding ElementName=m_FormItem, Path=IsSelected, Converter={StaticResource BooleanToVisibilityConverter}}" Margin="10,20,0,10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50"/>
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="30"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>

<TextBlock Text="説明:" VerticalAlignment="Top" Margin="0,2,0,0" />
<TextBox Grid.Column="1" Text="{Binding Path=Description}" MinHeight="150" HorizontalAlignment="Stretch"/>

<TextBlock Grid.Row="1" Text="クラス名:" VerticalAlignment="Center" />
<TextBlock Grid.Row="1" Grid.Column="1" VerticalAlignment="Center" Text="{Binding Path=ClassName}" Margin="5,0" HorizontalAlignment="Left"/>

</Grid>

<!--グリッドビュー-->
<DataGrid Grid.Row="3" ItemsSource="{Binding Path=Children}"
Visibility="{Binding ElementName=m_GridItem, Path=IsSelected, Converter={StaticResource BooleanToVisibilityConverter}}"
AutoGenerateColumns="True" Margin="10,20,10,0"
HorizontalScrollBarVisibility="Auto"/>
</Grid>
</UserControl>

インタフェースの実装

カスタムエディタの ViewModel クラスで ICustomEditorView を実装します。

実装例

CustomEditorViewModel.cs

using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;
using NextDesign.Core;
using NextDesign.Desktop;
using NextDesign.Desktop.CustomUI;
using NextDesign.Extension;

namespace CustomUISample.ViewModel.Editor
{
class CustomEditorViewModel : ICustomEditorView
{
#region タイプ記述子

/// <summary>
/// タイプ記述子
/// </summary>
private static CustomEditorDefinitionDescriptor s_DefinitionDescriptor;

/// <summary>
/// タイプ記述子
/// </summary>
public static CustomEditorDefinitionDescriptor DefinitionDescriptor
{
get
{
return s_DefinitionDescriptor ?? (s_DefinitionDescriptor = new CustomEditorDefinitionDescriptor
{
// カスタムエディタの種類識別子
CustomEditorTypeId = "CustomUI.Test",
// アクセスキー
AccessKey = "P",
// 表示名
DisplayName = "カスタムエディタ",
// グループ名
GroupName = "カスタムエディタ",
// アイコン(大)pack - uri 形式の文字列、または Stream 型を指定できます。
LargeIcon =
"pack://application:,,,/CustomUISample;component/Resources/Images/TestEditor32.png",
// アイコン(小)pack - uri 形式の文字列、または Stream 型を指定できます。
SmallIcon =
"pack://application:,,,/CustomUISample;component/Resources/Images/TestEditor16.png"
});
}
}

#endregion

#region プロパティ

/// <summary>
/// タイプ記述子
/// </summary>
public ICustomDescriptor Descriptor { get; set; }

/// <summary>
/// 対応するビュー定義のId
/// </summary>
public string ViewDefinitionId => Editor?.EditorDefinition.Id;

/// <summary>
/// エディタで選択された要素
/// 選択された要素がない場合は、null を返すように実装してください。
/// </summary>
public object SelectedItem => null;

/// <summary>
/// エディタで選択された要素の列挙
/// 選択された要素がない場合は、空の列挙を返すように実装してください。
/// </summary>
public IEnumerable<object> SelectedItems => Enumerable.Empty<object>();

/// <summary>
/// アプリケーション
/// </summary>
public IApplication App { get; private set; }

/// <summary>
/// エクステンション
/// </summary>
public CustomUISampleEntryPoint Extension { get; private set; }

/// <summary>
/// エディタ情報
/// </summary>
public ICustomEditor Editor { get; private set; }

/// <summary>
/// 対象モデル
/// </summary>
public IModel TargetModel { get; private set; }

#endregion

#region イベントハンドラ

/// <summary>
/// 独自拡張するユーザインタフェースを初期化する際の処理
/// Next Designは、独自拡張するユーザインタフェースを初期化する際にこのメソッドを呼び出します。
/// 拡張側で初期化時に実行したい処理がある場合はここで実装します。
/// </summary>
/// <param name="args">イベントパラメータ</param>
public void OnInitialized(InitializedEventArgs args)
{
// アプリケーションとエクステンションの情報を記憶します
App = args.App;
Extension = args.Extension as CustomUISampleEntryPoint;
}


/// <summary>
/// 独自拡張するユーザインタフェースを破棄する前の処理
/// Next Designは、独自拡張するユーザインタフェースを破棄する前にこのメソッドを呼び出します。
/// 拡張側で破棄前に実行したい処理がある場合はここで実装します。
/// </summary>
/// <param name="args">イベントパラメータ</param>
public void OnBeforeDispose(BeforeDisposeEventArgs args)
{
// 破棄する前の処理なし
}


#endregion

#region インタフェース実装

/// <summary>
/// このエディタの表示対象のモデルを設定します。
/// </summary>
/// <param name="model"></param>
public void SetModel(ICustomEditor model)
{
Editor = model;
TargetModel = model.Model;
}

/// <summary>
/// ドキュメント出力するコンテンツの内容を取得します。
/// </summary>
/// <param name="context"></param>
public ICustomEditorDocumentContent GetDocumentContent(ICustomEditorDocumentGenerationContext context)
{
// 現行バージョンでは、null 固定とします
return null;
}

#endregion
}
}

カスタムナビゲータの追加

ユーザコントロールの実装

カスタムナビゲータのビューを定義します。

実装例

CustomNavigator.xaml

<UserControl x:Class="CustomUISample.View.Navigator.CustomNavigator"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:CustomUISample.View.Navigator"
xmlns:viewModel="clr-namespace:CustomUISample.ViewModel.Navigator"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<UserControl.Resources>

<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="OverridesDefaultStyle" Value="False"/>
</Style>

<HierarchicalDataTemplate DataType="{x:Type viewModel:CustomNavigatorItemViewModel}" ItemsSource="{Binding Path=Children}">
<StackPanel Orientation="Horizontal">
<Image Source="{Binding Path=Icon}" Height="16" Width="16"/>
<TextBlock Text="{Binding Path=Model.Name}" Margin="5,0,0,0" VerticalAlignment="Center"/>
</StackPanel>
</HierarchicalDataTemplate>
</UserControl.Resources>
<Grid>
<TreeView x:Name="m_Tree" ItemsSource="{Binding Path=Items}" SelectedItemChanged="TreeView_SelectedItemChanged"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"/>
</Grid>
</UserControl>

カスタムナビゲータのビューの振る舞いを実装します。

CustomNavigator.xaml.cs

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using CustomUISample.ViewModel.Navigator;

namespace CustomUISample.View.Navigator
{
/// <summary>
/// CustomNavigator.xaml の相互作用ロジック
/// </summary>
public partial class CustomNavigator : UserControl
{
public CustomNavigator()
{
InitializeComponent();
}

/// <summary>
/// ツリーの選択変更
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void TreeView_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
{
var vm = DataContext as CustomNavigatorViewModel;
var itemVM = m_Tree.SelectedItem as CustomNavigatorItemViewModel;
if (itemVM != null)
{
vm.SelectedItem = itemVM.Model;
}
}
}
}

インタフェースの実装

カスタムナビゲータの ViewModel クラスで ICustomNavigator を実装します。

実装例

CustomNavigatorViewModel.cs

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Text;
using System.Linq;
using NextDesign.Core;
using NextDesign.Desktop;
using NextDesign.Desktop.CustomUI;

namespace CustomUISample.ViewModel.Navigator
{
public class CustomNavigatorViewModel : ICustomNavigator, IDisposable
{
#region プロパティ
/// <summary>
/// タイプ記述子
/// </summary>
public ICustomDescriptor Descriptor { get; set; }

/// <summary>
/// 選択しているアイテム
/// </summary>
private object m_SelectedItem;

/// <summary>
/// 選択しているアイテム
/// </summary>
public object SelectedItem
{
get => m_SelectedItem;
set
{
m_SelectedItem = value;

// 選択しているアイテムが、Modelの場合は
// 現在のワークスペースのカレントモデルとインスペクト対象の要素を設定します。
if (m_SelectedItem is IModel model)
{
Workspace.State.SetCurrentModel(model); ;
Workspace.State.SetInspectedObject(model); ;
}
}
}

/// <summary>
/// エディタで選択された要素の列挙
/// 選択された要素がない場合は、空の列挙を返すように実装してください。
/// </summary>
public IEnumerable<object> SelectedItems => Enumerable.Empty<object>();

/// <summary>
/// ID
/// </summary>

/// <summary>
/// アイテム
/// </summary>
private ObservableCollection<CustomNavigatorItemViewModel> m_Items;

/// <summary>
/// アイテム
/// </summary>
public IEnumerable<CustomNavigatorItemViewModel> Items => m_Items;

/// <summary>
/// ワークスペース
/// </summary>
private IWorkspace Workspace => m_App.Workspace;

#endregion

#region 内部フィールド

/// <summary>
/// コンフィグレーション
/// </summary>
private CustomNavigatorConfigs m_Configs;

/// <summary>
/// アプリケーション
/// </summary>
private NextDesign.Desktop.IApplication m_App;

#endregion

#region 構築・消滅

/// <summary>
/// 破棄
/// </summary>
public void Dispose()
{
DisposeItems();
if (m_App != null)
{
m_App = null;
}
}

/// <summary>
/// アイテムをDisposeする
/// </summary>
public void DisposeItems()
{
if (m_Items == null)
{
return;
}

foreach (var item in m_Items)
{
item.Dispose();
}

m_Items.Clear();
m_Items = null;
}

#endregion

#region イベントハンドラ

/// <summary>
/// OnInitialized "独自拡張するユーザインタフェースを初期化する際の処理
/// Next Designは、独自拡張するユーザインタフェースを初期化する際にこのメソッドを呼び出します。
/// 拡張側で初期化時に実行したい処理がある場合はここで実装します。"
/// </summary>
/// <param name="args"></param>
public void OnInitialized(InitializedEventArgs args)
{
m_Configs = new CustomNavigatorConfigs();
m_Configs.SelectionMode = SelectionMode.Multiple;
}

/// <summary>
/// 独自拡張するユーザインタフェースを破棄する前の処理
/// Next Designは、独自拡張するユーザインタフェースを破棄する前にこのメソッドを呼び出します。
/// 拡張側で破棄前に実行したい処理がある場合はここで実装します。
/// </summary>
/// <param name="args"></param>
public void OnBeforeDispose(BeforeDisposeEventArgs args)
{
// 処理なし
}

/// <summary>
/// このナビゲータを表示する際の処理
/// Next Designは、独自拡張するナビゲータを表示する際にこのメソッドを呼び出します。
/// 拡張側で表示時に実行したい処理がある場合はここで実装します。
/// </summary>
/// <param name="args"></param>
public void OnShow(OnShowEventArgs args)
{
m_App = args.App;
var project = m_App.Workspace.CurrentProject;
CreateChildren(project);
}

/// <summary>
/// このナビゲータを非表示にする際の処理
/// Next Designは、独自拡張するナビゲータを隠す際にこのメソッドを呼び出します。
/// 拡張側で非表示時に実行したい処理がある場合はここで実装します。
/// </summary>
/// <param name="args"></param>
public void OnHide(OnHideEventArgs args)
{
// 処理なし
}

#endregion

#region 内部処理

/// <summary>
/// 子要素を生成
/// </summary>
/// <param name="project"></param>
private void CreateChildren(IProject project)
{
if (project == null)
{
return;
}

// モデルの子要素を取得し、ナビゲータの子要素を生成します
var models = project.GetChildren().OfType<IModel>();
var items = new ObservableCollection<CustomNavigatorItemViewModel>();
foreach (var model in models)
{
var item = new CustomNavigatorItemViewModel(model, this);
items.Add(item);
}

m_Items = items;
}

/// <summary>
/// アイコンを取得する
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
internal object GetIcon(IModel model)
{
if (m_App == null)
{
return null;
}

if (model == null)
{
return null;
}

var icon = m_App.Resources.GetObjectIcon(model);
return icon;
}

#endregion
}
}

カスタムナビゲータに表示する表示要素のクラスを実装します。

CustomNavigatorItemViewModel.cs

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Text;
using System.Linq;
using NextDesign.Core;

namespace CustomUISample.ViewModel.Navigator
{
/// <summary>
/// サンプルナビゲータのアイテムVM
/// </summary>
public class CustomNavigatorItemViewModel : IDisposable
{
#region 内部フィールド

/// <summary>
/// 子要素
/// </summary>
private ObservableCollection<CustomNavigatorItemViewModel> m_Children;

/// <summary>
/// モデル
/// </summary>
private IModel m_Model;

/// <summary>
/// オーナー
/// </summary>
private CustomNavigatorViewModel m_Owner;

#endregion

#region プロパティ

/// <summary>
/// モデル
/// </summary>
public IModel Model => m_Model;

/// <summary>
/// 子要素
/// </summary>
public IEnumerable<CustomNavigatorItemViewModel> Children => m_Children;

/// <summary>
/// アイコン
/// </summary>
public object Icon => m_Owner?.GetIcon(Model);

#endregion

#region 構築・消滅

/// <summary>
/// コンストラクタ
/// </summary>
public CustomNavigatorItemViewModel(IModel model, CustomNavigatorViewModel owner)
{
m_Model = model;
m_Owner = owner;

CreateChildren();
}

/// <summary>
/// 破棄
/// </summary>
public void Dispose()
{
if (m_Model != null)
{
m_Model = null;
}

if (m_Children != null)
{
foreach (var child in m_Children)
{
child.Dispose();
}

m_Children.Clear();
m_Children = null;
}
}

#endregion

#region 内部処理

/// <summary>
/// 子要素の生成
/// </summary>
private void CreateChildren()
{
var children = m_Model.GetChildren().OfType<IModel>();
if (!children.Any())
{
return;
}

if (m_Children == null)
{
m_Children = new ObservableCollection<CustomNavigatorItemViewModel>();
}

foreach (var child in children)
{
var item = new CustomNavigatorItemViewModel(child, m_Owner);
m_Children.Add(item);
}
}

#endregion
}
}

カスタムインスペクタの追加

ユーザコントロールの実装

カスタムインスペクタのビューを定義します。

実装例

CustomInspector.xaml

<UserControl x:Class="CustomUISample.View.Inspector.CustomInspector"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:CustomUISample.View.Inspector"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<TextBlock Text="{Binding Path=Name}"
VerticalAlignment="Center" HorizontalAlignment="Center"/>
</Grid>
</UserControl>

インタフェースの実装

カスタムインスペクタの ViewModel クラスで ICustomInspector を実装します。

実装例

CustomInspectorViewModel.cs

using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;
using NextDesign.Core;
using NextDesign.Desktop.CustomUI;

namespace CustomUISample.ViewModel.Inspector
{
class CustomInspectorViewModel : ICustomInspector
{
#region フィールド

/// <summary>
/// ターゲットモデル
/// </summary>
private object m_Object;

#endregion

#region プロパティ

/// <summary>
/// タイプ記述子
/// </summary>
public ICustomDescriptor Descriptor { get; set; }

/// <summary>
/// 名前
/// </summary>
public string Name
{
get
{
if (m_Object is IModel model)
{
return $"{model.Name}({model.GetType().Name})";
}
return m_Object?.GetType().Name;
}
}

#endregion

#region イベントハンドラ

/// <summary>
/// 初期化
/// </summary>
/// <param name="args">イベントパラメータ</param>
public void OnInitialized(InitializedEventArgs args)
{
// 独自拡張するユーザインタフェースを初期化する際の処理
// Next Designは、独自拡張するユーザインタフェースを初期化する際にこのメソッドを呼び出します。
// 拡張側で初期化時に実行したい処理がある場合はここで実装します。
}

/// <summary>
/// 破棄
/// </summary>
/// <param name="args">イベントパラメータ</param>
public void OnBeforeDispose(BeforeDisposeEventArgs args)
{
// 独自拡張するユーザインタフェースを破棄する前の処理
// Next Designは、独自拡張するユーザインタフェースを破棄する前にこのメソッドを呼び出します。
// 拡張側で破棄前に実行したい処理がある場合はここで実装します。
}

/// <summary>
/// このインスペクタの表示対象のモデルを設定します。
/// </summary>
/// <param name="target">ターゲットのモデル</param>
/// <param name="targets">ターゲットのモデル群</param>
public void SetModel(object target, IEnumerable<object> targets)
{
m_Object = target;
}

#endregion
}
}

カスタム UI 登録処理と登録解除処理の実装

IExtention を実装したメインクラスの公開メソッドである Activate メソッドにカスタム UI の登録処理を実装します。そして、メインクラスの公開メソッドである Deactviate メソッドにカスタム UI の登録解除処理を実装します。

タイプ記述子

カスタムUI を登録する際には、タイプ記述子を指定します。 タイプ記述子では、カスタムUI の静的な情報を定義します。

カスタムUIタイプ記述子定義する情報
カスタムエディタCustomEditorDescriptorID
CustomEditorDefinitionDescriptor
CustomEditorDefinitionDescriptorID
アクセスキー
表示名
グループ名
アイコン
カスタムナビゲータCustomNavigatorDescriptorID
表示名
表示位置
アイコン
カスタムインスペクタCustomInspectorDescriptorID
表示名
表示位置

実装例

カスタムエディタ、ナビゲータ、インスペクタの登録処理、登録解除処理を実装します。

CustomUISampleEntryPoint.cs

using System;
using CustomUISample.View.Editor;
using CustomUISample.View.Inspector;
using CustomUISample.View.Navigator;
using CustomUISample.ViewModel.Editor;
using CustomUISample.ViewModel.Inspector;
using CustomUISample.ViewModel.Navigator;
using NextDesign.Extension;
using NextDesign.Desktop;
using NextDesign.Desktop.CustomUI;

namespace CustomUISample
{
public class CustomUISampleEntryPoint : IExtension
{
/// <summary>
/// エクステンション活性化時の処理
/// </summary>
/// <param name="context">エクステンションのコンテキストです。</param>
public void Activate(IContext context)
{
var registry = context.App.CustomUI;
var extensionName = context.ExtensionInfo.Name;

// カスタムエディタの登録
var customEditorDescriptor = new CustomEditorDescriptor(
typeof(CustomEditorViewModel).FullName,
CustomEditorViewModel.DefinitionDescriptor
);
registry.RegisterCustomEditor<CustomEditorViewModel, CustomEditor>(extensionName, customEditorDescriptor);

// カスタムインスペクタの登録
var customInspectorDescriptor = new CustomInspectorDescriptor(
typeof(CustomInspector).FullName,
"カスタムインスペクタ",
(CustomInspectorDescriptor.DisplayOrderNodeShapeDefinition + 1)
);
registry.RegisterCustomInspector<CustomInspectorViewModel, CustomInspector>(extensionName, customInspectorDescriptor);

// カスタムナビゲータの登録
// モデルナビゲータとプロダクトラインの間に表示します
var customNavigatorDescriptor = new CustomNavigatorDescriptor(
typeof(CustomNavigator).FullName,
"カスタムナビゲータ",
(CustomNavigatorDescriptor.DisplayOrderModel + 1),
@"pack://application:,,,/NextDesign;component/Resources/Images/ModelNavigator.png"
);
registry.RegisterCustomNavigator<CustomNavigatorViewModel, CustomNavigator>(extensionName, customNavigatorDescriptor);
}

/// <summary>
/// エクステンション非活性化時の処理
/// </summary>
/// <param name="context">エクステンションのコンテキストです。</param>
public void Deactivate(IContext context)
{
var registry = context.App.CustomUI;
var extensionName = context.ExtensionInfo.Name;

// カスタムUIの登録解除
registry.UnRegisterAllCustomUIs(extensionName);
}
}
}

カスタムエディタのビュー追加

対象モデルのビューにカスタムエディタを追加します。

操作手順
  1. モデルナビゲータでカスタムエディタを表示する対象モデルを選択します。
  2. コンテキストメニューの [ビューの追加] を選択します。
  3. ビューの追加候補の中に組み込んだカスタムエディタが [カスタムエディタ] の名称で表示されるので選択し、ビューを追加します。
  4. メインエディタで追加したビューに切り替えると、組み込んだカスタムエディタで対象モデルを表示・編集できます。

リファレンス

標準 UI の表示位置

カスタムナビゲータ、カスタムインスペクタは、カスタムUI 登録時に double 型の値で表示位置を指定します。 Next Design 標準のナビゲータ、インスペクタには、IDと固有値が割り当てられています。値が小さいほど画面上で左側に表示されますので、特定のナビゲータ、インスペクタの右隣に表示する場合は、そのナビゲータ、インスペクタの値 +1 の値を指定するなどしてください。

以下に Next Design 標準のナビゲータ、インスペクタの表示位置の値を示します。

  • 参考:標準ナビゲータの表示位置

    ナビゲータID
    モデルナビゲータCustomNavigatorDescriptor.DisplayOrderModel100
    プロダクトラインナビゲータCustomNavigatorDescriptor.DisplayOrderProductLine200
    構成管理ナビゲータCustomNavigatorDescriptor.DisplayOrderScm300
    プロジェクトナビゲータCustomNavigatorDescriptor.DisplayOrderProject400
    プロファイルナビゲータCustomNavigatorDescriptor.DisplayOrderProfile500
  • 参考:標準インスペクタの表示位置

    インスペクタID
    プロパティ(モデル)CustomInspectorDescriptor.DisplayOrderModel100
    関連(モデル)CustomInspectorDescriptor.DisplayOrderRelationship200
    ダイアグラム定義CustomInspectorDescriptor.DisplayOrderDiagramDefinition1000
    シェイプ定義(ノード)CustomInspectorDescriptor.DisplayOrderNodeShapeDefinition1100
    シェイプ定義(ポート)CustomInspectorDescriptor.DisplayOrderPortShapeDefinition1200
    シェイプ定義(コネクタ)CustomInspectorDescriptor.DisplayOrderConnectorShapeDefinition1300
    フォーム定義CustomInspectorDescriptor.CustomInspectorDescriptor2000
    フォーム要素(コントロール)CustomInspectorDescriptor.DisplayOrderFormControlDefinition2100
    フォーム要素(グループ)CustomInspectorDescriptor.DisplayOrderGroupDefinition2200
    フォーム要素(グリッド)CustomInspectorDescriptor.DisplayOrderGridDefinition2300
    フォーム要素(リスト)CustomInspectorDescriptor.DisplayOrderListDefinition2400
    行の定義CustomInspectorDescriptor.DisplayOrderTreeGridRow3100
    シェイプ定義(ライフライン)CustomInspectorDescriptor.DisplayOrderLifelineShapeDefinition4100
    シェイプ定義(ノート(シーケンス)・複合フラグメント)CustomInspectorDescriptor.DisplayOrderSequenceNodeShapeDefinition4200
    シェイプ定義(メッセージ(シーケンス))CustomInspectorDescriptor.DisplayOrderMessageShapeDefinition4300
    シェイプ定義(ノートアンカ)CustomInspectorDescriptor.DisplayOrderNoteAnchorShapeDefinition4400
    シェイプ定義(実行仕様・破棄・メッセージ端)CustomInspectorDescriptor.DisplayOrderSequenceShapeDefinition4500
    パッケージCustomInspectorDescriptor.DisplayOrderPackage10000
    メタモデル(クラス)CustomInspectorDescriptor.DisplayOrderClass11000
    メタモデル(関連クラス)CustomInspectorDescriptor.DisplayOrderRelationshipClass11100
    フィールドCustomInspectorDescriptor.DisplayOrderField12000
    列挙CustomInspectorDescriptor.DisplayOrderEnum13000