プログラムの事とか

お約束ですが「掲載内容は私個人の見解です」

何かに使えるかもしれないデータを公開しました

はてなにそろそろ記事を書けと言われていたので書きます。

puni-o.hatenablog.com

で収集したデータをGitHubに置きました。

github.com

レシピデータは某レシピサイトをクロールして集めた物なので文句言われたら消すかもしれません。

このデータが何か面白いものを作るうえで役に立てば幸いです

2016/07/15 追記

Cookpad某レシピサイトをクロールした時のソースもGitHubに入れました。

自分がデータを使えればいいだけで公開とか考えていなかったソースなんですが、 いままでいろんな方のソースとか見させてもらっているので私も少しでも貢献できればと思い上げました。

HtmlAgilityPack使ってSQL ServerDapperで保存しているので、その辺がよくわからない方には参考になるかもしれません。

UWPのInkCanvasで入力デバイスを指定する

f:id:puni-o:20160613101047j:plain

Windows 10 1511での話です、今後のバージョンアップでどうなるのかしりません

UWPのInkCanvasには

InkCnavas.InkPresenter.InputDeviceTypes

というプロパティがあります

指定するのは下のenumで取りたいデバイスだけを指定することができます

public enum CoreInputDeviceTypes : System.UInt32
{
    None = 0,
    Touch = 1,
    Pen = 2,
    Mouse = 4
}

実装例

<InkCanvas x:Name="ink"/>
<StackPanel Orientation="Horizontal" VerticalAlignment="Top" HorizontalAlignment="Left">
    <ToggleButton x:Name="Mouse" Content="Mouse" IsChecked="True" Checked="Toggle_Checked" Unchecked="Toggle_Checked"/>
    <ToggleButton x:Name="Pen" Content="Pen" IsChecked="True" Checked="Toggle_Checked" Unchecked="Toggle_Checked"/>
    <ToggleButton x:Name="Touch" Content="Touch" IsChecked="True" Checked="Toggle_Checked" Unchecked="Toggle_Checked"/>
</StackPanel>
private void SetInputDevice()
{
    var type = Windows.UI.Core.CoreInputDeviceTypes.None;
    if (Mouse?.IsChecked ?? false) type |= Windows.UI.Core.CoreInputDeviceTypes.Mouse;
    if (Pen?.IsChecked ?? false) type |= Windows.UI.Core.CoreInputDeviceTypes.Pen;
    if (Touch?.IsChecked ?? false) type |= Windows.UI.Core.CoreInputDeviceTypes.Touch;
    ink.InkPresenter.InputDeviceTypes = type;
}

private void Toggle_Checked(object sender, RoutedEventArgs e) => this.SetInputDevice();

超適当ですがこれでできますね

これを使って

UWPのInkCanvasは上記プロパティがあるおかげなのかなんなのか、InputDeviceTypesに指定した入力はIsHitTestVisibleプロパティの影響を受けません。 IsHitTestVisible="False"とするとInputDeviceTypesに指定したイベントだけがInkCanvasに行って残りはその裏にいるコントロールに渡されます。

<ScrollViewer>
    <Rectangle Width="1000" Height="1000">
        <Rectangle.Fill>
            <LinearGradientBrush>
                <GradientStop Color="Azure"/>
                <GradientStop Color="YellowGreen" Offset=".25"/>
                <GradientStop Color="Orange" Offset=".5"/>
                <GradientStop Color="Blue" Offset=".75"/>
                <GradientStop Color="Magenta" Offset="1"/>
            </LinearGradientBrush>
        </Rectangle.Fill>
    </Rectangle>
</ScrollViewer>
<InkCanvas x:Name="ink" IsHitTestVisible="False"/>
<StackPanel Orientation="Horizontal" VerticalAlignment="Top" HorizontalAlignment="Left">
    <ToggleButton x:Name="Mouse" Content="Mouse" IsChecked="True" Checked="Toggle_Checked" Unchecked="Toggle_Checked"/>
    <ToggleButton x:Name="Pen" Content="Pen" IsChecked="True" Checked="Toggle_Checked" Unchecked="Toggle_Checked"/>
    <ToggleButton x:Name="Touch" Content="Touch" IsChecked="True" Checked="Toggle_Checked" Unchecked="Toggle_Checked"/>
</StackPanel>

先ほどのXAMLを上のように変更します。 InkCanvasの後ろにScrollViewerを置きました。(中身はスクロールしていることが分かればいいだけの四角です)

これを手元の現役Surface Pro2で動かすと

f:id:puni-o:20160613102209g:plain

・はじめのイベントはタッチです。InputDeviceTypesにTouchを入れているのでInkCanvasが拾います

・次にInputDeviceTypesからTouchをはずして同じように動かします。するとTouchイベントはScrollViewerに飛ぶようになるのでScrollViewerのスクロールになります

・最後はペンのみをInputDeviceTypesにしてペンで書きながらタッチで裏をスクロールさせています。筆圧を感知しているのでペン入力だとわかってもらえると思います。

と、こんなことができます。

これを利用すると大きいキャンバスにペンで描画しながらスクロールするとか、ピンチで拡大縮小するとかそんなことが可能になります。(多分) 筆圧が無ければ移動拡大縮小はできたんですけどねぇ・・・

UWPのリリースビルドアプリでMissingInteropDataExceptionが出た

UWPの開発でデバッグ中(デバッグビルド)では全然問題が無かったのに、リリースビルドで実行したら例外が出ちゃった話です。

ソースはこんな感じ

class Coordinate
{
    public double Latitude { get; set; }
    public double Longitude { get; set; }
}

var points = new[] { 
    new Coordinate { Latitude = 35, Longitude = 139 }, 
    new Coordinate { Latitude = 36, Longitude = 140 } };
var line = new MapPolyline();
line.StrokeColor = Colors.Red;
line.StrokeThickness = 10;
line.Path = new Geopath(points.Select(p => new BasicGeoposition { Latitude = p.Latitude, Longitude = p.Longitude }));
Map.MapElements.Add(line);

Coordinateクラスは適当に作りました。 座標データを元に地図に線を描きます。

今回問題となるのはline.Pathに入れるGeopathコンストラクタ部分です。

Geopath(IEnumerable<BasicGeoposition> positions)

なのでpoints.SelectIEnumerable<BasicGeoposition>に変換してます。 デバッグ実行時は何の問題もなく動きますがリリースビルド時はnew Geopathの行で下のようになります。 f:id:puni-o:20160518152326p:plain

型 'System.Runtime.InteropServices.MissingInteropDataException' の例外が System.Private.Interop.dll で発生しましたが、ユーザー コード内ではハンドルされませんでした

追加情報:ComTypeMarshalling_MissingInteropData

この例外のハンドラーがある場合は、プログラムを安全に続行できます。

はい、ワカリマセン。

解決法

// 旧
line.Path = new Geopath(points.Select(p => new BasicGeoposition { Latitude = p.Latitude, Longitude = p.Longitude }));

// 新
line.Path = new Geopath(points.Select(p => new BasicGeoposition { Latitude = p.Latitude, Longitude = p.Longitude }).ToArray());

Geopathの引数を遅延実行させなくしました。

こういうものなんですかねぇ・・・