2018年7月28日土曜日

Angular - ngIf ディレクティブ

Angular の ngIf ディレクティブの利用例です。

HTML テンプレート
<p>
  <input type="button" value="toggle flag" (click)="toggleFlag()">
</p>

<div #ifBlock *ngIf="flag; else elseBlock">
  This is ifBlock
</div>

<ng-template #elseBlock>
  Here is elseBlock.
</ng-template>

TypeScript
export class IfComponent implements OnInit {

  flag: boolean;


  constructor() { }

  ngOnInit() {
    this.flag = true;
  }


  toggleFlag(){
    this.flag = !this.flag;
  }
}
TypeScript の flag 変数の値に応じて表示します。flag 変数の値が true のときは #ifBlock のある div タグが、false のときは #elseBlock のある ng-template の中が表示されます。

2018年6月6日水曜日

Angular 関連メモ

Angular CLI を利用した、プロジェクトへの各種機能の追加

コンポーネントの生成
D:\dev\angular\app1\src\app>ng g c comp1
→ コンポーネントは、app.component.html にタグとして定義して、画面に埋め込む。
app フォルダ配下でコマンドを実施する点は注意。

サービスの生成
ng g s service1

2018年5月2日水曜日

ASP.NET MVC 5 学習リソース

ASP.NET MVC の学習で役に立ったリソースの一覧です。

ASP.NET MVC5実践プログラミング
https://www.amazon.co.jp/dp/4798041793

プログラミングMicrosoft ASP.NET MVC 第3版
https://www.amazon.co.jp/dp/4822298388

The Complete ASP.NET MVC 5 Course(英語)
https://www.udemy.com/the-complete-aspnet-mvc-5-course/

2018年4月21日土曜日

ASP.NET MVC で URL からコントローラー名を隠す

2018/04/23 追記
ふと、属性ルーティングで済むのではないかと思い、試してみました。結果、うまくいきました。

RegisterRoutes 内で、MapMvcAttributeRoutes を呼び出します。デフォルトで定義されている MapRoute は、必要がなければ削除(コメントアウト)します。
public class RouteConfig
{
    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

        //属性ルーティングの有効化
        routes.MapMvcAttributeRoutes();

        //"Home" や "Home/Index" にアクセスする必要がなければ削除
        //routes.MapRoute(
        //    name: "Default",
        //    url: "{controller}/{action}/{id}",
        //    defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
        //);
    }
}

続いて、ルート属性を利用して、指定します。ルートの ”/”、”/Articles”、”/Articles/Index” で Index アクションにアクセスできるように属性を 3 つ設定しています。
public class ArticlesController : Controller
{
    [Route("~/")]
    [Route("Articles")]
    [Route("Articles/Index")]
    public ActionResult Index()
    {
        return View();
    }
}

しかも、最初に参照していた stackoverflow のスレッドにも、この属性ルーティングの方法が提案されていました。よく読みましょう... (^^;)
https://stackoverflow.com/a/39948890


2018/04/22
タイトルのままです。ASP.NET MVC で URL からコントローラー名を隠す方法を調べてみました。結果、ルーティングを設定することで解決しました。

public class RouteConfig
{
    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
        //MyRoute を追加。コントローラー名を指定していないリクエストは、Articles コントローラーで捕捉
        routes.MapRoute(
            "MyRoute",
            "{action}/{id}",
            new
            {
                controller = "Articles",
                action = "Index",
                id = UrlParameter.Optional
            }
        );

        routes.MapRoute(
            name: "Default",
            url: "{controller}/{action}/{id}",
            defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
        );
    }
}

参考:ASP.NET MVC - Removing controller name from URL
https://stackoverflow.com/questions/3337372/asp-net-mvc-removing-controller-name-from-url

2018年3月27日火曜日

ASP.NET Web API で JSON を返す方法

ASP.NET Web API で JSON を返す実装例です。

1.WebApiConfig クラス内で "text/html" フォーマットをリターンするようにします。

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        // Web API の設定およびサービス
        ...

        //json を返す
        //https://stackoverflow.com/a/13277616
        config.Formatters.JsonFormatter.SupportedMediaTypes
            .Add(new MediaTypeHeaderValue("text/html"));
    }
}

2.Request.CreateReponse メソッドに、ステータスコードと、モデルのリストを渡します。すると、クライアントには JSON がリターンされます。

public class ProductsController : ApiController
{
    ...

    public HttpResponseMessage Get()
    {
        IList<IProduct> products = _rep.GetAll();

        //モデルリストから JSON に変換
        //Content Negotiation in ASP.NET Web API
        //https://docs.microsoft.com/en-us/aspnet/web-api/overview/formats-and-model-binding/content-negotiation#serialization
        return Request.CreateResponse(HttpStatusCode.OK, products);
    }
}

2018年3月26日月曜日

論理回路

AND 条件・・・2つのスイッチを直列につないで、両方のスイッチが押されて電気が流れる

OR 条件・・・2つのスイッチを並列につないで、どちらか一方のスイッチが押されて電気が流れる

NOT 条件・・・スイッチを押すと電気が流れなくなる

2018年2月4日日曜日

Angular5 TODO リスト作成

Angular5 で簡易な TODO リストを作成する実装例を紹介します。

環境準備

node.js 及び npm のインストール

Angular によるアプリケーション開発を行うにあたり、これら機能を利用しますので、それぞれインストールします。インストール後、バージョンを確認します。

バージョン確認
node -v
npm -v

Angular インストール

次のコマンドで Angular CLI をインストールします。
npm install @angular/cli -g


Angular バージョ確認
ng -v


Angular CLI プロジェクトの作成、及びアプリケーションの起動

次のコマンドで Angular CLI プロジェクトを作成します。
ng new todoApp

作成したアプリケーションフォルダに移動
cd todoApp

アプリケーション起動
ng serve -o

→ ブラウザが起動してアプリケーションを表示


ここまでで開発の準備になります。ここから Angular CLI プロジェクトに実装を加えていきます。

機能実装

機能の実装は 1 ~ 15 のステップになります。

タスク数の表示

1.変数 taskText, taskCount を宣言する。

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

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'app';

  //1
  taskText:string;
  taskCount: number;
}


2.インターポレーションでテンプレートに taskCount を表示する。

app.component.html
<div style="text-align:center">
  <h1>
      タスク数 = {{ taskCount }}<!-- 2 -->
  </h1>
</div>


3.FormsModule をインポートする。

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

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


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


タスクの追加機能

コンポーネントが初期化されるタイミングで発生するライフサイクルイベントをハンドルし、コンポーネントで利用する変数の初期化を行います。

4. OnInit をインポートする。
5. AppComponent に OnInit を実装する。
6. 変数 tasks を宣言する。
7. ngOnInit イベント内で taskText を空文字で、taskCount の値を tasks の要素数で初期化する。
8. addTask メソッドを追加する。

app.component.ts
import { Component, OnInit/*4*/ } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit/*5*/ {
  title = 'app';

  //1
  taskCount: number;
  tasks = [];//6
  
  ngOnInit(){
    //7
    this.taskText = "";
    this.taskCount = this.tasks.length;
  }

  //8
  addTask(taskNameValue: string){
    this.tasks.push(taskNameValue);
    this.taskCount = this.tasks.length;
  }
}

続いてテンプレート(HTML)側にも、データのバインドなどを実装していきます。


9. input(text) を実装し、taskName という名前をつける。
10. input(text) の value に ngModel を利用して taskText の値を双方向バインドする。
11. input(button) に click イベントを実装する。

app.component.html
<div style="text-align:center">
  <h1>
    タスク数 = {{ taskCount }}<!-- 2 -->
  </h1>

  <input #taskName type="text" [(ngModel)]="taskText"><!-- 9, 10 -->

  <input type="button" value="タスク追加" (click)="addTask(taskName.value)"><!-- 11 -->
</div>

ここまでで、input(button) をクリックすると、コンポーネント側で tasks 配列の要素が追加され、テンプレート側でバインドしている taskCount の値も増えていくことを確認することができます。

タスクのリスト表示

続けて、追加したタスクをリスト形式で表示するための実装を加えていきます。


12. tasks 配列の各要素をリスト表示する。

app.component.html
<div style="text-align:center">
  <h1>
    タスク数 = {{ taskCount }}<!-- 2 -->
  </h1>

  <input #taskName type="text" [(ngModel)]="taskText"><!-- 9, 10 -->

  <input type="button" value="タスク追加" (click)="addTask(taskName.value)"><!-- 11 -->
</div>

<ul>
  <!-- 12 -->
  <li *ngFor="let task of tasks">
    {{ task }}
  </li>
</ul>


13. タスクリストの位置調整

app.component.css
ul {
    position: relative;
    left: 40%;
}

ここまでで、ボタンクリックでタスクが追加していくようになります。

タスクの削除

タスクの追加ができたら、タスクの削除もできるようにします。タスクの削除は、タスク(li 要素)をクリックした時に行います。

14. input(button) に click イベントを登録する。

app.component.html
<div style="text-align:center">
  <h1>
    タスク数 = {{ taskCount }}<!-- 2 -->
  </h1>

  <input #taskName type="text" [(ngModel)]="taskText"><!-- 9, 10 -->

  <input type="button" value="タスク追加" (click)="addTask(taskName.value)"><!-- 11 -->
</div>

<ul>
  <!-- 12 -->
  <li *ngFor="let task of tasks; let idx = index;" (click)="removeTask(idx)"><!-- 14 -->
    {{ task }}
  </li>
</ul>

コンポーネント側で、タスクを削除するための removeTask イベントハンドラを実装します。

15. app.component.ts
//15
removeTask(idx:number){
  this.tasks.splice(idx, 1);
}

以上で、簡単ではありますが、Angular を利用した TO DO リストの作成ができました。


全ソースコード

各ファイルのソースコードは次のようになっています。

app.component.ts
import { Component, OnInit/*4*/ } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit/*5*/ {
  title = 'app';

  //1
  taskText:string;
  taskCount: number;

  tasks = [];//6
  
  ngOnInit(){
    //7
    this.taskText = "";
    this.taskCount = this.tasks.length;
  }

  //8
  addTask(taskNameValue: string){
    this.tasks.push(taskNameValue);
    this.taskCount = this.tasks.length;
    this.taskText = "";
  }
  //15
  removeTask(idx:number){
    this.tasks.splice(idx, 1);
  }
}

app.component.html
<div style="text-align:center">
  <h1>
    タスク数 = {{ taskCount }}<!-- 2 -->
  </h1>

  <input #taskName type="text" [(ngModel)]="taskText"><!-- 9, 10 -->

  <input type="button" value="タスク追加" (click)="addTask(taskName.value)"><!-- 11 -->
</div>

<ul>
  <!-- 12 -->
  <li *ngFor="let task of tasks; let idx = index;" (click)="removeTask(idx)"><!-- 14 -->
    {{ task }}
  </li>
</ul>

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

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


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

app.component.css
ul {
    position: relative;
    left: 40%;
}
以上になります。

超簡易 Python サーバー作成方法

Python3 で簡易ウェブサーバーを作成する手順をメモしておきます。

1.フォルダレイアウト
C:\py
  - cgi-bin
    - index.py
    - index.tpl

2.実装
index.py
print('Content-type: text/html; charset=UTF-8\r\n')
fopen = open("cgi-bin/index.tpl", encoding="utf-8")
lines = fopen.read()
fopen.close()
print(lines)

index.tpl
<html>
    <head>
        <title>aaa</title>
    </head>
    <body>
        aaabbbccc
    </body>
</html>

3.コマンド
C:\py> python -m http.server --cgi 8000


4.ブラウザでアクセス
http://localhost:8000/cgi-bin/index.py

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>