Quantcast
Channel: SourceChord
Viewing all 153 articles
Browse latest View live

Build 2017メモ

$
0
0

ここ最近、Build2017の動画を色々と見て回ってました。
その中で、面白かったものなどを、いくつかメモっておこうと思います。

Fluent Design System

今回のBuildで印象に残ったのは、やっぱコレ。

http://fluent.microsoft.com/
https://channel9.msdn.com/Events/Build/2017/B8066

PlayGound is Expanding

今後、ソフトウェアの対象とするデバイスはどんどん多様になっていきます。

  • 普通のデスクトップPCやスマートフォンのような2Dなディスプレイを持っているデバイス
  • Amazon Echoとかみたいな、ディスプレイ表示を持たない0Dなデバイスから、
  • Hololenseや、その他VR系デバイスなどでの3Dな表示

このような0D~3Dまでの多様なデバイスで一貫したUXを提供する、ってのがポイントですかね。

↓のスライドでこの辺の話題をわかりやすくまとめてくれています。
https://speakerdeck.com/ahomu/fluent-design-system-in-5-minutes

UWPの今後

https://channel9.msdn.com/Events/Build/2017/B8100

Fluent Design SystemでUIがどう変わるかという説明や、どうやってXAMLで実装していくかの説明がされていました。

あと、この動画の最後の方(1:03:30~)のとこで、今後対応する内容の中に「Custom Markup Extension」ってあります。
そのうち、UWPでもMarkupExtension作れるようになるっぽいですね。メッチャ楽しみ!!

XAML Standard

https://github.com/Microsoft/xaml-standard

XAMLを使う各プラットフォームで、
それぞれが方言のような感じで分裂していくのを防ぎたいってことでしょうかね。

Xamarin.Formsって、微妙に各種要素の名前が他のXAML系プラットフォームと違って気持ち悪かったんで、これはちょっと嬉しいニュース。
StackPanelと言わずにStackLayoutになってるとか、
かなりAndroidに寄せたネーミングになってるなぁ、なんて印象は受けてました。

この辺のクラス名がある程度整理されると、微妙な違いな無くなってうれしいんだけど、
これって、既存のXamarin.Formsの各種クラス名をXAML Standardに合わせて名前変えてくってことなんだろうか??

ただ、このXAML Standardでの共通化の話で、WPFが置いてけぼりにされてる感が・・・
MSさん、、、たまにはWPFの事も思い出してあげてください。。。

ちなみに、↓のissuesなどにWPF開発者の方々の声が集まってます。
https://github.com/Microsoft/xaml-standard/issues/20
この辺、今後どうなるか定期的にウォッチしておこうかと思います。

とか思ってたら、こっちのスライドの19ページ目では、
XamarinでもWPFXAMLが再利用できる、、なんて書き方になってるけど、どうなるんでしょうね??
https://view.officeapps.live.com/op/view.aspx?src=https%3a%2f%2fsec.ch9.ms%2fsessions%2fc1f9c808-82bc-480a-a930-b340097f6cc1%2fbuild%2f2017%2fB8110.pptx

UWPのお話

UWPのコントロールについて

https://channel9.msdn.com/Events/Build/2017/B8035

定番どころの3rdパーティ製コントロールライブラリの紹介や、コントロールのスタイル変更やカスタムコントロールの作り方などの説明

UWPでのパフォーマンス向上Tips

https://channel9.msdn.com/Events/Build/2017/P4173

遅延ローディングを使ったTipsとか、その他いろいろパフォーマンス向上などにつながりそうなTips紹介

NuGet

https://channel9.msdn.com/Events/Build/2017/T6081

5:50~あたりで、新しいパッケージング方法の説明をしてます。

.net standardなクラスライブラリだと、
nuspecを書いてnuget.exeからパッケージングするのではなく、プロジェクトのプロパティで設定しておいてビルド時にパッケージを作れるようになってるんですね。
f:id:minami_SC:20170521134526p:plain

どうでもいいですが、いつも読み方に迷うコイツ「NuGet」ですが、にゅーげっとって発音してますね。

VSCode

https://channel9.msdn.com/Events/Build/2017/T6078

動画の中で↓のリポジトリが紹介されてました。
https://github.com/Microsoft/vscode-tips-and-tricks
VSCodeのTipsなどが色々とまとまっています。

VisualStudio

https://channel9.msdn.com/Events/Build/2017/B8083

プレゼンの冒頭で目の不自由なエンジニアの方が、音声読み上げを使ってライブコーディングしてました。

で、その音声読み上げ、
ものすごいスピードで読み上げしてるんです。
一瞬、何が起きたのかわからなかった。
でも、スクリーンリーダーを使って、ガリガリとコーディングしてました。

ソフトウェアのアクセシビリティ対応をちゃんとしていると、こんなことまでできるのか、、、と色々と感じるものがありました。

Edge

https://channel9.msdn.com/Events/Build/2017/B8041

39:31~
CSS Grid Layoutの対応を進めているみたいですね。

IEやEdgeは一足先にCSS Grid Layoutに対応し始めたのに・・・
その後なんだかんだでCSS Grid Layoutは新しい仕様に変わり、IE/Edgeは新しい仕様に対応せず、取り残された状態になってました。

これは対応がとても待ち遠しいです!!


Windows Template Studioを使ってみた

$
0
0

Build 2017の動画とか↓のブログ見て知ったのですが、こんなVS拡張機能が出てきました。

Windows Template Studio - Visual Studio Marketplace

今まで、UWPプロジェクトの雛形は、空っぽなウィンドウが表示されるだけの、非常に簡素なものしかありませんでした。   ですが、この拡張機能を使うと、ナビゲーションやMVVMなどを取り入れたプロジェクト雛形を、自分でカスタマイズして生成することができるようになります。

ちなみに、今後6週間程度の間隔で更新を続けるようです。

これは便利かも!!

似たような立ち位置のものとして、Template10っていうのがあったんだけど、この辺との棲み分けってどうなっていくのかな??

使い方

VisualStudioのツールメニュー⇒「拡張機能と更新プログラム」から、以下の拡張機能をインストールします。
f:id:minami_SC:20170524084820p:plain

この拡張機能をインストールすると、「Windows Template Studio」という新しいプロジェクトのテンプレートが追加されます。
f:id:minami_SC:20170524084837p:plain

このテンプレートでプロジェクトを作成すると、ウィザードで以下のような構成を自分で取捨選択し、プロジェクトの雛形が作れるようになっています。

↓のようなウィザードで、これらの構成を選んでいきます。
f:id:minami_SC:20170524085023p:plainf:id:minami_SC:20170524085031p:plain

生成されたプロジェクトの構成

最小構成のプロジェクト

まず、以下のような構成にしてプロジェクトを作ってみます。

  • ProjectType: Blank
  • Framework: Code Behind
  • Pages, Features: デフォルトのまま

こんな感じの構成のプロジェクトが出来上がります。
f:id:minami_SC:20170524085048p:plain

ナビゲーションを使わないプロジェクトタイプにしてますが、NavigationServiceやActivationServiceと言ったヘルパークラス類が追加されるようです。
こういうクラスはなんだかんだで必要になるんで、デフォルトで用意してくれると便利ですね。

他にも、ResouceExtensionsとかSingleton、ActivationHandlerなどといったクラスが用意されています。

実行すると、↓のようなウィンドウが表示されます。
f:id:minami_SC:20170524085447p:plain

最小構成なので、実行されるアプリは非常にシンプルなものです。

MVVM Basicのプロジェクト

続いて、Frameworkを「MVVM Basic」にした場合に生成されるプロジェクトを見てみます。

こんな感じのプロジェクト構成になっています。
f:id:minami_SC:20170524085100p:plain

Helpersフォルダに、ObservableとかRelayCommandといった、MVVMなプロジェクトの定番クラス類が用意されています。
BindableBaseじゃなくて、Observableってのが若干しっくりこないんですが、まぁこの辺は好みの問題でしょうか。

また、Views/ViewModelsフォルダが用意され、MainPageとそれに対応するMainViewModelクラスが作られています。

こんな風に、よくある形のViewとViewModelになってます。
デフォルトの状態だと、MainPageのDataContextにViewModelが設定されてません。
ですので、XAMLからバインディングする際には、x:BindでViewModelプロパティを通してバインドする必要があるので注意!!
f:id:minami_SC:20170524085117p:plain

個人のコーディングスタイルに合わせて、場合によってはDataContextにViewModelを設定したりするとよいかもしれません。 MainPage.xaml.cs

publicsealedpartialclass MainPage : Page
    {
        public MainViewModel ViewModel { get; } = new MainViewModel();
        public MainPage()
        {
            InitializeComponent();
        }
    }

MainVewModel.cs

publicclass MainViewModel : Observable
    {
        public MainViewModel()
        {
        }
    }

MVVM Lightのプロジェクト

最後に、MVVM Light Toolkitを使った構成のプロジェクトです。

こんな感じのプロジェクトが生成されました。
f:id:minami_SC:20170524085133p:plain

自分は、MVVM Light Toolkitはそんなに使っていないので、ここは省略します。

次回は、これらの雛形で用意されているクラスの役割などを少しずつ見ていきたいと思います。

Windows Template Studio雛形コードの使い方~Blank & CodeBehindなプロジェクト~

$
0
0

これから何回かに分けて、WindowsTemplateStudioで生成したプロジェクトが、どのような構造になっているか見ていこうと思います。

今回は最初なので、UWPの基本的な仕組みも含めて色々と試してみます。

プロジェクトの作成

WindowsTemplateStudioの雛形で、以下の構成でプロジェクトを作成します。

  • ProjectType: Blank
  • Framework: Code Behind
  • Pages, Features: デフォルトのまま

全体の構成

まずは、プロジェクト全体の構造のおさらい。

こんなプロジェクトが生成されます。
f:id:minami_SC:20170527124602p:plain

この構成のプロジェクトでは、主にViewsやModelsフォルダにコードを書いていくことになりそうな雛形ですね。

アプリのスタートアップ処理

で、この辺の処理ではActivationService/ActivationHandlerなどのクラスが色々と出てきます。
この辺の処理は複雑なので、スタートアップ処理全体の流れは、一番最後にまとめて確認したいと思います。

まずはAppクラスの中身を確認します。
最初にチェックしておくポイントは、以下の関数。

このActivationServiceのコンストラクタで、第二引数に渡している型が、最初に表示されるページになります。

/// <summary>/// Provides application-specific behavior to supplement the default Application class./// </summary>sealedpartialclass App : Application
    {
        // :// 略// :private ActivationService CreateActivationService()
        {
            returnnew ActivationService(this, typeof(Views.MainPage));
        }
    }

ページ表示

MainPageクラス

今回のサンプルは、MVVMは使わず、コードビハインドを利用した雛形となっています。

そのため、ViewModelクラスはなく、以下のようにMainPageクラスでINotifyPropertyChangedインターフェースを実装しています。
Setメソッドも用意されていて、PropertyChangedイベントを呼び出す処理が実装されています。

publicsealedpartialclass MainPage : Page, INotifyPropertyChanged
    {
        public MainPage()
        {
            InitializeComponent();
        }

        publicevent PropertyChangedEventHandler PropertyChanged;

        privatevoid Set<T>(ref T storage, T value, [CallerMemberName]string propertyName = null)
        {
            if (Equals(storage, value))
            {
                return;
            }

            storage = value;
            OnPropertyChanged(propertyName);
        }

        privatevoid OnPropertyChanged(string propertyName) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

MainPageへの処理追加

このページのコードをちょっと修正し、以下のようなサンプルを作ってみたいと思います。

  • TextBoxで文字列を入力
  • ↑の文字列をTextBlockで表示
  • ボタンを押すと、TextBoxの入力内容をクリア

実行するとこんな感じの画面になります。
f:id:minami_SC:20170527124634p:plain

string型のInputプロパティを作り、ボタンクリック時にはそのプロパティをクリアするだけのサンプルです。
MainPage.xaml/MainPage.xaml.csを、それぞれ以下のように修正します。

MainPage.xaml

<Pagex:Class="Blank_CodeBehind.Views.MainPage"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"mc:Ignorable="d"><Gridx:Name="ContentArea"Margin="12,0,12,0"><Grid.RowDefinitions><RowDefinition x:Name="TitleRow"Height="48"/><RowDefinition Height="*"/></Grid.RowDefinitions><TextBlockx:Name="TitlePage"x:Uid="Main_Title"Text="Navigation Item 2"FontSize="28"FontWeight="SemiLight"TextTrimming="CharacterEllipsis"TextWrapping="NoWrap"VerticalAlignment="Center"Margin="0,0,12,7"/><Grid Grid.Row="1"Background="{ThemeResource SystemControlPageBackgroundChromeLowBrush}"><StackPanel><TextBox Margin="5"Width="120"Text="{x:Bind Input, Mode=TwoWay}"HorizontalAlignment="Left" /><TextBlock Text="{x:Bind Input, Mode=OneWay}" /><Button Content="Clear"HorizontalAlignment="Left"Margin="5"Click="Button_Click"/></StackPanel></Grid></Grid></Page>

MainPage.xaml.cs

publicsealedpartialclass MainPage : Page, INotifyPropertyChanged
    {
        public MainPage()
        {
            InitializeComponent();

            this.DataContext = this;
        }

        privatestring input;
        publicstring Input
        {
            get { return input; }
            set { this.Set(refthis.input, value); }
        }

        privatevoid Button_Click(object sender, Windows.UI.Xaml.RoutedEventArgs e)
        {
            this.Input = string.Empty;
        }

        publicevent PropertyChangedEventHandler PropertyChanged;

        privatevoid Set<T>(ref T storage, T value, [CallerMemberName]string propertyName = null)
        {
            if (Equals(storage, value))
            {
                return;
            }

            storage = value;
            OnPropertyChanged(propertyName);
        }

        privatevoid OnPropertyChanged(string propertyName) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

ページ遷移

ここで作った雛形では、単一のMainPageしか用意されていません。
自分で新規ページを追加すると、以下のような手順でページ遷移が行えます。

プロジェクト作成時のウィザードで、複数のページを作っていた場合も、同様の方法でページ遷移できます。

ページの追加

Viewsフォルダを右クリックし、メニューから「新しい項目」を選んでクリックします。
「空白のページ」を選んで、新しいページをプロジェクトに追加しましょう。
f:id:minami_SC:20170527124654p:plain
f:id:minami_SC:20170527124720p:plain
このページには、以下のようにTextBlockでのメッセージだけ追加しておきます。
BlankPage1.xaml

<Page x:Class="Blank_CodeBehind.Views.BlankPage1"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:local="using:Blank_CodeBehind.Views"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"mc:Ignorable="d"><Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"><TextBlock Margin="5"HorizontalAlignment="Left"VerticalAlignment="Top"Text="This is BlankPage1.xaml"TextWrapping="Wrap" /></Grid></Page>

追加したページへの移動

MainPageに以下のようなボタンを追加します。
MainPage.xaml

<Button Content="Navigate"HorizontalAlignment="Left"Margin="5"Click="GoToBlankPage"/>

ボタンクリック時のイベントハンドラは、以下のようにします。
NavigationServiceクラスを用いて、ページ遷移の指示を行います。

MainPage.xaml.cs

privatevoid GoToBlankPage(object sender, Windows.UI.Xaml.RoutedEventArgs e)
        {
            Services.NavigationService.Navigate<BlankPage1>();
        }

Navigateボタンをクリックすると、ページ遷移します。
ページ遷移すると、ウィンドウ左上に「←」ボタンが出るので、このボタンでページを戻ることができます。
f:id:minami_SC:20170527124918p:plainf:id:minami_SC:20170527124931p:plain

戻る/進む

先ほどのサンプルでは、自動で表示される「←」ボタンでページを戻りましたが、
NavigationServiceの以下のメソッドで、ページを戻る/進む、という動作を実行できます。

戻る処理

if (Services.NavigationService.CanGoBack)
            {
                Services.NavigationService.GoBack();
            }

進む処理

if (Services.NavigationService.CanGoForward)
            {
                Services.NavigationService.GoForward();
            }

ローカライズ処理

x:Uid属性とreswファイルを用いたローカライズ

UWPでは、reswファイルを用いたローカライズが行えます。
詳細は、↓のページなどに詳しくまとまっています。
http://www.atmarkit.co.jp/ait/articles/1210/25/news026.html
http://aile.hatenablog.com/entry/2016/04/05/224806

雛形のデフォルトの状態だと、「en-us」のリソースのみが用意されています。
ここでは、「ja-jp」のリソースを追加して、日本語環境用の表示文字列を定義してみます。

ja-jpフォルダを作成し、その中に「リソースファイル(.resw)」を作成します。
f:id:minami_SC:20170527125021p:plain

そして、以下のように「Main_Title.Text」の項目に、日本語環境で表示したい文字列を設定します。
f:id:minami_SC:20170527125033p:plain

実行するとこの通り。
f:id:minami_SC:20170527125050p:plain

これだけで、x:Uid="Main_Title"の要素を日英対応するようローカライズできました。

言語設定の切り替え

ここで行ったローカライズでは、OSの表示言語設定に応じてアプリ表示の文字列が切り替わります。

しかし、OSの表示言語設定を切り替えるのは少し面倒です。

ちょっとだけ別言語での表示を確認したい、というようなときは、以下のようにAppクラスのOnLaunchedイベントで言語設定を切り替えてしまえば、別言語環境で表示される文字列をチェックでできます。

protectedoverride async void OnLaunched(LaunchActivatedEventArgs e)
        {
            // 表示言語の設定
            System.Globalization.CultureInfo.CurrentUICulture = new System.Globalization.CultureInfo("en-US");
            if (!e.PrelaunchActivated)
            {
                await ActivationService.ActivateAsync(e); 
            }
        }

この方法だと、言語設定が完全には切り替わりません。
ですので、reswファイルで設定した文字列のチェック程度にとどめておき、画面キャプチャなどが必要な場合には実際にOSの表示言語を切り替えた方がよいかと思います。

ヘルパークラス類

ResouceExtensionsクラス

x:Uidやreswを使うと、各種コントロールなどに表示する文字列は簡単にローカライズできます。
しかし、コードビハインドなど、C#コードからreswに定義した文字列にアクセスしたくなる場合もあると思います。

このResourceExtensionsクラスは、reswの内容へのアクセスを補助するヘルパークラスです。
呼び出し方はこんな感じ。

            var text = Helpers.ResourceExtensions.GetLocalized("Main_Title/Text");
            var dlg = new MessageDialog(text);
            await dlg.ShowAsync();

.reswファイルで、Main_Title.Textのように「.」区切りで書いていた部分は、「/」に置き換えてアクセスする必要があるので注意!!

Singletonクラス

一応、こんな風に任意のクラスをシングルトンとして扱えるようにする、汎用的なヘルパークラスです。

private async void Button_Click_1(object sender, Windows.UI.Xaml.RoutedEventArgs e)
        {
            var person = Helpers.Singleton<Person>.Instance;
            System.Diagnostics.Debug.WriteLine(person.Name);
        }


    publicclass Person
    {
        publicstring Name { get; set; }
        publicint Age { get; set; }
    }

スタートアップ処理の全体像

ActivationService & ActivationHandlerクラス

WindowsTemplateStudioで生成されるコードで、一番の鬼門になるのはこの辺かと思います。 ちょっとクラス構成も入り組んでますし、各関数の呼ばれるタイミングも、少しわかりにくいです。

ということで、GitHubリポジトリでも、↓にこのActivationService周りの説明をするページが用意されていました。 https://github.com/Microsoft/WindowsTemplateStudio/blob/master/docs/activation.md

アプリを普通に起動するのではなく、サスペンドからの復帰だったり、ファイル関連付けからの起動などなど、
アプリがアクティブになる、様々なパターンを扱いやすくするようにこんな構造になっているようです。

クラス構成

アプリの起動処理に関わるクラス構成は、以下のようになっています。

f:id:minami_SC:20170527125103p:plain

これらのクラスが、以下のようなシーケンスで呼び出されて、初期画面のMainPageが表示されます。
f:id:minami_SC:20170527125115p:plain

少々複雑な構成ですが、ここさえ理解できれば、このテンプレートでは他に難しいところは特にないかと思います。

基本的には、ActivationHandler派生のクラスを作成し、作成したクラスをActivationSerivceに登録することで、起動処理をカスタマイズできるような構成になっています。

アプリ起動処理のカスタマイズ(ファイルの関連付け)

このアプリを、ファイル関連付けから起動できるようにカスタマイズしてみます。

まずは、プロジェクトのプロパティから、「パッケージマニフェスト」の画面を開き、以下のように赤線の部分を設定します。
f:id:minami_SC:20170527125133p:plain

続いて、App.xaml.csでOnFileActivatedイベントの処理を追加します。
ファイル関連付けから起動された場合にも、ActivationServiceでの起動処理が実行されるようにしています。

App.xaml.cs

protectedoverride async void OnFileActivated(FileActivatedEventArgs args)
        {
            //base.OnFileActivated(args);
            await ActivationService.ActivateAsync(args);
        }

次に、FileAssociationServiceというクラスをServicesフォルダに追加します。
このファイルの内容は以下の通り。
FileAssociationService.cs

internalclass FileAssociationService : ActivationHandler<File<200b>Activated<200b>Event<200b>Args>
    {
        protectedoverride async Task HandleInternalAsync(FileActivatedEventArgs args)
        {
            // ファイルの情報を表示
            var file = args.Files.FirstOrDefault();
            var dlg = new MessageDialog($"{file.Name}を指定して、起動されました。");
            await dlg.ShowAsync();

            // MainPageへと遷移
            NavigationService.Navigate(typeof(MainPage));
            await Task.CompletedTask;
        }
    }

最後に、ActivationSerivceクラスに以下の行を追加し、アクティベーション処理の中で、先ほど追加したFileAssociationServiceのインスタンスを登録しておきます。

ActivationService.cs

private IEnumerable<ActivationHandler> GetActivationHandlers()
        {
            yieldreturn Helpers.Singleton<FileAssociationService>.Instance;    // ←追加yieldbreak;
        }

ここまで出来たら、一度ビルドしてから実行しておきます。

動作確認

作ったアプリを一度実行しておくと、以下のように「プログラムから開く」のメニューに、このアプリが追加されています。
f:id:minami_SC:20170527125154p:plain

ここからアプリを起動すると、先ほど作成したFileAssociationServiceの処理が実行されていることが確認できます。
f:id:minami_SC:20170527125207p:plain

ファイル関連付けの解除

作成したアプリをアンインストールすると、「プログラムから開く」メニューの項目は自動で削除されます。

今回はここまで。
次は、MVVM Basicなプロジェクトを見ていきたいと思います。

Windows Template Studio雛形コードの使い方~Blank & MVVM Basicなプロジェクト~

$
0
0

今度は、MVVM Basicな構成のプロジェクトを見ていきます。
この雛形は、シンプルなMVVM構成でコードを書く時には、割と使い勝手がいいかなと思います。

準備

まずは、以下の設定でプロジェクトを作成します。

  • ProjectType: Blank
  • Framework: MVVM Basic
  • Pages, Features: デフォルトのまま

プロジェクトの全体構成はこんな感じです。
f:id:minami_SC:20170527232606p:plain

Code BehindとMVVM Basicのプロジェクトの違い

アプリの起動処理や、一部の各種ヘルパー関数などは、前回のCode Behindなプロジェクトと共通です。

違いは以下のような点です。

  • Helpersフォルダに、以下のようなMVVM設計のための基底クラスが用意されている
    • Observableクラス
    • RelayCommandクラス
  • Views/ViewModelsフォルダ
    • Observableクラスを継承した、MainViewModelクラス
    • MainPage.xaml.csは、↑をプロパティとして持つだけのシンプルな構成

MVVMな設計のためのヘルパークラス類

MVVM Basicでは、Helpersフォルダに以下のようなObservable/RelayCommandといったクラスが追加されています。
これらは、MVVMな設計をする上での必需品となる、INotifyPropertyChangedとICommandインターフェースの実装クラスです。

C#7.0な書き方が多用されていますが、↓に書いたようなコードとだいたい同じことが書かれています。
http://sourcechord.hatenablog.com/entry/20130303/1362315081
http://sourcechord.hatenablog.com/entry/2014/01/13/200039

Observable.cs

publicclass Observable : INotifyPropertyChanged
    {
        publicevent PropertyChangedEventHandler PropertyChanged;

        protectedvoid Set<T>(ref T storage, T value, [CallerMemberName]string propertyName = null)
        {
            if (Equals(storage, value))
            {
                return;
            }

            storage = value;
            OnPropertyChanged(propertyName);
        }

        protectedvoid OnPropertyChanged(string propertyName) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

RelayCommand.cs

publicclass RelayCommand : ICommand
    {
        privatereadonly Action _execute;
        privatereadonly Func<bool> _canExecute;

        publicevent EventHandler CanExecuteChanged;
        public RelayCommand(Action execute) : this(execute, null) { }

        public RelayCommand(Action execute, Func<bool> canExecute)
        {
            this._execute = execute ?? thrownew ArgumentNullException("execute");
            this._canExecute = canExecute;
        }

        publicbool CanExecute(object parameter) => _canExecute == null || _canExecute();
        publicvoid Execute(object parameter) => _execute();
        publicvoid OnCanExecuteChanged() => CanExecuteChanged?.Invoke(this, EventArgs.Empty);
    }

    publicclass RelayCommand<T> : ICommand
    {
        privatereadonly Action<T> _execute;
        privatereadonly Func<T, bool> _canExecute;

        publicevent EventHandler CanExecuteChanged;
        public RelayCommand(Action<T> execute) : this(execute, null) { }

        public RelayCommand(Action<T> execute, Func<T, bool> canExecute)
        {
            this._execute = execute ?? thrownew ArgumentNullException("execute");
            this._canExecute = canExecute;
        }

        publicbool CanExecute(object parameter) => _canExecute == null || _canExecute((T)parameter);
        publicvoid Execute(object parameter) => _execute((T)parameter);
        publicvoid OnCanExecuteChanged() => CanExecuteChanged?.Invoke(this, EventArgs.Empty);
    }

ViewsとViewModelsフォルダ

MainPage.xaml
MainPageのxamlは、前回のコードビハインドを用いたプロジェクトとほぼ同様のものです。
ということで、ここではコードは省略します。

MainPage.xaml.cs
MainPageのコードビハインドは、ViewModelのプロパティを持つだけのシンプルなものになっています。
前回と違い、MVVMなスタイルでViewとViewModelを分離しているので、コードビハインドはINotifyPropertyChangedの実装などはせず、シンプルな形になっています。

publicsealedpartialclass MainPage : Page
    {
        public MainViewModel ViewModel { get; } = new MainViewModel();
        public MainPage()
        {
            InitializeComponent();
        }
    }

MainViewModel.cs
ViewModelは、Observableを継承しただけのシンプルなものが用意されています。

publicclass MainViewModel : Observable
    {
        public MainViewModel()
        {
        }
    }

サンプル

ObservableやRelayCommandどのクラスを利用し、ちょっとしたサンプルコード書いてみます。

テキストボックスの文字列をViewModelのNameプロパティとバインドしておき、
Clearボタンが押されたら、RelayCommandを用いて上記Nameプロパティをクリアします。

f:id:minami_SC:20170527233040p:plain

View/ViewModelのコードは、それぞれ以下のような感じ。

MainPage.xaml

<Pagex:Class="Blank_MvvmBasic.Views.MainPage"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"mc:Ignorable="d"><Gridx:Name="ContentArea"Margin="12,0,12,0"><Grid.RowDefinitions><RowDefinition x:Name="TitleRow"Height="48"/><RowDefinition Height="*"/></Grid.RowDefinitions><TextBlockx:Name="TitlePage"x:Uid="Main_Title"FontSize="28"FontWeight="SemiLight"TextTrimming="CharacterEllipsis"TextWrapping="NoWrap"VerticalAlignment="Center"Margin="0,0,12,7"/><Grid Grid.Row="1"Background="{ThemeResource SystemControlPageBackgroundChromeLowBrush}"><StackPanel><TextBox Margin="5"Width="200"Text="{x:Bind ViewModel.Name, Mode=TwoWay}"HorizontalAlignment="Left" /><Button Content="Clear"HorizontalAlignment="Left"Margin="5"Command="{x:Bind ViewModel.ClearCommand}" /></StackPanel></Grid></Grid></Page>

MainPage.xaml.cs
雛形コードのまま変更なし。

MainViewModel.cs

publicclass MainViewModel : Observable
    {
        public MainViewModel()
        {
        }

        // Observableクラスで定義されているSetメソッドを使うことで、// プロパティの値が更新されたら、INotifyPropertyChangedでの更新通知イベントが呼び出されます。privatestring name;
        publicstring Name
        {
            get { return name; }
            set { this.Set(refthis.name, value); }
        }

        // 以下、RelayCommandクラスを用いたコマンドの実装private RelayCommand clearCommand;
        public RelayCommand ClearCommand
        {
            get { return clearCommand = clearCommand ?? new RelayCommand(Clear); }
        }
        privatevoid Clear()
        {
            this.Name = string.Empty;
        }
    }

コマンド実行のEnable/Disable制御

RelayCommandのCanExecuteを利用して、コマンド実行可否の制御をしてみます。

UWPではx:Bindによってイベントから関数へと直接バインドすることができます。
なので、RelayCommandクラスを用いずとも、前述のサンプルと同等の事は実装できます。

しかし、RelayCommandではコマンドが実行可能か否かをコマンド自身が示すことができるようになっています。
コマンドが実行可能かどうかを判断するチェック処理を定義しておくと、コマンドをボタンにバインドしたときに、自動でEnable/Disable制御をしてくれるようになります。

ということで、コマンドの実行可否の制御をしてみます。
修正点は以下の二つ。

  • RelayCommand作成時に、第二引数でコマンド実行できるかどうかのチェック処理を渡す
  • NameプロパティのSetterで、ClearCommandのOnCanExecuteChangedを呼び出す
    • Nameプロパティが変わる = Clearボタンの実行可否が変わる可能性があるため

こうすると、ClearCommandをボタンのCommandプロパティにバインドしておくだけで、
CanExecuteがfalseの時には、ボタンが勝手にDisable状態へと変化します。

publicclass MainViewModel : Observable
    {
        public MainViewModel()
        {
        }

        // Observableクラスで定義されているSetメソッドを使うことで、// プロパティの値が更新されたら、INotifyPropertyChangedでの更新通知イベントが呼び出されます。privatestring name;
        publicstring Name
        {
            get { return name; }
            set { this.Set(refthis.name, value); this.ClearCommand.OnCanExecuteChanged(); }
        }

        // 以下、RelayCommandクラスを用いたコマンドの実装private RelayCommand clearCommand;
        public RelayCommand ClearCommand
        {
            get { return clearCommand = clearCommand ?? new RelayCommand(Clear, () => !string.IsNullOrWhiteSpace(this.Name)); }
        }
        privatevoid Clear()
        {
            this.Name = string.Empty;
        }
    }

Windows Template Studio雛形コードの使い方~Pivot & Tabs プロジェクト~

$
0
0

今度は、Pivotを用いたプロジェクトを作ってみます。

Pivotのプロジェクトは、前回使用したBlankプロジェクトと共通点も多く、割とシンプルな構成になっています。
チェックすべき箇所も少ないので、CodeBehind版/MVVM Basic版の両方をまとめて見ていきます。

プロジェクトの作成

それぞれ、以下のような設定でプロジェクトを作成します。

CodeBehind版
  • ProjectType: Pivot and Tabs
  • Framework: Code Behind
  • Pages, Features: Blank Pageを一つ追加
MVVM Basic版
  • ProjectType: Pivot and Tabs
  • Framework: MVVM Basic
  • Pages, Features: Blank Pageを一つ追加

Pivotでページ切替を行うので、プロジェクト作成時に以下のボタンで、Blank Pageを一つ追加しておきましょう。
f:id:minami_SC:20170529103629p:plain

Pivotプロジェクトの構成

Pivotプロジェクトは、今まで使ってきたBlankとほぼ同じプロジェクト構成になっています。
ここでは、Blankとの違いだけを確認します。

以下のファイルが、Blankプロジェクトと比較して新たに追加された要素となります。

CodeBehindMVVM Basic
f:id:minami_SC:20170529104412p:plainf:id:minami_SC:20170529104420p:plain

App.xaml.cs
ActivationServiceをPivotPageを指定で生成するようになっています。
ということで、アプリを起動するとPivotPage.xamlが表示されます。

private ActivationService CreateActivationService()
        {
            returnnew ActivationService(this, typeof(Views.PivotPage));
        }

PivotPage
PivotPageでは、Pivotコントロールを使って、MainPageとBlankPageの表示切り替えを行っています。
ただPivotコントロールがあるだけのシンプルなページですね。

<Pagex:Class="Pivot_MvvmBasic.Views.PivotPage"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"xmlns:model="using:Pivot_MvvmBasic.Models"xmlns:views="using:Pivot_MvvmBasic.Views"mc:Ignorable="d"><Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"><Pivot x:Uid="PivotPage"><PivotItem x:Uid="PivotItem_Main"><Frame><views:MainPage/></Frame></PivotItem><PivotItem x:Uid="PivotItem_Blank"><Frame><views:BlankPage/></Frame></PivotItem></Pivot></Grid></Page>

PivotPage.xaml.cs
コードビハインドは、CodeBehind/MVVMBasicなどの、選択したプロジェクトタイプに合わせた内容のコードが生成されています。
特筆すべき点はないので、ここは省略します。

PivotViewModel.cs MVVM Basicのプロジェクトタイプの場合は、以下のようなVMが作成されます。
特に何もしていない、

publicclass PivotViewModel : Observable
    {
        public PivotViewModel() 
        {
        }
    }

実行すると、こんな感じのウィンドウが表示されます。
f:id:minami_SC:20170529103651p:plain

TypeScriptのQuickStartページ

$
0
0

いつの間にか、TypeScriptの公式サイトに↓こんなページができていました。
Quick Start · TypeScript

ReactやAngular、Vue.js、Knockout.jsといった定番フレームワークを用いたフロントエンド開発や、
Express, ASP.NET Coreなどのサーバーサイド開発でTypeScriptを使ったサンプル等が公開されています。

ただ、入門用としては少々複雑なものもあるかな、、という印象でした。
特にNode.jsのサンプルは、どう考えてもやりすぎだろ、、、と。
npm scriptもかなり細分化して、ビルド処理、ウォッチ処理、jestを使った単体テストやtslintなど、盛りだくさんです。

QuickStartと言うなら、なるべく余計なものはそぎ落とした方が、
TypeScriptの使い方を学びやすくなるのにな、、、という気がします。

でもまぁ、なんだかんだで色々と参考になるのでは、と思います。

Node.js 8.0をインストールしてみた

$
0
0

Node.js 8.0がリリースされていたので、インストールしてみました。

https://nodejs.org/ja/

最近、Node.js自体の更新はあまり追いかけてなかったのですが、今回の更新は結構魅力的ですね!!

バンドルされるnpmがv5に更新されたり、utilモジュールにpromisify関数が追加されたりと、色々便利な更新が含まれています。

ということで、気になる変更点をφ(..)メモメモ

バンドルされるnpmのバージョンがv5系になった

大きな変更点は以下のような点です。

  • package-lock.json
    • npm install時に、依存ライブラリを固定するためのファイルが自動で生成されます
    • yarnっぽい感じ
  • npm installすると、デフォルトで–saveオプション動作
    • –saveを付けなくても、dependenciesに書き込まれるようになりました。
    • dependenciesに入れたくない場合は、--no-saveオプションを指定します
  • npm installが速くなった

lockファイルの導入/–saveオプション不要など、依存パッケージを厳密に管理する方向への変化といった感じでしょうか。

これはいいですね!!

Npm v5については、↓の記事がとても分かりやすかったです。
http://yosuke-furukawa.hatenablog.com/entry/2017/05/30/090602

async/await対応

一応、v7.6からは--harmony-async-awaitオプションなしでasync/await使えるようになっていました。
ですが、このバージョンがデフォルトでasync/awaitが使える最初のLTS版です。

こんな感じのコードが、そのまま実行できます。

function wait(delay) {returnnew Promise(resolve => setTimeout(resolve, delay));
}

async function main() {
    console.log("start");
    for (var i=0; i<10; i++) {
        await wait(1000);
        console.log("next");
    }}

main();

TypeScriptやBabelなどを使わなくても、ここまで書けるようになりました。
今後、素のJavaScriptを書く場合でも、async/awaitを使える機会が増えそうですね。

util.promisify

utilモジュールにpromisifyという関数が追加されました。

Node.jsでよく用いられるコールバック関数形式での非同期処理を、Promise形式の関数に変換できるものです。

  • 最後の引数でコールバック関数を受け付ける
  • ↑のコールバック関数は、第一引数でエラー、第二引数で関数の実行結果を返す

util.promisifyについては↓が参考になります。
http://yosuke-furukawa.hatenablog.com/entry/2017/05/10/101752

// 普通のコールバックを使った書き方
fs.readFile("./test.txt", "utf-8", (err, data) => {
    console.log(data);
});

// promisifyを使ってPromise形式に変換すれば、async/awaitで呼び出せる
async function main() {const readFile = util.promisify(fs.readFile);

    var data = await readFile("./test.txt", "utf-8");
    console.log(data);
}
main();

これは、かなり便利!!

ただ、@types/nodeの型定義ファイルには、この辺の定義が追加されていません。
TypeScriptで使う場合は、しばらくの間はanyにして使う感じかな。

一応、↓にIssues上がってました。そのうち対応されるといいなぁ。。。
https://github.com/DefinitelyTyped/DefinitelyTyped/issues/16860

FontAwesome.WPFを使ってみた

$
0
0

Web系の開発でアイコン表示などによく使われているFontAwesomeというものがあります。
サイト上でよく使われるような様々なアイコンを、Webフォントとして利用できるようにしたものです。
Font Awesome, the iconic font and CSS toolkit

これをWPFやUWPなどから使えるようにした、FontAwesome.WPFというライブラリを使ってみました。 github.com

インストー

Nugetパッケージの管理メニューから、「FontAwesome.WPF」で検索して以下の項目をインストールします。
f:id:minami_SC:20170802082941p:plain

Nugetのコンソールからは、↓のコマンドでインストールできます。

Install-Package FontAwesome.WPF

使い方

主な使い方はこんな感じ。
簡単にいろんなアイコン表示ができます。これは便利!!

MainWindow.xaml

<Window x:Class="FontAwesomeWpfTest.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"xmlns:local="clr-namespace:FontAwesomeWpfTest"xmlns:fa="http://schemas.fontawesome.io/icons/"mc:Ignorable="d"Title="MainWindow"Height="350"Width="525"><Window.Resources><FontFamily x:Key="FontAwesome">pack://application:,,,/FontAwesome.WPF;component/#FontAwesome</FontFamily></Window.Resources><Grid><WrapPanel ItemWidth="32"ItemHeight="32"><!-- ImageAwesomeコントロールで表示 --><fa:ImageAwesome Icon="Desktop" /><!-- 色を変えてみる --><fa:ImageAwesome Icon="Flag"Foreground="Red"/><!-- Awesome.Contetnt添付プロパティでアイコン設定 --><Button fa:Awesome.Content="Flag"FontFamily="{StaticResource FontAwesome}"/><!-- コードビハインドから設定する場合 --><Image x:Name="image"/><!-- アニメーションで回転を行う --><fa:ImageAwesome Icon="Spinner"Spin="True"SpinDuration="10" /><!-- 回転角度などを指定 --><fa:ImageAwesome Icon="Spinner"FlipOrientation="Horizontal"Rotation="60" /><!-- 複数のアイコンを組み合わせて表示 --><Grid><fa:ImageAwesome Icon="Camera"VerticalAlignment="Center"HorizontalAlignment="Center"Width="24"Height="24" /><fa:ImageAwesome Icon="Ban"Foreground="Red"Opacity="0.7"/></Grid></WrapPanel></Grid></Window>

MainWindow.xaml.cs

/// <summary>/// MainWindow.xaml の相互作用ロジック/// </summary>publicpartialclass MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            this.image.Source = ImageAwesome.CreateImageSource(FontAwesomeIcon.Flag, Brushes.Black);
        }
    }

f:id:minami_SC:20170802082954p:plain

チートシート

一応、XAMLエディタ上でコード補間出るので、アイコンの名前はある程度探しやすいです。
f:id:minami_SC:20170802083052p:plain

でも、やっぱどんなアイコンがあるのか、パッと一覧で見たいということはよくあります。 そんな時は、↓のチートシートを見ればよいかな、、と。
http://fontawesome.io/cheatsheet/

↓ジャンル別
http://fontawesome.io/icons/


Electron 1.7.5 + TypeScript 2.5.2のサンプル

$
0
0

最近あまりElectronいじってなかったのですが、
気が付いたらElectron 1.7系のstable版となるv1.7.5がリリースされてました。

てことで、以前書いたElectron+TypeScriptのサンプルコードを最新バージョンに対応させておきました。

Electron/TypeScriptそれぞれを以下のバージョンに更新してます。

  • Electron 1.7.5
  • TypeScript 2.5.2

Electronの型定義ファイル

Electronのパッケージ内に、TypeScript向け型定義ファイルが同梱されるようになりました。
V1.6.x系の途中から型定義ファイルが含まれるようになってたみたいです。

↓のようにelectronのパッケージ内に.d.tsファイルが含まれるようになってます。
f:id:minami_SC:20170908003051p:plain

ってことで、もう@types/electronをnpmから取得せずとも、TypeScriptでバッチリ使えるようになっています。
だいぶ便利になりましたね!!

TypeScript2.2.x系以降で使うために

TypeScript 2.2.1以降で、require/importなどが含まれるコードをトランスパイルすると、
以下のようなコードがトランスパイル結果の先頭に付与されるようになってます。

Object.defineProperty(exports, "__esModule", { value: true});

(CommonJSなどを指定してトランスパイルした場合)

このコードは、実行環境がNode.jsなどでrequireが使える環境であれば問題なく実行できます。
しかし、Electronはrequireでのモジュール読み込みはできますが、exportsなどの変数が用意されていません。
そのためUncaught ReferenceError: exports is not definedというようなエラーが出てしまいます。

そんな時は、html側に以下のようなコードを足すとこのエラーを回避できます。

<!DOCTYPE html><html><head><metacharset="UTF-8"><title>Hello World!</title><!-- ↓このコードを、index.jsを読み込む前の部分に足す --><script>window.exports = module.exports</script><scriptsrc="index.js"></script></head><body><h1>Hello World!</h1><hr/><buttononclick="hello()">Show Message</button></body></html>

ちょっとダーティなハックって感じですが、お手軽な対処になると思います。

根本的な対処

根本的に対処するなら、html側からスクリプト読む際は以下のようにrequire関数を通すようにします。

<!DOCTYPE html><html><head><metacharset="UTF-8"><title>Hello World!</title><script>window.exports = module.exports</script></head><body><h1>Hello World!</h1><hr/><buttonid="btnShowHello">Show Message</button><script>// You can also require other files to run in this process      require('./index.js')
</script></body></html>

requireした先のコンテキストではexportsなどが定義されていて、CommonJSなコードが普通に解釈できるようです。
GitHubにあげたサンプルコードでは、こちらの方法で対処しました。

ちなみに、electronの公式サンプルコードもこの方法scriptを読み込むようになっています。
https://github.com/electron/electron-quick-start/blob/master/index.html
ということで、<script src="index.js"></script>と書かずにscriptタグ内にrequire関数を書いて読む方がよいかもしれません。

その他

electron v1.5系ではWebComponents、v1.6系でCSS Grid Layoutが使えるようになっています。
(v1.5系はpre-release版だけでstableのリリースがなかったため、実質的には両方ともv1.6系から使えるようになった、という感じかも)

以前↓で書いたようなことが、普通に使えるようになっています。 sourcechord.hatenablog.comsourcechord.hatenablog.com

この辺は、また日を改めてサンプルコードを書いてみようと思います。

monaco-editor + electronのサンプルコードを更新しました

$
0
0

以前、monaco-editorなどをelectron環境とかで使ってサンプルコードを書きました。

sourcechord.hatenablog.comsourcechord.hatenablog.com

だいぶ時間がたって、使っているライブラリ類のバージョンが古くなっていたので、このサンプルのライブラリ類を更新しました。

それぞれ、以下のバージョンを使うように更新しています。

  • monaco-editor v0.10.0
  • electron v1.7.5
  • typescript v2.5.2

monaco-editorのモジュール読み込み方法の変更

monaco-editorでは、このライブラリのモジュール読み込みには、ライブラリ内に含まれるloader.jsという関数を使用することになっています。
このloader.jsはAMD形式のモジュールローダーとなっており、このファイルを読み込むとグローバルのrequire関数がAMD形式のもので上書きされます。

このままだと、electron環境で使えるCommonJS形式のrequire関数が使えなくなるので、とても都合が悪いです。

monaco-editorの公式サンプルコードを見てみると、
electron環境で使う場合には、以下のようにloader.jsのrequire関数をamdRequireという別名にして扱うようにしていました。
https://github.com/Microsoft/monaco-editor-samples/blob/master/sample-electron/index.html

ということで、このコードを参考に以下のように書いてみました。

<script>// loader.jsを読み込むと、require関数がloader.js内のAMD方式のもので上書きされてしまう。// 通常のCommonJSスタイルのrequireが使えるように、別変数に退避しておくvar nodeRequire = global.require;</script><scriptsrc="node_modules/monaco-editor/min/vs/loader.js"></script><script>// loader.jsのrequire関数はamdRequireという名前にしておき、// 退避しておいた、CommonJSスタイルのrequire関数を元に戻すvar amdRequire = global.require;      global.require = nodeRequire;

実行結果

monaco-editorのバージョンを上げてみたら、こんな風にスクロールバー横にコードが縮小表示されるようになってました。
最近のVSCodeと同じ表示です。

f:id:minami_SC:20170909104103p:plain

monaco-editorも色々と便利になってますね。

electronでCSS Grid Layoutを使うサンプル

$
0
0

Electron v1.7系では、内部で使用しているChromiumが58系に更新されたため、CSS Grid Layout Module Level1が使えます。
https://caniuse.com/#feat=css-grid

ということで、以前↓で書いたサンプルを、最新のElectron v1.7.5環境用に書き換えました。

コードは以下のリポジトリにあげています。
https://github.com/sourcechord/electron-gridlayout-sample

electron v1.7系以降の環境では、↓のような拡張フラグの指定をしなくても普通にCSS Grid Layoutが使えます。

App.commandLine.appendSwitch("--enable-experimental-web-platform-features");

CSS Grid Layoutに対応したブラウザも増えてきましたし、各種入門記事もWeb上にだいぶ増えてきました。
これからは、CSS Grid Layoutを使う機会も徐々に増えそうですね!!

f:id:minami_SC:20170910140911p:plain

electronでWeb Componentsを使うサンプル

$
0
0

electron v1.5以降のバージョンでは、WebComponentsが普通に使えるようになりました。 (v1.5系はpre-release版だけでstableのリリースがなかったため、実質的にはv1.6系以降のバージョンですね。)

ということで、以前↓で書いた記事の内容をelectronで動かすサンプルを作りました。

WebComponentsの詳細については、最初のリンクで書いた記事で説明しています。
ということで、ここではコンポーネントの作り方の詳細な説明は端折り、サンプルを見ていきたいと思います。

サンプル

サンプルコードは以下のリポジトリに上げています。
https://github.com/sourcechord/electron-webcomponents-sample

実行すると、こんな風にストップウォッチのコンポーネントが二つ表示されます。
f:id:minami_SC:20170910173155p:plain

プロジェクト構造

f:id:minami_SC:20170910173208p:plain
stopwatch-elementフォルダを作り、このフォルダの中でストップウォッチのコンポーネント定義を行っています。

コンポーネントの使い方

コンポーネントを定義したhtmlファイルを<link>タグで読み込むと、そのコンポーネントが利用できるようになります。
簡単ですね!!

index.html

<!DOCTYPE html><html><head><metacharset="UTF-8"><title>Web Componentsのサンプル</title><linkrel="import"href="stopwatch-element/stopwatch-element.html"></head><body><h1>Web Componentsのサンプル</h1><stopwatch-element></stopwatch-element><hr /><stopwatch-element></stopwatch-element><hr /></body></html>

JavaScriptで使えるモダンなDataGrid系ライブラリを調べてみた

$
0
0

WebアプリのUIを作っていると、表形式でデータ表示をしたいときとかがあるかと思います。
特に業務系アプリとかだったら、この手のDataGrid系のコントロールが必要になる場面って多いですよね。
JavaScriptやHTMLでUIを作る場合、DOM要素のtableタグでもテーブル表示はできますが、tableタグだと、テーブルのヘッダを固定できないとか、カラム幅の調整が面倒とか、なかなか使い勝手が悪いです。

そんな時には、何かしらのライブラリを併用することになります。
ちょっと前までだと、この手のテーブル表示にはjQuery依存なライブラリを使うことが多かったかと思います。

ですが、個人的にはjQuery系のライブラリって、あんまいい印象ないんですよね。
ちょっと入り組んだことをすると意味不明な挙動に悩まされたり、何かと不満がたまることが多かった気がします。(使い方の問題なだけの気もしますが。。。)
近年のjQuery離れの風潮も考えると、できれば極力jQueryに依存したライブラリは使いたくないです。

ということで、今回はjQueryに依存しないライブラリを中心に色々探してみました。 また、AngularやReact、Vue.jsなどのような、特定のフレームワークに依存しないものを見繕っています。   で、個人的に「これはよさそう!!」と思った、以下の3つのライブラリを試してみました。

  • handsontable
  • ag-grid
  • canvas-datagrid

handsontable

無償のCommunityEditionと有償のPro版があるようです。 有償版は要素のフィルタリングやCSVエクスポートなどの付加機能が付いた高機能版となっているみたい。

こんな感じのテーブル表示になります。
f:id:minami_SC:20170913004820p:plain

ag-grid

こっちも割と定番どころのライブラリっぽいですね。
handsontableと同じように、このライブラリも無償版と有償版があります。

ag-gridのUIはこんな感じ。
f:id:minami_SC:20170913004831p:plain

Web Components対応

このライブラリでは、↓のnpmモジュールを追加でインストールすることで、WebComponentsとして読み込むことができます。(Chromeなどの対応ブラウザの場合)

<!DOCTYPE html><html><head><metacharset="UTF-8"><title>ag-gridのサンプル(WebComponents版)</title><scriptsrc="../../node_modules/ag-grid/dist/ag-grid.min.js"></script><linkrel="import"href="../../node_modules/ag-grid-webcomponent/ag-grid.html"></head><body><h1>ag-gridのサンプル(WebComponents版)</h1><ag-gridid="grid"style="height: 115px; width: 500px;"class="ag-fresh"             enable-col-resize             enable-sorting             enable-filter></ag-grid><script>// You can also require other files to run in this process        require('./index.js')
</script></body></html>

canvas-datagrid

DOMとは違うのだよ、DOMとは!!

今回色々調べてて一番ビックリしたのがコレ!!
ライブラリ名が体を表していますが、tableタグなどのDOM要素を使うのではなく、canvas上にテーブルを描画しています。
テーブル表示やセルの選択状態スクロールバーなどなどをすべてcanvas上に書くという、なんともイカレたイカしたライブラリです。

↓よくまぁここまで作りこんだなぁ、という感じ。ちゃんとコンテキストメニューも出たりします。 f:id:minami_SC:20170913004845p:plain

こういう手法なんで、tableタグなどのブラウザごとの微妙な挙動の違いとかには遭遇しにくいのかな、、、と思ったり。
ただし、canvas上への独自描画なので、他のDOM要素なUI部品とは若干ルック&フィールが異なる点を少し感じるかもしれません。

でも、DOM要素やcssなどのブラウザごとの微妙な挙動の違いに悩まされるくらいなら、いっそこういうアプローチも面白いのかもしれません。

現状はpre-release版とのことなんで、実際のアプリ開発で使うのはまだやめておいた方がよいかも。
とはいえ、今後が楽しみなライブラリです。

Web Components対応

このライブラリ、WebComponents形式での利用に対応しているようです。
WebComponentsに対応したブラウザだったら、以下のような形式で利用できます。

<!DOCTYPE html><html><head><metacharset="UTF-8"><title>canvas-datagridのサンプル(WebComponents版)</title><scriptsrc="../../node_modules/canvas-datagrid/dist/canvas-datagrid.js"></script></head><body><h1>canvas-datagridのサンプル(WebComponents版)</h1><canvas-datagridstyle="--cdg-cell-color: darkblue;">[
            {"col1": "row 1 column 1", "col2": "row 1 column 2", "col3": "row 1 column 3"},
            {"col1": "row 2 column 1", "col2": "row 2 column 2", "col3": "row 2 column 3"}
        ]</canvas-datagrid></body></html>

これは便利!!

サンプル

ag-gridとcanvas-datagridは、WebComponentsとしても利用できるようになっています。
ということで今回は、WebComponentsが利用できるelectron上でこの辺のライブラリを試してみました。
サンプルは↓に置いています。
(ほぼ公式ページのサンプルコードをそのまま流用しただけのものですが・・・)

f:id:minami_SC:20170913004857p:plain

Visual Studio 2017 Update3でC#7.1を使ってみた

$
0
0

リリースされてから随分経ちましたが、VS2017 Update3に更新しました。 Update3からは、C#7.1の機能が使えるようになってます。

自分はまだあまりC#7の機能を使いこなせてないですが、
7.1で色々と便利な機能も追加されているので少し使ってみました。

C#7.1の有効化

VS2017をUpdate3に更新しても、デフォルトの状態ではC#7.1は有効になっていません。
プロジェクトの設定で、以下の箇所を「C#の最新のマイナーバージョン(最新)」に変更する必要があります。

f:id:minami_SC:20170914231906p:plain

Debug/Releaseそれぞれのビルド構成で設定が必要なので注意しましょう。

サンプル

asyncなMain関数

Main関数をasyncにできるようになりました。
asyncなAPIをちょっとテストする際とかに便利になりそうです。

static async Task Main(string[] args)
        {
            Console.WriteLine("Hello World!");
            await Task.Delay(1000);
            Console.WriteLine("1秒経過");
            await Task.Delay(5000);
            Console.WriteLine("5秒経過");
        }

f:id:minami_SC:20170914231919p:plain

タプルの改善

タプルはC#7から使えるようになりました。 C#7.1ではタプルの使い勝手が少し改善されてます。

↓のようなコードで、タプルの変数personの各要素に、Item1/Item2などの名前ではなくタプル定義時の名前でアクセスできるようになってます。

            var name = "ほげほげ";
            var age = 25;

            var person = (name, age);
            Console.WriteLine($"{person.name}さん {person.age}才");

.NET Framework 4.7以降の環境では、このコードがそのまま実行できます。 4.6.x以前のバージョンでは、System.ValueTuppleパッケージをNugetからインストールする必要があるので注意。

ImageSharp v1.0.0beta1がリリースされたので使ってみた

$
0
0

.Netの様々な環境で動作する、ImageSharpという画像処理ライブラリのv1.0.0beta1がリリースされました

github.com

以前.NET blogの↓の記事などでも紹介されてたライブラリです。
https://blogs.msdn.microsoft.com/dotnet/2017/01/19/net-core-image-processing/

他のクロスプラットフォームな画像処理ライブラリ(ImageMagickやSkiaなど)には依存せず、すべてC#で実装されてます。
また、.NET standardなライブラリになっているので、
通常の.NET Framework環境だけでなく、UWPなどの環境や.NET Core環境、Xamarin環境などでも使えるようです。

ImageSharpで提供してる機能などは、↓のページにまとまっています。
https://github.com/SixLabors/ImageSharp/blob/master/features.md

画像の読み書きだけでなく、色々な画像処理の定番アルゴリズム類や図形描画などの機能も実装されてます。

個人的には、.NET環境での画像処理ライブラリの大本命になるんじゃないかな、、と思ってて、 リリースされるのを首を長くして待ってました。
(といっても、今回はβ版のリリースなので、正式なリリースはまだまだ先でしょうが・・・)

準備

インストール

Nugetで「ImageSharp」で検索し、↓のパッケージをインストールします。
f:id:minami_SC:20170916111408p:plain
まだβ版なので、「プレリリースを含める」にチェックを入れないと検索結果に出てきません。注意しましょう。

コンソールからインストールする場合は以下のコマンド。

Install-Package SixLabors.ImageSharp
名前空間の設定

ImageSharpを利用するコードに、以下のusing文を追加しておきましょう。

using SixLabors.ImageSharp;

使ってみる

まだドキュメント類はあまり整備されてないんですが、適当に使ってみました。
まずは画像を読み込んでから、リサイズ&モノクロ化をして結果をファイルに保存してみます。

f:id:minami_SC:20170916111448j:plainf:id:minami_SC:20170916111455j:plain
元画像と結果画像

staticvoid Main(string[] args)
        {
            // 画像の読み込みusing (Image<Rgba32> image = Image.Load("Images/source.jpg"))
            {
                // 読み込んだ画像を編集(Mutateメソッドを呼び出すと、画像を編集できるようになる)
                image.Mutate(x =>
                    {
                        // リサイズ&グレースケール化を行う
                        x.Resize(image.Width / 2, image.Height / 2)
                         .Grayscale();
                    });

                // 結果画像を保存
                image.Save("result.jpg");
            }
        }

読み込んだ画像データはIDisposableなオブジェクトになっているので、using文でキッチリとリソース管理できます。
また各種の画像処理はメソッドチェーン形式で繋いで書けます。
イイ感じですね!!

ちなみに画像データに編集を加える場合には、Mutateメソッドを呼び出し、Mutateメソッドの引数として渡すラムダ式/関数の中で処理する必要があるので注意が必要です。

図形の描画

DrawLines、DrawTextなどといった、図形や文字などを描画するためのAPIが用意されています。

先ほどの画像データに、DrawLines関数で直線を描画してみます。

ImageSharp.Drawingのインストール

この手の図形描画系のメソッドは、ImageSharp.Drawingという別パッケージに分割されています。

Nugetで「ImageSharp.Drawing」を検索し、以下のパッケージをインストールします。
f:id:minami_SC:20170916111714p:plain

直線の描画

DrawLinesという関数で、頂点リストで定義された複数の直線をまとめて描画できます。

// 画像の読み込みusing (Image<Rgba32> image = Image.Load("Images/source.jpg"))
            {
                // 読み込んだ画像を編集(Mutateメソッドを呼び出すと、画像を編集できるようになる)
                image.Mutate(x =>
                    {
                        // リサイズ&グレースケール化を行う
                        x.Resize(image.Width / 2, image.Height / 2)
                         .Grayscale();

                        // 頂点のリストを定義
                        var points = new SixLabors.Primitives.PointF[] {
                            new Vector2(10, 10),
                            new Vector2(480, 50),
                            new Vector2(540, 420),
                        };
                        // 頂点リストで定義された複数の直線を描画
                        x.DrawLines(new Rgba32(255, 0, 0, 127), 5, points);
                    });

                // 結果画像を保存
                image.Save("result.jpg");
            }

f:id:minami_SC:20170916111701j:plain

ピクセル操作

画像を読み込んだImageオブジェクトのインデクサを通して、ピクセルデータの編集ができます。
以下の例では、x, y座標に応じて色を変えて、グラデーションを描画しています。

staticvoid Main(string[] args)
        {
            // 640×480pxの空の画像を作成using (var image = new Image<Rgba32>(640, 480))
            {
                for (var y = 0; y < image.Height; y++)
                {
                    for (var x = 0; x < image.Width; x++)
                    {
                        // x, y座標に応じて色を変えて、グラデーションを描画float r = (float)x / image.Width;
                        float g = (float)y / image.Height;
                        float b = 0;
                        image[x, y] = new Rgba32(r, g, b);
                    }
                }

                // 結果画像を保存
                image.Save("result.jpg");
            }
        }

f:id:minami_SC:20170916111829j:plain

ちなみに以下の公式ブログなどをみると、ピクセルデータのアクセス用APIとしては、今後System.MemoryのSpanを用いたAPIを用意するっぽい。
https://sixlabors.com/blog/announcing-imagesharp-beta-1/

この辺、まだ.net standardなライブラリでは使えないので、今後対応するってことみたいですね。


WPFでImageSharpを使ってみる

$
0
0

今回はImageSharpで編集した画像をWPFのUIで表示してみます。

ImageSharpでは、Imageというクラスで画像データを扱っています。(←WPFにも同名のImageコントロールというクラスがありますが別物です。)

そのままではWPFのUIに表示できないので、WPFで扱えるようBitmapSourceなどのオブジェクトに変換して表示してみます。

名前空間の注意

コードビハインドなど、WPFの各種名前空間が参照されているコードでは、WPFとImageSharpの間でImageクラスなどの名前がぶつかってしまいます。そんな時は、以下のように名前空間まで含めて書いてクラス名の衝突を回避します。

using (Image<Bgr24> image = SixLabors.ImageSharp.Image.Load<Bgr24>("Images/source.jpg"))

ImageSharpの画像から、WPF用の画像データへ変換

WPFでは、画像データをウィンドウ上のImageコントロールで表示するためには、ImageSource/BitmapSource派生の画像データに変換しなければなりません。

ということで、ImageSharpで画像を読み込みモノクロ化などの変換をした結果を、WPF用の画像に変換して表示してみます。

MainWindow.xaml

<Window x:Class="ImageSharpWpfTest.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"xmlns:local="clr-namespace:ImageSharpWpfTest"mc:Ignorable="d"Title="MainWindow"Height="350"Width="525"><Grid><Image x:Name="image"Margin="5"/></Grid></Window>

MainWindow.xaml.cs

/// <summary>/// MainWindow.xaml の相互作用ロジック/// </summary>publicpartialclass MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            // ImageSharpで画像の読み込みusing (Image<Bgr24> image = SixLabors.ImageSharp.Image.Load<Bgr24>("Images/source.jpg"))
            {
                // 読み込んだ画像を編集(Mutateメソッドを呼び出すと、画像を編集できるようになる)
                image.Mutate(x =>
                {
                    // グレースケールに変換
                    x.Grayscale();
                });

                // ImageShaprの画像オブジェクトから、ピクセルデータのbyte配列を取得する。
                var pixels = image.SavePixelData();
                // byte列からBitmapSourceオブジェクトを作成
                var bmp = BitmapSource.Create(image.Width, image.Height, 96, 96, PixelFormats.Bgr24, null, pixels, image.Width * 3);

                //// WriteableBitmapに変換する場合はこうする//var wb = new WriteableBitmap(image.Width, image.Height, 96, 96, PixelFormats.Bgr24, null);//wb.WritePixels(new Int32Rect(0, 0, image.Width, image.Height), pixels, image.Width * 3, 0);// Imageコントロールに、画像を設定this.image.Source = bmp;
            }
        }
    }

f:id:minami_SC:20170917221239p:plain

とりあえず、こんな感じのコードでImageSharpで作った画像をWPFで表示できます。

Firefox56で追加されたCSS Grid DevToolsが便利!!

$
0
0

Firefox56から、開発者ツールのインスペクターに、CSS Grid Layout用のデバッグツールが追加されました。

Gridの分割位置を画面上に表示してくれます。
f:id:minami_SC:20171004224253p:plain

これは便利!!

WPFのGridコントロールで、ShowGridLines="True"にしたときのような表示ですね!!
f:id:minami_SC:20171004224319p:plain

grid-template-areasを使ってグリッドの書くエリアに名前を付けた場合、エリア名も表示することができます。

.wrapper{display: grid;
      width: 100%;
      height: 100%;
      grid-template-columns: 150px3fr 1fr;
      grid-template-rows: auto1fr auto;
      grid-template-areas: 
          "header header header""left  content right""footer footer footer";
      padding: 10px;
    }

f:id:minami_SC:20171004224308p:plain

CSS Grid Layoutを使った画面レイアウトでは、Firefoxの開発者ツールがとても役に立ちそうです。
こういう風にブラウザに標準で専用ツールが付いてくると、今後ますますCSS Grid Layoutの普及に拍車がかかりそうですね!!

Windows10 Fall Creators Updateに更新してみました

$
0
0

今回はWindowsUpdateにすぐ降ってきたので、更新アシスタントは使わずそのままWindowsUpdateで更新しました。

f:id:minami_SC:20171019003232p:plain

なんか、Edgeでタブたくさん開くと、今までよりも随分とモリモリとメモリを消費していくようになった気がします。
Chrome的なメモリは潤沢に使って速度上げる方向にシフトしたんかな・・・
この辺はしばらく使いながら様子を見ようと思います。

Edgeの更新に関しては、お気に入りページをタスクバーにピン留めできるようになったのが地味に便利な点ですね。
f:id:minami_SC:20171019003243p:plain

あと、Mixed Reality ポータルを起動して要件のチェックをしてみましたが、PCスペック的に無理でした・・・orz
自分のPCはSandy Bridge世代でオンボードグラフィックなので、わかっちゃいたけど、やっぱもう厳しいですね(汗

フォトアプリやストア、計算機など、一部のアプリでFluent DesignのAcrylicな効果が適用されるようになりました。
f:id:minami_SC:20171019003528p:plain:w250
ただ、現状はこういうアクリル系デザインと、今までのデザインとか混在していて、まだチグハグな感じです。
Fluent Designが本格的に適用されてくるのは、次のRS4を気長に待ちましょう。

あと、なんか更新したら、こんな感じの意味不明なアプリが大量に増殖してました。。。なんだこれ・・・
f:id:minami_SC:20171019003545p:plain:w200

どうせそのうち更新で直るんかな、、、
とりあえず、ここもしばらく放置で様子見ようかと思います。

Windows10 Fall Creators UpdateのEdgeでCSS Grid Layoutが使えるようになりました!!

$
0
0

おぉ~!!

Edgeでも、-ms-のベンダープレフィックスが付いた昔の仕様ではなく、CSS Grid Layout Module Level1のグリッドレイアウトが使えるようになってます。

これで、現在の主要なブラウザは一通り対応した感じでしょうか。
https://caniuse.com/#feat=css-grid

f:id:minami_SC:20171019004558p:plain

<!DOCTYPE html><html><head><meta charset="UTF-8"><title>Holy Grail Layout</title><style type="text/css">
    * {
      box-sizing: border-box;
    }

    .wrapper {
      display: grid;
      width: 100%;
      height: 100%;
      grid-template-columns: 150px 3fr 1fr;
      grid-template-rows: auto 1fr auto;
      padding: 10px;
    }
    
    .box {
      background-color: #444;
      color: #fff;
      border-radius: 5px;
      border: 2px solid black;
      padding: 20px;
    }
    
    .header{
      /*↓grid-areaで書く場合はこんな感じ*/
      /*grid-area: 1/1/2/4;*/
      grid-row: 1;
      grid-column: 1 / span 3;
    }
    .left{
      /*grid-area: 2/1/3/2;*/
      grid-row: 2;
      grid-column: 1;
    }
    .content{
      overflow: auto;
      /*grid-area: 2/2/3/3;*/
      grid-row: 2;
      grid-column: 2;
    }
    .right{
      /*grid-area: 2/3/3/4;*/
      grid-row: 2;
      grid-column: 3;
    }
    .footer{
      /*grid-area: 3/1/4/4;*/
      grid-row: 3;
      grid-column: 1 / span 3;
    }
  </style></head><body><div class="wrapper"><div class="box header">header</div><div class="box left">left</div><div class="box content">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Obcaecati debitis nemo excepturi voluptatibus magnam fugit officia, ut, dicta, animi inventore quidem aliquam adipisci vitae perspiciatis id autem maiores asperiores dolores!</div><div class="box right">right</div><div class="box footer">footer</div></div></body></html>

ただ、なんだかんだで、IE11はまだ若干シェア残っているので、Webサイトで使う場合はその辺の対応は必要かもしれません。

IE11やWin10FCUより前のEdgeに対応する場合は、↓の記事などが参考になりそうです。 qiita.com

ChromeFirefoxは基本的に最新バージョンに更新されている環境が多いのでいいとして、 IE11やEdge15以前のバージョンも-ms-プレフィックスを使って、古い仕様のGrid Layoutを使うことである程度は対処できます。
ただ、古めのSafariはちょっと対処が難しいですね。
ここを妥協できれば、CSS Grid Layoutの利用を考えるのも結構アリな時代になってきたのかな、、、とか思います。

XAML Advent Calendar 2017を作りました

$
0
0

今年も技術系アドベントカレンダーの時期が近づいてきましたね。
Qiitaでも色々なカレンダーが作られ始めていたので、今年もXAMLアドベントカレンダーを作っておきました。

去年は12月になってからカレンダー作ったせいもあってか、あまり人は集まりませんでした。
一人アドベントカレンダーのノリで書ききろうかとも思ったけど、さすがにネタが続かず結局力尽きてしまいました・・・

今年はFluent Design SystemとかXAML Standardなど、XAMLに関する発表もいろいろあったし、たくさん集まるといいなぁ。

Viewing all 153 articles
Browse latest View live