開発備忘録

WPF(Xaml + C#)の話題を中心に.Net関連についてのブログです。

JR回数券と定期券の併用方法について

たまに使用する電車の乗車回数券ですが、定期券との併用方法をよく忘れるのでメモ

この記事で紹介する内容はJR西日本大阪環状線JR神戸線)でのみ使用可能であることを確認しています。
全ての線区・区間が同じ仕組みかどうかはわかりませんのでご注意ください。
※この記事は2017年7月時点のものです。

回数券はJRの券売機で購入することができる乗車券です。
詳細については以下のページを確認してください。

faq.jr-odekake.net

通常、定期券は以下の様に複数の駅間で使用していると思います。
f:id:iyemon018:20170720165411p:plain


ここで例えばB駅で乗り換えてD駅まで定期的に移動することになった場合、回数券を使用すると少し交通費を節約することができます。
f:id:iyemon018:20170720165646p:plain

イメージとしてはこんなところでしょうか。
この②の区間の回数券を購入し、通常使用している①区間の定期券と合わせて使用することが可能です。
ただし、行き(上記A駅からD駅へのルート)と帰り(上記D駅からA駅へのルート)で手順が異なるので注意してください。

■行き

1.A駅で定期券を使って乗車する。
2.D駅まで乗車する。
3.D駅の精算機でカード挿入口に"定期券"→"回数券"の順番に挿入する。
  この時、定期券にチャージ済みであってもこの方法を使用することはできます。
  ただし、支払い不要のメッセージが表示されるので素早く回数券を投入してください。
4.出場証が発行されるので通常の切符と同じように使用する。

■帰り

1.D駅で回数券を使用して乗車する。
2.A駅まで乗車する。
3.A駅の精算機でカード挿入口に"回数券"→"定期券"の順番に挿入する。
4.出場性が発行されるので通常の切符と同じように使用する。

乗車するときと生産する際の手順が異なります。
特に乗車する際は手順を間違えると回数券で支払いすることができなくなるので注意してください。

Jenkins でxUnit + OpenCover を使ったカバレッジ集計・レポート表示方法について

少し前にJenkins でxUnit を使ったユニットテストの実行方法を試しました。
iyemon018.hatenablog.com

今回は、Jenkins でxUnit でユニットテストを実行し、OpenCover を使ってカバレッジを集計・プロジェクトページに表示する方法についてメモします。

続きを読む

TFS でTF14061 が表示されたときの対処方法

TFS 使っているときにTF14061 なるエラーメッセージが表示されたときの事象と対処方法メモです。

現象

Visual Studio でTFS と接続しているときに、チーム エクスプローラー上に"予期しないファイルの終わりを検出しました。"というメッセージが表示される。
この状態でチェックインしても同じメッセージが表示されてしまい、チェックインすることができない。
ソース管理エクスプローラーを表示しようとするとマップが解除されてしまっていて表示されない。
このときに"TF14061" メッセージが表示される。

原因

TFS のキャッシュにゴミデータが含まれてしまっているため。
異なるバージョンのTFS に接続してOS を再起動したときに発生したので、TFS バージョンの混在が原因かも?

対処方法

一度Visual Studio を終了して"%USERPROFILE%\AppData\Local\Microsoft\Team Foundation\6.0" にある"Cache" フォルダを削除する。
Visual Studio を再起動するとチェックイン出来るようになる。

WPF でVisualTree のヒット テストを実行する

VisualTreeHelper を使用すると特定のコントロールのVisualTree 要素を検索したりできることは知っていたのですが、今まで使用する機会は殆どありませんでした。
今回使用したときに躓いた箇所も含めて、その使用方法をメモします。

以下、動作環境です。

VisualTreeHelper とは

WPF (と言うかXAML) には"LogicalTree" と"VisualTree" の2種類の要素ツリーが存在します。

  • LogicalTree は、論理ツリー つまりXAML で定義した内容で表されるツリーです。
  • VisualTree は、テンプレートなどの内容も含めた、その名の通りビジュアライズされた要素のツリーです。

"VisualTreeHelper" は、このVisualTree 上の要素を検索したりヒット テストを実施するためのヘルパー クラスです。

続きを読む

ViewModelのプロパティ変更をトリガーにアニメーションする方法

WPF でViewModel のプロパティが変更されたときにStoryboard を開始する方法で少し躓いたのでメモ。
開発環境は以下の通り。

ViewModel のプロパティの変更をトリガーにアニメーションするのが目的なので、まず思い浮かんだのがこれ↓

<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:local="clr-namespace:BindingSoureChangedAnimation"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
        xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
        x:Class="BindingSoureChangedAnimation.MainWindow"
        Title="MainWindow"
        Width="525"
        Height="350"
        d:DataContext="{d:DesignInstance {x:Type local:MainWindowViewModel}, IsDesignTimeCreatable=True}"
        mc:Ignorable="d">
    <Window.Style>
        <!--
            Style のDataTrigger でViewModel のプロパティの値によってストーリーボードを開始する。
        -->
        <Style TargetType="{x:Type Window}">
            <Style.Triggers>
                <DataTrigger Binding="{Binding IsAnimation}"
                             Value="True">
                    <DataTrigger.EnterActions>
                        <BeginStoryboard Storyboard="{DynamicResource ColorChangeStoryboard}"
                                         x:Name="Begin_ColorChangeStoryboard" />
                    </DataTrigger.EnterActions>
                    <DataTrigger.ExitActions>
                        <StopStoryboard BeginStoryboardName="Begin_ColorChangeStoryboard" />
                    </DataTrigger.ExitActions>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </Window.Style>
    <Window.Resources>
        <!-- 実行したいStoryboard  -->
        <Storyboard x:Key="ColorChangeStoryboard">
            <ColorAnimationUsingKeyFrames Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)"
                                          Storyboard.TargetName="rectangle">
                <EasingColorKeyFrame KeyTime="0"
                                     Value="#FF7A7AFF" />
                <EasingColorKeyFrame KeyTime="0:0:1"
                                     Value="#FFFFFFA9" />
            </ColorAnimationUsingKeyFrames>
        </Storyboard>
    </Window.Resources>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <CheckBox Content="アニメーション"
                  IsChecked="{Binding IsAnimation, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
        </CheckBox>
        <Border Grid.Row="1">
            <Rectangle x:Name="rectangle"
                       Fill="#FF7A7AFF"
                       Stroke="Black"
                       Margin="32" />
        </Border>
    </Grid>
</Window>

Window のStyle.Trigger のDataTrigger を使用するパターン。
これを実行するとこうなります。
f:id:iyemon018:20170609002314p:plain

Window のStyle からでは、Window.Resources 内のリソースにはアクセスできないとのこと…。
同様にWindow.Content のGrid のStyle でも実現はできません。

で、次の案。
Behavior のControlStoryboardAction を使用する。
ただ、このBehavior はEventTrigger になっているのでイベントの着火をトリガーとするため今回の目的には合致しません。(※)

いろいろ調べた結果、以下の方法で実現することができました。

<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:local="clr-namespace:BindingSoureChangedAnimation"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
        xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
        x:Class="BindingSoureChangedAnimation.MainWindow"
        Title="MainWindow"
        Width="525"
        Height="350"
        d:DataContext="{d:DesignInstance {x:Type local:MainWindowViewModel}, IsDesignTimeCreatable=True}"
        mc:Ignorable="d">
    <Window.Resources>
        <!-- 実行したいStoryboard  -->
        <Storyboard x:Key="ColorChangeStoryboard"
                    RepeatBehavior="Forever">
            <ColorAnimationUsingKeyFrames Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)"
                                          Storyboard.TargetName="rectangle">
                <EasingColorKeyFrame KeyTime="0"
                                     Value="#FF7A7AFF" />
                <EasingColorKeyFrame KeyTime="0:0:1"
                                     Value="#FFFFFFA9" />
            </ColorAnimationUsingKeyFrames>
        </Storyboard>
    </Window.Resources>
    <i:Interaction.Triggers>
        <!--
            IsAnimation プロパティの値が"True" ならStoryboard を開始する。
            "True" 以外の値ならStoryboard を停止する。
        -->
        <ei:DataTrigger Binding="{Binding IsAnimation, Mode=OneWay}"
                        Value="True">
            <ei:ControlStoryboardAction Storyboard="{StaticResource ColorChangeStoryboard}" />
        </ei:DataTrigger>
        <ei:DataTrigger Binding="{Binding IsAnimation, Mode=OneWay}"
                        Value="True"
                        Comparison="NotEqual">
            <ei:ControlStoryboardAction Storyboard="{StaticResource ColorChangeStoryboard}"
                                        ControlStoryboardOption="Stop" />
        </ei:DataTrigger>
    </i:Interaction.Triggers>
    <Window.DataContext>
        <local:MainWindowViewModel />
    </Window.DataContext>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <CheckBox Content="アニメーション"
                  IsChecked="{Binding IsAnimation, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
        <Border Grid.Row="1">
            <Rectangle x:Name="rectangle"
                       Fill="#FF7A7AFF"
                       Stroke="Black"
                       Margin="32" />
        </Border>
    </Grid>
</Window>

変更点はここ

    <i:Interaction.Triggers>
        <!--
            IsAnimation プロパティの値が"True" ならStoryboard を開始する。
            "True" 以外の値ならStoryboard を停止する。
        -->
        <ei:DataTrigger Binding="{Binding IsAnimation, Mode=OneWay}"
                        Value="True">
            <ei:ControlStoryboardAction Storyboard="{StaticResource ColorChangeStoryboard}" />
        </ei:DataTrigger>
        <ei:DataTrigger Binding="{Binding IsAnimation, Mode=OneWay}"
                        Value="True"
                        Comparison="NotEqual">
            <ei:ControlStoryboardAction Storyboard="{StaticResource ColorChangeStoryboard}"
                                        ControlStoryboardOption="Stop" />
        </ei:DataTrigger>
    </i:Interaction.Triggers>

ControlStoryboardAction 使ってるんですが、そのトリガーに"ei:DataTrigger" を使用しています。
通常の"DataTrigger" とは違って"Microsoft.Expression.Interactivity.Core" 名前空間にいるやつです。
こいつを探し出すのが苦労したorz

通常、Blend からBehavior をドラッグ・アンド・ドロップで配置するとトリガーは、"EventTrigger" になります。
これを"ei:DataTrigger" に変更するには以下の手順を実行します。

1.Behavior を配置する。

2.EventTrigger をDataTrigger に変更する。
  プロパティ ウィンドウの[トリガー] - [新規] をクリックします。
f:id:iyemon018:20170609004623p:plain

  一覧から"DataTrigger" を選択して[OK] をクリックします。
f:id:iyemon018:20170609004816p:plain

3.トリガーの値を設定する。
  プロパティ ウィンドウの[トリガー] "TriggerType" が"DataTrigger" に変わっていることを確認してViewModel のプロパティの値をバインドする。
f:id:iyemon018:20170609004947p:plain

これを探し出すのに一番時間がかかりました。
ちなみにControlStoryboardAction は、Play とStop それぞれのアクションを設定しないとStoryboard を開始、終了することができません。
また、値の比較種別として"Equal", "NotEqual" 以外にも"LessThan (未満)", "GreaterThan (~より大きい)" 等があるので、ViewModel のプロパティがある数値以上の場合にアニメーションを制御する といったこともできそうです。(未確認)


今回使用したソースはこちら↓↓↓
github.com

(WPF) ウィンドウのバウンド エフェクトを無効化する方法

Windows10 でスクロールバーが表示されたListBox をタッチ操作したときにバウンドするようなUI 表現を無効化する方法についてメモします。

タブレットでWindows10 を使用している際に、エクスプローラーなどで一覧表示している際に、領域外までスクロールするとウィンドウが少しだけ移動します。
イメージ的にはこんな感じ↓↓↓
f:id:iyemon018:20170605132510p:plain

この動作はWindow 内にListBox やDataGrid などのリスト系コントロールがある場合に発生します。
地味に厄介なのが、最大化表示でウィンドウ枠を非表示にしても発生するという点です。
デジタルサイネージのようにクライアント領域をフルに使用している場合にこの動作が発生すると、少しだけ背景(デスクトップなど)が見えてしまって非常に格好悪いです。

この動作は、.NET Framework 4.0 で追加された"ManipulationBoundaryFeedback"イベントで無効化することができます。


以下の例では、ListBox のManipulationBoundaryFeedback イベントを追加しています。

private void ListBox_ManipulationBoundaryFeedback(object sender, ManipulationBoundaryFeedbackEventArgs e)
{
    e.Handled = true;
}

これで領域外でスクロールしてもバウンドしなくなりました。
他にも、"e.BoundaryFeedback" プロパティでタッチ操作の移動ベクトルや移動対象のオブジェクトを取得することができます。
今回の例ではイベントで対処していますが、アプリケーションに組み込むのであればBehavior にしたほうがいいでしょう。

以上、小ネタでした。

Windows10 + WPF でタッチ フィードバックを無効化する(※)

Windows10 上のWPF アプリケーションでタッチ フィードバックを無効化する方法にいてメモ

※まず最初に、この記事で紹介する方法はあるパターン(後述)に対応できていません。
 そのパターンでの対応方法が見つかれば追記 or あらたに記事を書きます。

タッチ フィードバックとは?

Windows8 以降(?)に登場したタッチパネル向けの視覚的表現です。
下の白い円状のインジケータがそれです。
f:id:iyemon018:20170525223659p:plain

このタッチ フィードバックは、以下の設定で表現のレベルを変更することができます。
[Windowsの設定] - [簡単操作] - [その他のオプション] - [タッチ フィードバック]
f:id:iyemon018:20170525224213p:plain

or
[コントロールパネル] - [ペンとタッチ] - [タッチ]
f:id:iyemon018:20170525224224p:plain

この設定は同期しているのでどちらかを変更すればもう片方も変わります。

無効化するには

上記の設定をOFFにすればデスクトップやエクスプローラ、ブラウザなどを操作している感じでは、無効化することができます。
ただし、独自に作成したWPFなどのアプリケーションは、この設定の影響を受けないようです。
Visual Studioもこの影響を受けません。
(UWPならこの設定の影響を受けるのかもしれませんが未検証です。)

ということでタッチ フィードバックを無効化する方法について色々調べてみた結果、完成したコードがこちら↓↓↓

続きを読む