RunningCSharp

MS系開発者による、雑多な記事。記事は所属企業とは関係のない、個人の見解です。

GitHub:はてなブログ上にGitHubにアップロードしたソースコードの表示を試してみる

https://gist-it.appspot.com/

上記リンクを参考にしながら、この間アップロードしたソースコードの表示を試してみます。

github.com

上記URLにアップされたソースコードの中で、「RadioButtonList.cs」を表示する場合は、

<script src="http://gist-it.appspot.com/github/ysrun/sample_radiobuttonlist/blob/master/radiobuttonlist/radiobuttonlist/RadioButtonList.cs" ></script>

上記のタグをブログ本文中に入れることで、ファイル全文が表示できました。 (全文で表示すると結構量があったため、ここでは省略いたします。)

恐らくブログで一番使うのは、行番号を指定しての表示かなと考えております。

f:id:ys-soniclab:20160806224812p:plain

上記GitHubのサイト上表示によると「14行目~31行目」となっているOnApplyTemplateメソッドを表示してみようと思います。 なお、参考サイトによると行数は0始まりのようなので、13行目から30行目の指定をしたいと思います。

「?slice=13:30"」という表記をスクリプトタグの属性値に加えてみます。

<script src="http://gist-it.appspot.com/github/ysrun/sample_radiobuttonlist/blob/master/radiobuttonlist/radiobuttonlist/RadioButtonList.cs?slice=13:30" ></script>

パッと見たところ、最後2行が切れているように見えます、フッターの表示部分と被ってしまっているのかもしれません。 表示行を2行増やしてみますと、

<script src="http://gist-it.appspot.com/github/ysrun/sample_radiobuttonlist/blob/master/radiobuttonlist/radiobuttonlist/RadioButtonList.cs?slice=13:32" ></script>

こんな感じで表示されます。

C#:補完文字列に関するTips

C#4.6以降で使える補完文字列でも、改行や\をそのまま扱いたいときは@が使えます。

string test = $@"C:\test
D:\test";

また、補完対象の中括弧内に関数を指定する事も可能でした。

string test1 = "test1";
string interpolation = "補完したい文字列:{func(test1)}";
… 
static string func(string teststr) => teststr + "add";

更に中括弧内で使う関数の引数に文字列リテラルを使用することも可能で、更にその文字列リテラルに$を付けて補完文字列を扱えるなど、非常に柔軟な仕様のようです。

string test1 = "and";
string interpolation = $"{func(@"\te" + $"st{test1}")}";
Console.WriteLine(interpolation);
… 
static string func(string teststr) => teststr + "add";

結果

\testandadd

WPF:配列からRadioButtonを自動生成するItemsControlを作成

タイトルの通りItemsSourceにboolとstringを持ったオブジェクトの配列を渡すことでRadioButtonを生成するコントロールのサンプルです。

サンプルはGitHubにアップしてみました。 github.com

ItemsControlを継承したカスタムコントロールとなっております、利用時にはResourceDictionaryの読み込みが必要な感じになっています。ResourceDictionaryたいしたことは書いていませんが、改善で拡張する際にあったほうが便利かと思いつけました。

一応、使い方を。 ①RadioButtonList.csとRadioButtonList.xamlをプロジェクトに追加

②利用するView(ウィンドウなど)またはApp.xamlなど参照可能な場所に

<ResourceDictionary Source="/radiobuttonlist;component/RadioButtonList.xaml"/>

上記のリソースを読み込んだうえで、

<ctl:RadioButtonList xmlns:ctl="clr-namespace:radiobuttonlist"
ItemsSource="{Binding Items}" CheckedItem="{Binding CheckedItem}"
TitleMemberPath="Title" IsCheckedMemberPath="IsChecked"/>

上記のような感じのタグで配置します。

③ViewModel側ではItemsSourceに指定した配列クラスの「IsCheckプロパティにバインドしたいプロパティ名」を「IsCheckedMemberPath」に、 「キャプションとして表示したい文字列のプロパティ名」を「IsCheckedMemberPath」に指定します。

こんな感じで使えるかと。

例えば、上記のタグに下記のようなデータクラスをバインドした場合、

//ItemsはItemsSourceプロパティとバインドされたObservableCollection
Items.Add(new RadioButtonItem() { IsChecked = true, Title = "test1" });
Items.Add(new RadioButtonItem() { IsChecked = false, Title = "test2" });
Items.Add(new RadioButtonItem() { IsChecked = false, Title = "test3" });
Items.Add(new RadioButtonItem() { IsChecked = false, Title = "test4" });
Items.Add(new RadioButtonItem() { IsChecked = false, Title = "test5" });

下記のような画面が表示されます。

f:id:ys-soniclab:20160730230748p:plain

また、IsCheckedプロパティがTrueになったオブジェクトはCheckedItemプロパティに格納されます。


作成時、ItemTempleteの動的生成部分はちょっと作るのが大変でした。

//ItemTemplateをプロパティ値から動的に作成
var elementFactory = new FrameworkElementFactory(typeof(RadioButton));
if (!string.IsNullOrEmpty(TitleMemberPath))
{
    elementFactory.SetValue(RadioButton.ContentProperty, new Binding(TitleMemberPath));
}
if (!string.IsNullOrEmpty(IsCheckedMemberPath))
{
    elementFactory.SetValue(RadioButton.IsCheckedProperty, new Binding(IsCheckedMemberPath));
}
elementFactory.SetValue(RadioButton.GroupNameProperty, string.IsNullOrEmpty(GroupName) ? Guid.NewGuid().ToString() : GroupName);
elementFactory.AddHandler(RadioButton.CheckedEvent, new RoutedEventHandler(CheckedMethod));
this.ItemTemplate = new DataTemplate { VisualTree = elementFactory };

書きづらいし読みづらいとも思いますが、Bindingオブジェクトも色々手を付けられ、イベントに対応したメソッドも簡単に取り付けられるのは便利だと思いました。

Xamarin:ItemsControl.ItemsSourceプロパティとバインドした配列を別スレッドから動かす

WPFでもあった問題なのですが、(async/awaitなどを用いるなどして)メインではないスレッドから、ItemsControlのItemsSourceプロパティにバインドしたObservableCollectionに操作を行おうとするとエラーとなります。

(上記エラーはUWPプロジェクト、Windows8.1プロジェクトで確認)

xaml(View)

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="asyncawait_test.Page1"
             xmlns:local="clr-namespace:asyncawait_test">
  <ContentPage.BindingContext>
    <local:ViewModel />
  </ContentPage.BindingContext>
    <StackLayout Orientation="Vertical">
      <Button Text="test" Command="{Binding MyCommand}" />
      <ListView ItemsSource="{Binding MyList}" />
    </StackLayout>  
</ContentPage>

ViewModel(一部抜粋)

public const string MyListPropertyName = "MyList";

private ObservableCollection<string> _myList = new ObservableCollection<string>();

/// <summary>
/// ListViewのItemsSource
/// </summary>
public ObservableCollection<string> MyList
{
    get
    {
        return _myList;
    }

    set
    {
        if (_myList == value)
        {
            return;
        }

        _myList = value;
        RaisePropertyChanged(MyListPropertyName);
    }
}

private RelayCommand _myCommand;

/// <summary>
/// ボタンのコマンド
/// </summary>
public RelayCommand MyCommand
{
    get
    {
        return _myCommand
            ?? (_myCommand = new RelayCommand(
                                    async () =>
                                    {
                                        await Task.Factory.StartNew(TestMethod);
                                    }));
    }
}

//awaitで呼び出されるため別スレッドで実行されるメソッド
private void TestMethod()
{
    //エラー
    MyList.Add("aaa");
}

WPFではDispacherを用いて解決しておりましたが、XamarinではDevice.BeginInvokeOnMainThreadメソッドを用いて解決するとよさそうです。

//awaitで呼び出されるため別スレッドで実行されるメソッド
private void TestMethod()
{
    //これならOK
    Device.BeginInvokeOnMainThread(() => MyList.Add("aaa"));
}

Xamarin+Azure:Mobile Apps Quickstart templateを使ってAzure Mobile Appを作成した話

埼玉・春日部で開催された「JXUG Xamarin もくもく会」に参加してきました。

ytabuchi.hatenablog.com

上記企画のTシャツがほしいからと、

ytabuchi.hatenablog.com

上記のリンクの通りにAzureのアプリケーションを作り、Xamarinで動くサンプルをダウンロードし、動作している動画をTwitterに投稿しました。

twitter.com

とても手軽にAzureに接続してデータ送信できるアプリケーションを作成できて感動しました。

なお私は以前Azureのお試し登録を行ってしまっていた為初回登録時の2万円分くらいの無料枠がないため、

無料のVisual Studio Dev Essentialsで、毎月3000円のAzure無料枠を活用しようsatonaoki.wordpress.com

上記の方法で月3000円の無料枠がもらえる形で登録しなおしました。

(初回の無料枠を使い切った状態から直接登録しようとしたときはうまくいかず、一度従量課金サブスクリプションを作ってからだと登録できました。)

会場で企画の紹介や手順の解説をして下さった皆様、有難う御座いました。

C#+XAML:MVVM Light Toolkitの.net Framework4.5(C#5)以上用カスタムスニペット(Setメソッドを利用するプロパティ用)

前回の記事では.net4.5向けのmvvminpcスニペットを作成しましたが、 Setメソッド(プロパティ変更+変更通知を行うViewModelBaseのメソッド)を用いたプロパティ用スニペットについても.net4.5用のオーバーライドに対応したものがなさそうだったため、作り方を記載しようと思います。

1;以下の内容で「mvvmInpcSet45.snippet」というファイルを用意します。

<?xml version="1.0" encoding="utf-8"?>
<CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
 <CodeSnippet Format="1.0.0">
   <Header>
     <SnippetTypes>
       <SnippetType>Expansion</SnippetType>
     </SnippetTypes>
     <Title>INPC "Set" Property</Title>
     <Shortcut>mvvminpcset45</Shortcut>
   </Header>
   <Snippet>
     <Declarations>
       <Literal Editable="true">
         <ID>Type</ID>
         <ToolTip>Property type</ToolTip>
         <Default>bool</Default>
         <Function>
         </Function>
       </Literal>
       <Literal Editable="true">
         <ID>AttributeName</ID>
         <ToolTip>Attribute name</ToolTip>
         <Default>_myProperty</Default>
         <Function>
         </Function>
       </Literal>
       <Literal Editable="true">
         <ID>InitialValue</ID>
         <ToolTip>Initial value</ToolTip>
         <Default>false</Default>
         <Function>
         </Function>
       </Literal>
       <Literal Editable="true">
         <ID>PropertyName</ID>
         <ToolTip>Property name</ToolTip>
         <Default>MyProperty</Default>
         <Function>
         </Function>
       </Literal>
     </Declarations>
     <Code Language="csharp"><![CDATA[private $Type$ $AttributeName$ = $InitialValue$;

       /// <summary>
       /// Sets and gets the $PropertyName$ property.
       /// Changes to that property's value raise the PropertyChanged event. 
       /// </summary>
       public $Type$ $PropertyName$
       {
           get
           {
               return $AttributeName$;
           }
           set
           {
               Set(ref $AttributeName$, value);
           }
       }]]></Code>
   </Snippet>
 </CodeSnippet>
</CodeSnippets>

2:1で用意したファイルを「%UserProfile%¥Documents¥Visual Studio 2015¥Code Snippets¥Visual C#¥My Code Snippets」に保存します。 または、Visual Studinのメニュー「ツール > コード スニペット マネージャー」より、インポート機能でスニペットを追加します。

3:Visual StudioC#ファイル内で「mvvmInpcSet45」と入力し、タブキーを押してみてください。(インテリセンスに表示されない場合は、Visual Studioを再起動してください)

上記の操作で、下記のような感じのスニペットが展開されたかと思います。

       private bool _myProperty = false;

       /// <summary>
       /// Sets and gets the MyProperty property.
       /// Changes to that property's value raise the PropertyChanged event. 
       /// </summary>
       public bool MyProperty
       {
           get
           {
               return _myProperty;
           }
           set
           {
               Set(ref _myProperty, value);
           }
       }

.net4.5以降向けのすっきりしたSetメソッド用スニペットとなりました。

C#+XAML:MVVM Light Toolkitの.net Framework4.5(C#5)以上用カスタムスニペット(プロパティ用)

MVVMLight Toolkit純正のスニペット(mvvminpcやmvvminpclambdaなど)では、文字列かラムダ式でプロパティ名を渡しています。 しかし、.net4.5(C#5)ではnameof演算子を使い、メソッド側で呼び元のプロパティ名を取得できるため、実際のところ呼び出し時にプロパティ名は渡す必要がありません。

そのため.net4.5以降のMVVMLight Toolkitでは、RaisePropertyChangedメソッドにnameof演算子を使って実装されたプロパティ名関連の引数を無くしたオーバーロードが実装されています。

今回はmvvminpcをカスタムし、.net4.5以降のMVVMLight Toolkit向けの簡略化されたスニペットの作り方を紹介いたします。(なお、ファイルパスなどの情報はVisual Studio 2015を対象としたものです。)

1;以下の内容でファイルを用意します。名前は「mvvmInpc45.snippet」としておいてください。

<?xml version="1.0" encoding="utf-8"?>
<CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
  <CodeSnippet Format="1.0.0">
    <Header>
      <SnippetTypes>
        <SnippetType>Expansion</SnippetType>
      </SnippetTypes>
      <Title>INPC Property</Title>
      <Shortcut>mvvminpc45</Shortcut>
    </Header>
    <Snippet>
      <Declarations>
        <Literal Editable="true">
          <ID>Type</ID>
          <ToolTip>Property type</ToolTip>
          <Default>bool</Default>
          <Function>
          </Function>
        </Literal>
        <Literal Editable="true">
          <ID>AttributeName</ID>
          <ToolTip>Attribute name</ToolTip>
          <Default>_myProperty</Default>
          <Function>
          </Function>
        </Literal>
        <Literal Editable="true">
          <ID>InitialValue</ID>
          <ToolTip>Initial value</ToolTip>
          <Default>false</Default>
          <Function>
          </Function>
        </Literal>
        <Literal Editable="true">
          <ID>PropertyName</ID>
          <ToolTip>Property name</ToolTip>
          <Default>MyProperty</Default>
          <Function>
          </Function>
        </Literal>
      </Declarations>
      <Code Language="csharp"><![CDATA[private $Type$ $AttributeName$ = $InitialValue$;

        /// <summary>
        /// Sets and gets the $PropertyName$ property.
        /// Changes to that property's value raise the PropertyChanged event. 
        /// </summary>
        public $Type$ $PropertyName$
        {
            get
            {
                return $AttributeName$;
            }

            set
            {
                if ($AttributeName$ == value)
                {
                    return;
                }

                $AttributeName$ = value;
                RaisePropertyChanged();
            }
        }]]></Code>
    </Snippet>
  </CodeSnippet>
</CodeSnippets>

2:1で用意したファイルを「%UserProfile%\Documents\Visual Studio 2015\Code Snippets\Visual C#\My Code Snippets」に保存します。 または、Visual Studinのメニュー「ツール > コード スニペット マネージャー」より、インポート機能でスニペットを追加します。

3:Visual StudioC#ファイル内で「mvvminpc45」と入力し、タブキーを押してみてください。(インテリセンスに表示されない場合は、Visual Studioを再起動してください)

上記の操作で、下記のような感じのスニペットが展開されたかと思います。

    private bool _myProperty = false;

    /// <summary>
    /// Sets and gets the MyProperty property.
    /// Changes to that property's value raise the PropertyChanged event. 
    /// </summary>
    public bool MyProperty
    {
        get
        {
            return _myProperty;
        }

        set
        {
            if (_myProperty == value)
            {
                return;
            }

            _myProperty = value;
            RaisePropertyChanged();
        }
    }

mvvminpcよりもすっきりした内容で、.net4.5以降では同機能が利用できます。