Enum Radio Button Binding
WPFのMVVMは好きです。他の言語で似非MVVM書いてるとなんだかなーって思う。
が、やっぱりWPFは嫌いです。
はい。EnumをBindingしたいとき。
まずおもむろにEnumの拡張を用意しましょう。このブログでも出てきたと思いますよー。
public static class EnumEx { public static string StringValue(this Enum e) { var fieldInfo = e.GetType().GetField(e.ToString()); var attribute = (StringValueAttribute)fieldInfo.GetCustomAttributes(typeof(StringValueAttribute), false).FirstOrDefault(); return attribute == null ? null : attribute.StringValue; } }
次にConverterを2つ用意しましょう。
using System; using System.Globalization; using System.Windows.Data; namespace Hoge { [ValueConversion(typeof(Enum), typeof(bool))] public class EnumToRadioButtonConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { return value.Equals(Enum.Parse(value.GetType(), parameter.ToString())); } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { if (!(bool)value) return Binding.DoNothing; return Enum.Parse(targetType, parameter.ToString()); } } }
using System; using System.Globalization; using System.Windows.Data; namespace Hoge { [ValueConversion(typeof(Enum), typeof(string))] public class EnumToStringConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { return (Enum.Parse(value.GetType(), parameter.ToString()) as Enum).StringValue(); } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { if (!(bool)value) return Binding.DoNothing; return Enum.Parse(targetType, parameter.ToString()); } } }
んで、enumとViewModel。双方向は省略。INotifyPropertyChangedを実装してくだされ。
namespace Hoge { public enum Gender { [StringValue("男性")] Male, [StringValue("女性")] Female } public sealed class HogeViewModel { public Gender Gender { get; set; } } }
で、View
<Page x:Class="Hoge.SamplePage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:Hoge" mc:Ignorable="d" d:DesignHeight="500" d:DesignWidth="300"> <Page.DataContext> <local:HogeViewModel x:Name="viewModel" /> </Page.DataContext> <Page.Resources> <local:EnumToRadioButtonConverter x:Key="EnumToRadioButton"/> <local:EnumToStringConverter x:Key="EnumToString"/> </Page.Resources> <Grid> <StackPanel Orientation="Horizontal"> <RadioButton GroupName="Gender" Content="{Binding Gender, ConverterParameter=Male, Converter={StaticResource EnumToString}}" IsChecked="{Binding Gender, ConverterParameter=Male, Converter={StaticResource EnumToRadioButton}}"/> <RadioButton GroupName="Gender" Content="{Binding Gender, ConverterParameter=Female, Converter={StaticResource EnumToString}}" IsChecked="{Binding Gender, ConverterParameter=Female, Converter={StaticResource EnumToRadioButton}}"/> </StackPanel> </Grid> </base:BasePage>
Windowsタスクトレイ常駐型のアプリを作る(WPF版)
よく作るんですけどね。忘れるよね。
なお、ググるキーワードはNotifyIcon。
Component作成
Componentsフォルダを作って、右クリック→「追加」→「新しい項目」
「コンポーネントクラス」を探し出して、お好きな名前をつけて追加しましょう。
ここでは「NotifyIcon」としました。
NotifyIconクラスの編集
ツールボックスから「ContextMenuStrip」と「NotifyIcon」を追加します。
ツールボックスで検索して、ドラッグ&ドロップで持っていきましょう。
デフォルトの名前が嫌なので変えましたよ。
contextMenuStripの設定
contextMenuStripを右クリックで「項目の編集」
MenuItemを追加
「デザイン」→「(Name)」と「表示」→「Text」を編集
Nameはご自由に。Textはタスクトレイのアイコンを右クリックしたときに出るメニューに表示されますよ。
myNotifyIconの編集
プロパティを開いて、ContextMenuStripとIconを設定
NotifyIcon.csの編集
終了メニュークリックしたらアプリケーションを終了。
using System; using System.ComponentModel; using System.Windows; namespace Hoge.Components { public partial class NotifyIcon : Component { public NotifyIcon() { InitializeComponent(); toolStripMenuItemExitApp.Click += delegate (object sender, EventArgs e) { Application.Current.Shutdown(); }; } public NotifyIcon(IContainer container) { container.Add(this); InitializeComponent(); } } }
App.xamlの編集
App.xaml.csのほうから
using Hoge.Components; using System.Windows; namespace Hoge { /// <summary> /// App.xaml の相互作用ロジック /// </summary> public partial class App : Application { private NotifyIcon notifyIcon = new NotifyIcon(); protected override void OnStartup(StartupEventArgs e) { base.OnStartup(e); ShutdownMode = ShutdownMode.OnExplicitShutdown; } protected override void OnExit(ExitEventArgs e) { base.OnExit(e); notifyIcon.Dispose(); } } }
んで、App.xaml
StartupUri="MainWindow.xaml"って記載があるので削除しましょう。
<Application x:Class="Questionnaire.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:Hoge"> <Application.Resources> </Application.Resources> </Application>
Windowsインストーラーの作成
2018年最新版!
Visual Studio2017向け!ぼくはVisual Studio Community 2017だよ!
既存のソリューションにインストーラープロジェクトを追加するよ!最近C#ばっかだよ!
作成
Visual Studioを起動。インストーラーを追加したいソリューションを開いてね!
ソリューションを右クリックで「追加」→「新しいプロジェクト」
「インストール済み」→「その他のプロジェクトの種類」→「Setup Project」で名前をつけて「OK」
インストールするファイルの指定
追加されたプロジェクトを右クリックで「View」→「ファイルシステム」
ちなみに「インストール」「アンインストール」からインストーラーとあんインストーラーが起動できるよ!
単純なものだったら「Application Folder」を右クリック→「Add」→「プロジェクト出力」でexeとかDLLが追加できるよ!
よその記事見るとインストーラービルド時に構成を切り替えてーとかやってたけど、インストーラーなんてここでRelease Any CPUにしとけばいいと思うよ!
インストーラー設定
必要最低限。セットアッププロジェクトのプロパティね。
Author→お名前を書きましょう
Manufacturer・ProductName→C:¥Program Files¥[Manufacturer]¥[ProductName]にデフォルトでインストールされるよ!
TargetPlatform→ちゃんと合わせようね!
Docker環境構築(Rails)②
devdevdev.hatenablog.com
基礎編はこちら
前回作ったコンテナ上にrailsの実行環境を作っていきますよー
ホスト側は一切汚しません。
とりあえずね
$ docker-compose run app bundle init
app/Gemfileが生成されるよ
Gemfileを編集
デフォルトはこう
# frozen_string_literal: true source "https://rubygems.org" git_source(:github) {|repo_name| "https://github.com/#{repo_name}" } # gem "rails"
最後の行を以下のように書き換えます
gem 'rails', '5.1.4'
docker-compose.ymlの編集
appの下に以下を追記
environment: RAILS_ENV: development
app / volumesの下に以下を追記
- bundle:/usr/local/bundle
appの一番下に以下を追記
command: /bin/sh -c 'mkdir -p tmp/sockets/ && bundle exec puma -C config/puma.rb'
一番下に以下を追記
volumes: bundle:
Dockerfileの編集
docker/app/Dockerfileに以下を追記
RUN apt-get update && apt-get install -y nodejs ADD ./app/Gemfile* $APP_ROOT/ RUN bundle install
ビルド
$ docker-compose build
railsアプリケーション作成
appにsshではいる
$ docker-compose run app bash
普通に作る
$ rails new . -d mysql
Gemfileを上書きしていいか聞かれるので「Y」
app/config/database.yml書き換え
development: password: password
app/config/puma.rbに以下を追記
app_root = File.expand_path("../..", __FILE__) bind "unix://#{app_root}/tmp/sockets/puma.sock"
ビルドして起動
$ docker-compose build $ docker-compose up
http://localhost/にアクセスしてrailsの画面が表示されればおk。
Docker環境構築(Rails)①
入門~インストールはこちら
devdevdev.hatenablog.com
DockerとDocker-Compose
Dockerはコンテナの管理
Dockerfileで色々管理
Docker-Composeは複数のコンテナの管理
docker-compose.ymlで色々管理
Docker-Composeで環境を作るコンテナの内容によってはDockerfileは不要
くらいに覚えておけば十分かと。
構築する環境
App(Ruby 2.5.1) - アプリケーションサーバー
MySQL 5.7.21 - DB
Nginx 1.13.10 - Webサーバー
phpMyAdmin - 何かと便利
Redis 3.2.11 - KVS
ファイル構成
- app/ - docker-compose.yml - docker/ - app/ - Dockerfile - mysql/ - conf.d/ - custom.cnf - nginx/ - app.conf
docker/配下のファイルの用意
App
Dockerfileを用意
FROM ruby:2.5.1 ENV APP_ROOT /var/www/app WORKDIR $APP_ROOT
MySQL
Dockerfileは不要。
mysql/conf.d/custom.cnfを用意しましょう。
[client] default-character-set=utf8 [mysqld] character-set-server=utf8 [mysqld_safe] timezone = UTC
Nginx
Dockerfileは不要
nginx/app.confを用意しましょう。
server { listen 80 default_server; index index.php index.html index.htm; root /var/www/app; }
phpMyAdmin
Dockerfileも何もいりません。
Redis
Dockerfileも何もいりません。
docker-compose.ymlの作成
version: '2' services: app: build: context: . dockerfile: ./docker/app/Dockerfile volumes: - ./app:/var/www/app ports: - 3000:3000 depends_on: - mysql - redis mysql: image: mysql:5.7.21 environment: MYSQL_ROOT_PASSWORD: password MYSQL_DATABASE: app ports: - 3306:3306 volumes: - ./docker/mysql:/etc/mysql/conf.d nginx: image: nginx:1.13.10 ports: - 80:80 volumes_from: - app volumes: - ./app:/var/www/app - ./docker/nginx:/etc/nginx/conf.d depends_on: - app phpmyadmin: image: phpmyadmin/phpmyadmin environment: - PMA_ARBITRARY=1 - PMA_HOST=mysql - PMA_USER=root - PMA_PASSWORD=password links: - mysql ports: - 8080:80 redis: image: redis:3.2.11
起動してみる
$ docker-compose up
・エラーが表示されない
・http://localhost/にアクセスしてNginxの404が表示される
・http://localhost:8080/にアクセスしてphpMyAdminが表示される
のが確認できれば完了。停止はControl + cで。
アプリケーションの用意は次回やります。
Trouble shooting
ERROR: for mysql Cannot start service mysql: b'Mounts denied: ~
ファイルを作った場所によってはこんなエラーが出る場合があります。
右上のクジラアイコンをクリックして、「Preferences」
「File Sharing」でdocker-compose.ymlがある場所を追加しましょう。
終わったら「Apply & Restart」してしばらく待ちましょう。
Docker入門~インストール
そういえば書いてなかった気がする&人に説明するので、筆を取ることにしました。
入門
Dockerとは
コンテナ仮想化ツール
簡単に言うとPC上にWebサーバーとか、DBサーバーとかを一つにまとめた環境をポンと構築できるよってやつ。
Vagrantとかは1台の仮想マシンに1マシンになるので、WebサーバーとDBサーバーを立てようと思ったら2つ必要になるのが大きな違いかな。
Dockerを使うメリット
本番環境と同じ環境を簡単に用意できる。
なんならそのまま本番環境に使えるらしい。
起動とか処理が早い。
軽い。
コマンドを叩くだけで環境構築完了!
Docker用語
・イメージ:コンテナの元となるもの。EC2でいうAMI。Docker Hubというところにある。
・コンテナ:イメージを元に作られたもの。ここに各プロジェクト用の情報などが設定される。EC2でいうインスタンス。
インストール
Docker Store
から「Docker Community Edition for Mac」をダウンロードしましょう。
ダウンロードした「Docker.dmg」をダブルクリックして開きましょう。
書いてあるとおりにドラッグ&ドロップすれば完了!
【Swift4】【Codable】 CodingKeys書くのだるいよね
とゆーわけで作りました。SwiftLint対応。
SOURCE_DIR="$PROJECT_DIR/Hoge/Models" DEST_DIR="$PROJECT_DIR/Hoge/ModelExtensions" find $DEST_DIR -name "*Ex.swift" -type f | while read FILE do rm -f ${FILE} done find $SOURCE_DIR -name "*.swift" -type f | while read FILE do NAME=$(basename ${FILE} | sed "s/.swift//g") DEST_FILE=$DEST_DIR"/"$NAME"Ex.swift" touch $DEST_FILE echo "extension $NAME {" >> "$DEST_FILE" echo " enum CodingKeys: String, CodingKey {" >> "$DEST_FILE" while read line; do if ! echo $line | grep -q //; then if echo $line | grep -q let; then NAME=$(echo $line | sed -e "s/:.*$//g" -e "s/^.*let //g") SNAKED=$(echo $NAME | gsed -r -e 's/^([A-Z])/\L\1\E/' -e 's/([A-Z])/_\L\1\E/g') if [ $NAME = $SNAKED ]; then echo " case $NAME" >> "$DEST_FILE" else echo " case $NAME = "'"'"$SNAKED"'"' >> "$DEST_FILE" fi fi fi done < ${FILE} echo " }" >> "$DEST_FILE" echo "}" >> "$DEST_FILE" done