2017年12月26日火曜日

2017年12月23日土曜日

Visual Studio Code ソースコード 拡大/縮小機能の有効化


Visual Studio Code にはエディタの拡大率を Ctrl キー + マウスホイールで拡大/縮小する機能があります。デフォルトでは無効化されているので、下記のように有効化します。

ファイル > 基本設定 > 設定

デフォルト:
"editor.mouseWheelZoom": false

変更後:
"editor.mouseWheelZoom": true



Visual Studio Code では意図的に無効化しているようです。TrackPad や TouchPad を利用する際に、この機能により意図せずソースコードが拡大/縮小されてしまうためだそうです。
Feature request: Allow zooming with ctrl+mousewheel combination #6978
https://github.com/Microsoft/vscode/issues/6978

2017年11月30日木曜日

flutter 開発メモ

flutter 開発に関するメモです。基本的な内容がほとんどです。

アプリケーションテンプレートの生成
flutter create watashi_app

アプリケーションの実行
アプリケーションのトップフォルダ(pubspec.yaml のあるフォルダ)で、次を実行
flutter run


2017年11月23日木曜日

WPF 添付イベント(Attached Event)実装例

添付イベントの実装例を紹介します。

MainWindow.xaml.cs
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
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;

namespace WpfApp3
{
    /// <summary>
    /// MainWindow.xaml の相互作用ロジック
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
        
        private void InputChangedHandler(object sender, RoutedEventArgs e)
        {
            Debug.WriteLine("InputChangedHanlder is called.");
        }
    }

    public static class EventHelper
    {
        public static readonly DependencyProperty IsEventRaisingProperty =
            DependencyProperty.RegisterAttached("IsEventRaising",
            typeof(bool),
            typeof(EventHelper),
            new FrameworkPropertyMetadata(false, new PropertyChangedCallback(OnIsEventRaisingChanged)));

        public static bool GetIsEventRaising(DependencyObject sender)
        {
            return (bool)sender.GetValue(IsEventRaisingProperty);
        }

        public static void SetIsEventRaising(DependencyObject sender, bool ier)
        {
            sender.SetValue(IsEventRaisingProperty, ier);
        }

        public static readonly RoutedEvent InputChangedEvent = EventManager.RegisterRoutedEvent(
            "InputChanged",
            RoutingStrategy.Bubble,
            typeof(RoutedEventHandler),
            typeof(EventHelper)
        );

        public static void AddInputChangedHandler(DependencyObject sender, RoutedEventHandler handler)
        {
            UIElement element = sender as UIElement;
            if (element != null)
            {
                element.AddHandler(InputChangedEvent, handler);
            }
        }

        public static void RemoveInputChangedHandler(DependencyObject sender, RoutedEventHandler handler)
        {
            UIElement element = sender as UIElement;
            if (element != null)
            {
                element.RemoveHandler(InputChangedEvent, handler);
            }
        }

        private static void OnIsEventRaisingChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            (sender as TextBox).TextChanged += (_s, _e) =>
            {
                (sender as TextBox).RaiseEvent(new RoutedEventArgs(InputChangedEvent));
            };
        }
    }
}

MainWindow.xaml
<Window
        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:WpfApp3"
        xmlns:sys="clr-namespace:System;assembly=mscorlib"
        xmlns:Custom="http://infragistics.com/DockManager" x:Class="WpfApp3.MainWindow"
        mc:Ignorable="d"
        Title="MainWindow X" Height="350" Width="525">
    <Grid>
        <TextBox local:EventHelper.IsEventRaising="True"
                 local:EventHelper.InputChanged="InputChangedHandler"
                             />
    </Grid>
</Window>

2017年11月20日月曜日

WPF ユーザーコントロールのプロパティにデータをバインド

ユーザーコントロールのプロパティに、他のユーザーコントロールのプロパティをバインドしてみます。

ターゲットプロパティ・・・値を設定するプロパティ
ソースプロパティ・・・値を取得してくるプロパティ

ターゲットプロパティは、依存関係プロパティ(Dependency Property)である必要があります。


実装例:
この例では、Slider コントロールの Value プロパティを、TextBox の Text プロパティにバインドしています。なお、TextBox の Text プロパティは依存関係プロパティ(Dependency Property)です。

<Slider x:Name="slider1"
        HorizontalAlignment="Left" 
        Margin="49,36,0,0" 
        VerticalAlignment="Top" 
        Width="257"
        />
<TextBox HorizontalAlignment="Left"
         Height="24" Margin="49,85,0,0" 
         TextWrapping="Wrap"
         VerticalAlignment="Top"
         Width="257"
         Text="{Binding ElementName=slider1, Path=Value}"/>

2017年11月19日日曜日

WPF Trigger 実装例

WPF Trigger の実装例です。

Button の Content の値に応じて Button の背景色を赤色に変更します。また、Button にマウスがホバーしている間、Button の文字色を白色に変更します。


<Window x:Class="TriggerDemo.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:TriggerDemo"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Button
            Content="button1"
            Height="30"
            Width="200">
            <Button.Resources>
                <Style TargetType="Button">
                    <Style.Triggers>
                        <!--Content が "button1" ならば-->
                        <Trigger Property="Content" Value="button1">
                            <!--背景色を赤色に変更-->
                            <Setter Property="Background" Value="Red"/>
                        </Trigger>
                        <!--Button 上にマウスがホバーしていたら-->
                        <Trigger Property="IsMouseOver" Value="True">
                            <!--前景色を白色に変更-->
                            <Setter Property="Foreground" Value="White"/>
                        </Trigger>
                    </Style.Triggers>
                </Style>
            </Button.Resources>
        </Button>
    </Grid>
</Window>


関連情報:

WPF DataTrigger 実装例
http://kainobi2.blogspot.jp/2017/05/wpf-datatrigger.html

2017年11月18日土曜日

WPF 添付プロパティ(Attached Property)の実装方法

WPF でクラスインスタンスを利用する際に、クラスに対して直接プロパティを追加できないが、任意のプロパティを追加して利用したい状況があるかと思います。そのような場合、添付プロパティ(Attached Property)を利用することができます。


MainWindow.xaml.cs

コードビハインドで「propa」と入力してスニペットを挿入します。その後、適宜名前やメタデータを変更していきます。

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    public static double GetRecord(DependencyObject obj)
    {
        return (double)obj.GetValue(RecordProperty);
    }

    public static void SetRecord(DependencyObject obj, double value)
    {
        obj.SetValue(RecordProperty, value);
    }

    // Using a DependencyProperty as the backing store for Record.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty RecordProperty =
        DependencyProperty.RegisterAttached("Record",
            typeof(double),
            typeof(MainWindow), 
            new FrameworkPropertyMetadata(0.0)
            );

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        var btn = sender as Button;
        Debug.WriteLine(btn.GetValue(RecordProperty));
    }
}



MainWindow.xaml

追加した Record 添付プロパティに、double 値を設定します。

<Window x:Class="AttachedPropertyDemo.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:AttachedPropertyDemo"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Button 
            Content="abc"
            Height="30"
            Width="200"
            local:MainWindow.Record="3.0"
            Click="Button_Click"/>
    </Grid>
</Window>

関連情報:
WPF 依存関係プロパティ
http://kainobi2.blogspot.jp/2016/11/wpf.html

2017年11月17日金曜日

WPF バインディング:Source の使い方

Binding オブジェクトの持つ、Source プロパティの利用方法の紹介です。Source プロパティを利用することで、Resources に登録されている任意のオブジェクトを参照することができます。

例えば、Resources に用意されている Int 型の値を、TextBox の Tooltip プロパティにバインドしてみます。

※ Int 型の値を利用するためには、mscorlib アセンブリの参照を追加しています。

<Window x:Class="WpfApp3.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:WpfApp3"
        mc:Ignorable="d"
        xmlns:sys="clr-namespace:System;assembly=mscorlib"
        Title="MainWindow X" Height="350" Width="525">
    <Grid>
        <Grid.Resources>
            <sys:Int32 x:Key="num1">123</sys:Int32>
        </Grid.Resources>

        <TextBox x:Name="textBox1"
                 Height="30"
                 Width="250"
                 Text="abc"
                 ToolTip="{Binding Source={StaticResource num1}}"/>
    </Grid>
</Window>

2017年11月11日土曜日

WPF バインディング:RelativeSource の使い方

Binding オブジェクトの持つ、RelativeSource プロパティの利用方法の紹介です。

バインディングを利用して、バインドするソースとして、バインドターゲットの UI 要素から相対位置に存在する UI 要素のプロパティを指定する時には、RelativeSource プロパティを利用することができます。

例えば、TextBox の Tooltip プロパティにバインドするバインドソースとして、TextBox の親(Grid)の親である Window の Title プロパティを利用することを考えてみます。

デザインタイムでは、UI 要素は下記の構造になっています。TextBox から、2 つ上位にある Window のプロパティを参照します。

Window
    - Grid
        - TextBox


TextBox.Tooltip プロパティには、RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window} として、RelativeSoure を利用し、Mode に FindAncestor、AncestorType に Window をそれぞれ指定しています。これで、TextBox のツールチップには「MainWindow X」という値が表示されるようになります。

<Window x:Class="WpfApp3.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:WpfApp3"
        mc:Ignorable="d"
        Title="MainWindow X" Height="350" Width="525">
    <Grid>

        <TextBox x:Name="textBox1"
                 Height="30"
                 Width="250"
                 Text="abc"
                 ToolTip="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}, Path=Title}"/>
    </Grid>
</Window>

2017年10月2日月曜日

ASP.NET Web API で JSON を取得する方法

Web API で JSON を取得する実装例です。

View:
<input type="button" id="apiButton" class="btn" value="Web Api Test" />

<script>
    function asyncCall() {
        var xhr = new XMLHttpRequest();
        xhr.onreadystatechange = function () {
            if ((xhr.readyState === 4) && (xhr.status === 200)) {
                var json = xhr.response;
                console.log(json);
            }
        }
        xhr.open("GET", "/api/values", true);
        xhr.send(null);
    }

    var button1 = document.getElementById("apiButton");
    button1.addEventListener("click", asyncCall, false);
</script>

Controller:
public class Item
{
    public int Id { get; set; }

    public string Name { get; set; }

    public DateTime RegisteredOn { get; set; }

    public int CategoryId { get; set; }
}


public class ValuesController : ApiController
{
    // GET api/values
    public IEnumerable<Item> Get()
    {
        List<Item> items = new List<Item>();
        items.Add(new Item { Id = 1, Name = "Toshihiko", CategoryId = 1, RegisteredOn = DateTime.Today });
        items.Add(new Item { Id = 2, Name = "Takashi", CategoryId = 1, RegisteredOn = DateTime.Today });
        return items;
    }
}

2017年9月20日水曜日

Angular メモ

Angular アプリケーションプログラミング を読み、要点をメモしています。本文のコピーにならないように、自分の言葉に置き換えて記載しています。


2 章 Angular の基本
2.1 Angular を利用するための準備

2.1.1 Angular アプリケーションの基本構造

npm start コマンド:
Angular 同梱の lite-server が実行されます。この時、TypeScript が JavaScript にトランスパイルされます。
→ 2.3.1 で詳細説明。

xxx.js.map:
ソースマップファイルという。ts ファイルと js ファイルを紐付けています。デバッグ時に ts ファイルでデバッグ実行することができます。

2.2.1 モジュールについて

NgModule:
モジュール定義のためのモジュール

BrowserModule:
アプリケーションをブラウザで実行するためのモジュール

Angular モジュール:
オブジェクトをまとめるための入れ物という概念です。定義されているクラスの中は空でも動作します。(e.g. AppModule)

Angular モジュール = デコレーター + クラス
デコレーターでクラスの構成情報を設定します。


2.2.2 コンポーネント

app.component.ts 一部抜粋
@Component({
  selector: 'my-app',
  template: `<h1>Hello {{name}}</h1>`,
})

→ selector で指定されている要素(my-app)に、template で設定されているテンプレートを適用する、という意味です。変数 name の前後を囲っている {{...}} は Interpolation という構文で、変数を受け取る際の記述方法です。


2.2.3 スタートアップ
main.ts:
アプリケーション起動のための情報を設定しています。

main.ts
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';
platformBrowserDynamic().bootstrapModule(AppModule);
→ app.module から AppModule をインポートし、bootstrapModule メソッドで起動しています。


2.3.1 package.json
アプリケーションの情報、及びアプリケーションで利用するライブラリの情報をまとめています。

scripts コマンドには npm のサブコマンドを定義しています。
{
  "name": "angular-quickstart",
  ...
  "scripts": {
    ...
    "start": "concurrently \"npm run build:watch\" \"npm run serve\"",
    ...
  },

→ npm start と入力すると TypeScript とトランスパイル、lite-server の実行及びアプリケーションのロードが行われますが、実際にはこの package.json のショートカット経由でこれら処理が呼び出されます。


3 データバインディング
3.2 Interpolation(補間)構文
{{...}} 式の内部では、グローバルオブジェクトを参照することができません。
グローバルオブジェクトは、window、document など。

3.3 プロパティバインディング
テンプレート内の HTML 要素のプロパティと、コンポーネントのプロパティ値を紐付けます。ここでは、テンプレートの a タグの href プロパティと、コンポーネントの url プロパティの値を紐付けています。

import { Component } from '@angular/core';

@Component({
  selector: 'my-app',
  template: `<a [href]="url">go to Yahoo!</a>`,//プロパティバインディング
})
export class AppComponent 
{
  url = "http://www.yahoo.co.jp";
}

→ 出力結果は <a href="http://www.yahoo.co.jp">go to Yahoo!</a> になります。


3.5 イベントバインディング
3.5.1 イベントバインディングの基本

テンプレート内にハンドルするイベントと、イベントに対応するメソッドを紐付けます。ここでは click イベント発生時に myClick() メソッドが呼びされます。

import { Component } from '@angular/core';

@Component({
  selector: 'my-app',
  template: `<input type="button" [value]="myText" (click)="myClick()"/>`,//イベントハンドリング
})
export class AppComponent 
{
  myText = "クリック前";
  myClick() {
    this.myText = "クリック後";
  }
}

3.5.2 イベント情報の取得

JavaScript では func(evt) の形式でイベント引数を参照することができますが、Angular では $event という表記になります。

import { Component } from '@angular/core';

@Component({
  selector: 'my-app',
  template: `<input type="button" [value]="myText" (click)="myClick($event)"/>`,//イベント引数
})
export class AppComponent 
{
  myText = "クリック前";
  myClick(e: MouseEvent) {
    this.myText = "クリック後";
    console.log(e.target);
  }
}

実行結果:


















3.5.3 テンプレート参照変数

テンプレート内の要素への参照ができる仕組みです。下記では、input 要素を myInput として参照し、myInput の value プロパティを log メソッドの引数として渡しています。

@Component({
  selector: 'my-app',
  template: `<input #myInput type="text" (input)="log(myInput.value)"/>`,//テンプレート参照変数
})
export class AppComponent 
{
  log(myInput: string) {
    console.log(myInput);
  }
}


input 要素(myInput) に値を入力していくと、input イベントに紐づく log メソッドが呼び出され、コンソールに input 要素の value が出力されています。























なお、テンプレート参照変数は、テンプレート内の別の要素からも参照することができます。input イベントが発生したタイミングで、label 要素に入力文字列が変化していきます。

import { Component } from '@angular/core';

@Component({
  selector: 'my-app',
  template: `
    <input #myInput type="text" (input)="0"/>
    <label>「{{myInput.value}}」が入力されました。</label>
    `,
})
export class AppComponent 
{
  
}

3.5.4 キーイベントのフィルタリング(keyup.enter イベント)

Angular では Enter キーを押下したタイミングでイベントを処理するというコモンシナリオに対応する keyup.enter イベントを用意してくれています。下記例では、input 要素に値を入力し、Enter を押下したタイミングでコンソールに入力値を出力しています。

import { Component } from '@angular/core';

@Component({
  selector: 'my-app',
  template: `
    <input #myInput type="text" (keyup.enter)="log($event)"/>
    `,
})
export class AppComponent 
{
  log(e: MouseEvent){
    var target: HTMLTextAreaElement = <HTMLTextAreaElement>e.target;
    console.log(target.value);
  }
}

3.6 双方向バインディング

コンポーネントの持つプロパティと UI 要素と紐付け、コンポーネント側からの変更、もしくは UI 上での変更を受け取り、ビュー ↔ コンポーネントの間で値を同期する機能です。双方向バインディングは他の開発プラットフォーム(例えば、WPF など .NET Framework)にもある、便利な機能ですね。

app.module.ts では、双方向バインディングに必要となる FormsModule をインポートします。

app.module.ts
import { NgModule }      from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule }   from '@angular/forms';//追加

import { AppComponent }  from './app.component';

@NgModule({
  imports:      [ BrowserModule, FormsModule ],//FormsModule を追加
  declarations: [ AppComponent ],
  bootstrap:    [ AppComponent ]
})
export class AppModule { }

app.component.ts では、テンプレートに form 要素を配置し、その中に双方向バインディングを実装する input 要素を配置します。双方向バインディングには ngModel ディレクティブを利用します。
ここでは 2 つの input 要素を用意し、共通のコンポーネントプロパティを参照します。どちらかの input 要素で値が変更されれば、myValue の変更通知を受けて、もう一方の input 要素の値も自動的に切り替わります。

app.component.ts
import { Component } from '@angular/core';

@Component({
  selector: 'my-app',
  //template に form 要素を定義し、form 要素内に input 要素を 2 つ定義します。
  //どちらかの input 要素の値を変更すると、もう一方の input 要素の値も自動的に変更されます。
  //両方の input 要素は共に、ngModel を利用して myValue プロパティの値を双方向バインドしています。
  template: `
    <form>
    <input id="myText1" name="myText1" type="text" [(ngModel)]="myValue"/>
    <input id="myText2" name="myText2" type="text" [(ngModel)]="myValue"/>
    </form>
    `
})
export class AppComponent 
{
  myValue = "abc";
}

4. 標準パイプ/ディレクティブ
4.1 パイプ

パイプは、テキストや数値などの値をフォーマットする機能です。よく使われるフォーマットのパターンは Angular で予め用意してくれています。

下記、myText プロパティと myNumber プロパティをパイプで整形しています。
import { Component } from '@angular/core';

@Component({
  selector: 'my-app',
  template: `
    <p>{{myText | uppercase}}</p>
    <p>{{myText | lowercase}}</p>
    <p>{{myNumber | currency}}</p>
    <p>{{myNumber | currency: 'JPY': true}}</p>
    `
})
export class AppComponent 
{
  myText = "ABCdef";
  myNumber = 198000;
}

実行結果












i18nPlural
評価の値が単数形の場合と、複数形の場合で表示を変更するためのパイプです。次の例では、配列の length に応じて表示文字列を決定しています。また、テンプレート内にバインドするプロパティに、# を含めると、評価された items.length の値を埋め込むことができます。

import { Component } from '@angular/core';

@Component({
  selector: 'my-app',
  template: `
    <p>{{items.length | i18nPlural: status}}</p>
    `
})
export class AppComponent 
{
  items = ["a", "b", "c", "d", "e"];
  status={
    "=0": "None is selected yet.",
    "=1": "1 item is selected.",
    "other": "# items are selected",
  }
}

実行結果

4.2 ディレクティブ
4.2.1 ngIf
要素の表示、非表示切り替えに利用できます。条件が真のときには表示し、偽のときは非表示にします。


app.module.ts
forms 、FormsModule をインポートします。

import { NgModule }      from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule }   from '@angular/forms';//追加

import { AppComponent }  from './app.component';

@NgModule({
  imports:      [ BrowserModule, FormsModule ],//FormsModule を追加
  declarations: [ AppComponent ],
  bootstrap:    [ AppComponent ]
})
export class AppModule { }


app.component.ts
div 要素内に *ngIf="条件" で条件判定を行います。

import { Component } from '@angular/core';

@Component({
  selector: 'my-app',
  template: `
    <form>
    <label for="show">check the box</label>
      <input id="show" name="show" type="checkbox" [(ngModel)]="isVisible" />
    </form>
    <div *ngIf="isVisible">
    text here...
    </div>
    `
})
export class AppComponent 
{
  isVisible = false;
}

Angular に関連するトピックは次のページにまとめてあります。

Angular 機能紹介一覧
https://kainobi2.blogspot.com/2019/02/angular.html