20200124のC#に関する記事は4件です。

【C#】NPOIを使って「.xls」の外部参照URLを無視する方法

概要

  • C# をつかって「.xls」拡張子のエクセルファイルを書き込むが、参照できないURLがbookに含まれているときの処理について

使用バージョン

  • .NETFramework 4.6.1
  • NPOI 2.4.1

やりたいこと

  • 一括で「.xls」ファイルに入っている指定のセルの書き込みをする
  • 例:sheet1のC3に数字を書き込む
  • "=sheet1!C3" と書かれているセルがあり、セルの内容を反映(セルの評価)したい

適用Source

var book = WorkbookFactory.Create(@"C:\sample.xls");

var sheet = book.GetSheet(XlsxSheet.SheetName);
//ブック全体の数式を評価
book.GetCreationHelper().CreateFormulaEvaluator()bookWriter.EvaluateAll();

エラーがおきる

  • 以下エラー

error.png

  • NPOI.Util.RuntimeException:Could not resolve external workbook name... NPOI.SS.Formula.Workbook.NotFoundException: Could not resoleve external workbook name...

推測される原因

  • Excelの機能で、セルに対して他のファイルから読み取ったセルを代入することができるが そのファイルパスが参照できない、開けない状態。

対策

var book = WorkbookFactory.Create(@"C:\sample.xls");

var sheet = book.GetSheet(XlsxSheet.SheetName);

var bookWriter = book.GetCreationHelper().CreateFormulaEvaluator();
//外部参照URLを無視
bookWriter.IgnoreMissingWorkbooks = true;
//ブック全体の数式を評価
bookWriter.EvaluateAll();       

所感

  • NPOIってJavaのPOIから移行してるってこともあり、POIのリファレンスをみると分かる
  • ただNPOIとPOIは移行とはいえ、メソッドの名前やクラスの名前がイコールではないため、コピペは不可。
  • ググっても「ignore」を使っている人がいなかったで上げてみました。初投稿です。誰かのためになれば幸いです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

VSCodeでC#のインテリセンスが効かないとき

プロジェクトを開いたときに右下にこれが出る。

SomeProject.jpg

このとき、Output の OmniSharp Log

OmniSharpLog.jpg

に下記のメッセージが出る。

Microsoft.Build.Exceptions.InvalidProjectFileException: 指定された SDK 'Microsoft.NET.Sdk' は見つかりませんでした。  

何が起きているか

OmniSharp(C#のインテリセンス) が使う MSBuild のバージョン?があっていない。

環境変数で、OmniSharp の使う MSBuild を指定する

.NETCore-3.1 で動かす例

MSBuildSDKsPath=C:\Program Files\dotnet\sdk\3.1.100\Sdks (PATHに注意。マイナーバージョンちがうなど C:\Program Files\dotnet\sdk\3.1.101\Sdks)

設定してから、VSCode を再起動してエラーが無くなれば成功。
逆にUnityなどで .NET-4.7 などを対象にする場合は動かなくなるかもしれぬ。

OmniSharpの設定(~/.ominisharp/omnisharp.json)

{
    "MsBuild": {
        "MSBuildSdksPath": "c:/Program Files/dotnet/sdk/3.1.101/Sdks"
    }
}

これはうまくいかなかった。書き方が違うのかもしれない。

https://github.com/OmniSharp/omnisharp-vscode/issues/3074

関連

上記の記事では、Visual Studio Build Tools 2017 のアンインストール や Visual Studio をインストールするにより、MSBuild のインストール状況が変わるので間接的に解決していると思われる。
MSBuildは、.NETSdk や VisualStudio に付属しているものが知らない間にインストールされることがあるので、OmniSharp が適切なMSBuildを発見できなくなることがありそう。

逆に環境変数 MSBuildSDKsPath が間違って動かない場合もある。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

visual stdio データ入力されたものをグラフ化する

睡眠時間と満足度をユーザーに入力してもらい、それをグラフ化したいのですがプログラムのコードの書き方が分かりません。

教えてください。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

UniRxでダブルクリック判定を3種類の方法で書いてみる

UnityのUniRxは便利ですし、ネットの記事を読むことで基本的な事は理解できるでしょう
しかし、いざ応用するとなるとなかなか感覚を掴めません

そこで、ダブルクリック判定は、UniRxの扱いを入門するのにちょうどいいものだと思い、
UniRxによるシングル、ダブルクリック判定法を3つ書いてみました

今回実装するダブルクリック判定の仕様は次のようです
・シングルクリックとダブルクリックをどちらも判定できる
・ダブルクリック時に、シングルクリックは判定しない
・連打時の事も考える

準備

まずはクリック判定だけ取っておきましょう

var click = this.UpdateAsObservable()
    .Where(_ => Input.GetMouseButtonDown(0));

先に言っておきます。シングルとダブルの判定は同じObservable内でbool型で判定します
シングルクリックならfalseを流し
ダブルクリックならtrueを流すことにします

1つ目

まずは、ネットでUniRx ダブルクリックなど検索するといくらか目にする例です

var dClick1 = click
    .TimeInterval() // 前のイベントとの時間差
    .Select(v => v.Interval <= TimeSpan.FromSeconds(0.2f))
        // ↑ シングルならfalse、ダブルならtrue
    .Buffer(2, 1)
    .Where(b => !(b[0] && b[1]));
        // ↑ 連打時の判定 (3連打以上は無視)

// 出力
dClick1.Subscribe(b => Debug.Log(b ? "シングルクリック" : "ダブルクリック");
    // ↑ 3項演算子によるシングル、ダブルクリック出力

クリックをした時間差で判定する方法ですね
余計に前の状態をBufferで取ってこなくてはいけませんが、UniRx初心者が理解しやすい内容と言えます。
連打時の挙動は、
最初にシングルクリック、次にダブルクリックが流れ、
後はまったく流れないです

2つ目

今度はストリームの合成の概念を使います

var dClick2 = click
    .ThrottleFirst(TimeSpan.FromSeconds(0.2f))
        // シングルクリック判定の間隔。0.2秒以内に2つ以上流さない
    .SelectMany(Observable.Return(false) // シングルクリックはfalseを流す
        .Merge(click // ダブルクリック判定につなげる
        .Select(_ => true) // ダブルクリックはtrueを流す
        .Take(TimeSpan.FromSeconds(0.2f)).Take(1)));
            // ダブルクリック判定。trueを流す

今度は、シングルクリック判定をしたら、シングルクリック判定をやめて
ダブルクリック判定を一定時間するという方法です
Returnにより、一旦シングルクリック判定を流し、
Mergeにより、ダブルクリック判定につなげます
SelectMany
 元々のObservbleにイベントが流れた時に、
 引数に渡したObservableからイベントを取り始めます

ThrottleFirstによって、シングルクリック判定を一定時間やめておき、
そのうちに、ダブルクリック判定をしています
判定時間を2回指定しなければいけないので少々気持ち悪いです

連打時の挙動は
シングルクリックとダブルクリックの判定が交互に流れます
素直な挙動です

3つ目

var dClick3 = click
    .Select(_ => false).Take(1) // シングルならfalse。一つだけ通す
    .Concat(click.Select(_ => true) // ダブルクリックならtrue
        .Take(TimeSpan.FromSeconds(0.2f)).Take(1)) // ダブルクリック判定
    .RepeatSafe(); // 判定が終わったら繰り返し

理解の難易度が高いオペレータを使いますが、一番シンプルな実装方法です
僕はこの方法が一番好きです

Concatを使っていますがこれは
 直前のObservableがOnCompletedしたら、引数に渡したObservableに切り替える
というものです
また、引数を渡さないこともでき、その場合は
 直前にSelectで指定したObservableを使う
  (この場合は一時的にIObservable<IObservable<T>>という型になる)
というようになります

シングルクリック判定が起こってから、
ダブルクリック判定をはじめて、
すべて終了すれば RepeatSafe()により最初から判定を行う
という感じです
RepeatSafe()はOnCompletedが連続で流れれば繰り返しを終了します
Repeat()なんて使うな!無限ループが怖いぞ!

連打時には
シングルクリックとダブルクリックの判定が交互に行われるので
シングルクリックとダブルクリックが交互に出力されます

出力

最後にDebug.Logの出力だけ書きます(1つ目のところでもちらっと書きました)

var doubleClick = dClick3;
doubleClick.Subscribe(b =>
    Debug.Log(b ? "ダブルクリック" : "シングルクリック");

doubleClickにdClick1や2をいれれば、そちらの方の実装を試せます

最後

ダブルクリックというのは単純なようですが、
実際に判定を取る事を考えると奥が深い処理です

この記事を書くにあたって、Concatを覚えられて良かったです

UniRxはまだまだ学習コストが高いですね

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む