空談録

http://artfulplace.net/blogs/ からひっこしつつ

OfficeのリボンXMLを別アセンブリのクラスから拡張する

ぐぬぬぬぬ、月一更新はしたいと思っていたのに…

OfficeのリボンカスタマイズにはXMLを書く場合とWinFormsもどきで頑張っていじる場合があると思います。
しかしXMLで書くのは面倒…インテリセンスがそこそこ効くけど…

というあれそれを解決するためにxamlで書けるようにしたい!というライブラリを作ろうとした話です。
完成?いつかするかなって…一応根本部分はできたしあとは生やせば……

なおあまりxaml関係ない記事です。IRibbonExtensibilityとかいうやつの話です

XAMLで扱えるクラスでリボンを拡張する

リボンの拡張にはIRibbonExtensibility (Microsoft.Office.Core)を使います。これさえ実装していればおっけー!という感じだと思います
ついでにXAMLで読み込むためにDependencyObjectを継承しておきましょう。

サクサク実装するとこんなんでしょうか

using System.Windows;
using System.Windows.Markup;
using Office = Microsoft.Office.Core;

// ~~~~~~

[ComVisible(true)]
public class RibbonExtensibility : DependencyObject, Office.IRibbonExtensibility
{
    public string GetCustomUI(string RibbonID)
    {
        return "<?xml version=\"1.0\" encoding=\"UTF-8\"?> ...";
    }
}

とまあいつも通りダメコードなのですが、ひとまずこれで作ってみる感じかなと
DependencyObjectを継承してXAMLで扱えるようにして、IRibbonExtensibilityを実装してリボンを読み込んでもらえるようにします。

ちなみにIDTExtensibility2がいるとかどこかにあるんですけどVSTOアドインの場合は不要で、COMアドインの場合は普通に必須です。
(というよりはCOMアドインそのものの読み込みにIDTExtensibility2が必要なのでリボン関係ないのでは…とは思う)

GetCustomUIの中身は最初は動くXMLを入れておきましょう。結構検証で詰まりますし。

で、読み込み部分はThisAddin.csに次のコードをコピペします。
読み込み部分は単純で、オーバーライドしてIRibbonExtensibilityを返せばいい感じです

protected override Microsoft.Office.Core.IRibbonExtensibility CreateRibbonExtensibilityObject()
{
    return new RibbonExtensibility();
}

やべえ!XAML全然関係ない!

で、アドインを実行するともれなく次のようなメッセージが出ます。

A QueryInterface call was made requesting the class interface of COM visible managed class 'RibbonExtensibility'. However since this class derives from non COM visible class 'DependencyObject', the QueryInterface call will fail. This is done to prevent the non COM visible base class from being constrained by the COM versioning rules.

DependencyObjectがCOMで参照できないんですけど!!って言われます。
参照できなくてもいいんだけど…と思って続行していると読み込んでくれません。つらい。

ちなみにDependencyObjectを継承するアホなことをしていなければ別ライブラリでIRibbonExtensibilityだけ実装で読み込めるはずです。なんと!このブログ記事の存在価値やいかに

というわけで答えを書いてしまいましたがComVisibleじゃないクラスを継承していなければいいだけなのでRibbonExtensibilityからDependencyObjectを消します。
代わりにRibbonExtensibilityを使っていた部分を置き換える別のクラスを作って、こちらに「DependencyObjectのみ」を継承します。IRibbonExtensibilityは不要です。

今回だと次のようなコードで対処できます。

[ComVisible(true)]
public class RibbonExtensibility : Office.IRibbonExtensibility
{
    public RibbonExtensibility(CustomUI ui)
    {
        customUI = ui.GetRibbonXml();
    }
    private string customUI { get; set; }
    public string GetCustomUI(string RibbonID)
    {
        return customUI;
    }
}

public class CustomUI : DependencyObject
{
    public string GetRibbonXml() { ... }
}

つまるところ適当に継承して手抜きをするなって話ですね。
別ライブラリとか関係なくね?って感じがしていますが、実質その通りでどこにあっても動きます。

XAML読み込みはどうなったのよ

こちらの顛末を書いておきます。

先ほどのCustomUIみたいなクラスを大量にはやすことでこんなxamlが記述できます。

<CustomUI x:Class="NereidTestAddin.RibbonData"
             xmlns="clr-namespace:artfulplace.Nereid;assembly=artfulplace.Nereid"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:NereidTestAddin">
    <Ribbon>
        <Tabs>
            <Tab IdMso="TabAddIns">
                <Group Id="MyGroup" Label="My Group">
                    <Button Id="aaaa" Label="aaaa" />
                </Group>
            </Tab>
        </Tabs>
    </Ribbon>
</CustomUI>

で、これを普通にXMLとして作るだけです。
作るとこんな感じになります。

<?xml version="1.0" encoding="UTF-8"?>
<customUI xmlns="http://schemas.microsoft.com/office/2006/01/customui" onLoad="Ribbon_Load">
  <ribbon>
    <tabs>
      <tab idMso="TabAddIns">
        <group id="MyGroup" label="My Group">
          <button id="aaaa" label="aaaa" />
        </group>
      </tab>
    </tabs>
  </ribbon>
</customUI>

ええまあいろいろ大変でしたが、読み込めない理由がただのタイプミスだったとかそんな話しかあとは残ってない…
上のを読み込むと普通にaaaaってボタンが増えます。もう画像はいいよね…


というわけでXAMLで書ける何かを作っている話でした。
文章が崩壊しまくっていてブログ書かなすぎの弊害を受けている…
それ以上にこれブログに書く意味あったのか大変に怪しい…

github.com
上の何かでそれっぽい作業をしてます。心優しい方はDependencyPropertyをはやしてくれると大変助かります。。。。。
ぶっちゃけすでに飽きかけているのもあり、それ以上にDataContextがFrameworkElement以上にしかないことを知ったり、UIの更新にはInvalidateでリボンそのものを読み込み直すしかなかったりでXAMLでやる意味あるのか?という疑問が出てきている…

この辺で

Baldr Heartの感想とか

久々に書く記事がこれで申し訳ない感じがあるけどここ最近ゲームしかしてないし…

というわけで先週にはBaldr Heartクリアしてましたが適当に感想とか書いとこうかなぁと
products.web-giga.com

特にそういう要素について書きませんけど18歳未満はあれなげな感じなので、そういうのに興味がないとか年齢的にあれとかあれとかだったら閉じましょう。ネタばれへの考慮もしません
あとそんなにいい感想を書かないのであれ

続きを読む

Office 2016 ver 16.0.7167.xとPowerPoint Zoomについて

PowerPoint 2016はアップデートでどんどん神がかっていく…

というわけでInsider向けにアップデートが来ていたらしいです。7/23に
まったく気づいていませんでした。ラボ畜は人を狂わせる

フォーラムの通知はこれ
http://answers.microsoft.com/en-us/office/forum/office_insider-registration/announcing-july-insider-update-1607167xxxx-for/a4c6159a-833e-43b8-9517-6ded4281592b
Office BlogでのJuly Updateの詳細はこれ
New to Office 365 in July—new intelligent services Researcher and Editor in Word and more - Office Blogs

変更点をフォーラムから引っ張ってくると
・自動ナビゲーション機能としてZoomを追加したよ!
・引用をWord上で行えるResearcher機能を追加したよ
Excel 2016からLocalのPowerBIにパブリッシュできるように
・Get&Transform周り?か何かで日付/時間変換を改良うんぬん
Outlookに@を付けたよ
Outlookで旅行の管理が楽になった
Outlookにいいアイデアがあったらフィードバックのサジェストから送れるよ
・Docs.comにOfficeから直接アップロードできるように

Outlook周りはよくわからないので誰か頼みました
Zoomは後で書きます

ResearcherはWordの新機能としてキーワードを検索してそれをドラッグアンドドロップで引用できるぜ!みたいな機能です。
便利そうではありますがあくまでペインで開くしページの詳細はブラウザに飛ぶので結局ブラウザでよくね?ってなりそう
なんとなくWordがTeXの立場を狙ってるんかなぁという感じではあります

PowerBI周りはサブスクリプションがないです。PowerBI.comじゃなくても大丈夫とかそんなんだと思います

Docs.comへのアップロードは使ってる人なら便利なのかなぁという気がします。私は結局PowerPoint OnlineならOneDrive埋め込みでよくねみたいな感じになりました

Wordが結構変わってる気がします。詳しい調査は今度します…(最近Wordを使う機会がない…)

PowerPointのZoomについて

で、まあZoomです。MorphもすごかったですけどZoomもなかなかやばい

Zoomは単純に言えば各セクションなりスライドのトップスライドへと遷移できる親スライドを作成する機能です
すごいめっちゃわかりづらい!

動画を適当に貼っておきます(14.9MB)

(↑なんかうまく動いてない?のでクリックしてOneDriveで見てください…)
とてもよさげでしょう?
では実際に作っていきましょう

適当にスライドを作成してInsert→Links→Zoomを選びます。
このとき3つありますが、Summary ZoomとSection Zoom, Slide Zoomの2つとの間には機能的に違いがあります。
今回はSummary Zoomを使います

f:id:fantasticswallow:20160801195848j:plain

するとこんな感じで使うスライドを選べるようになります。Summary Zoomでは選択したスライドAと選択したスライドCの間のスライドBはスライドAをトップスライドとするセクションに結合されます。
(画像でいう2枚目と4枚目のスライドはそれぞれセクションになり、3枚目のスライドは2枚目のセクションとなる。もちろん複数スライドがあればそのようになる)

今回は2,3,4枚目を選択して追加します。するとこのように新しいスライドが追加されます
f:id:fantasticswallow:20160801200211j:plain

まず注目してほしいのは左側です。選択スライドごとにセクションが分割されています。ここが割と大事だったりします
そもそもZoomの核となる機能は指定したスライドへの遷移です。その遷移の際にアニメーションをつけれるというのがZoomです
Zoomの優れている点は、通常同じことをすればZoomを含むスライドから遷移すると、そのあとにあるスライド、セクションに到達しますがZoomで遷移するセクションはスキップされて遷移する点です
例えば通常のセクションA、ZoomセクションB、Zoomで遷移するセクションC,D、通常セクションEという順で並んでいたとします。
(Return to ZoomをONという設定の場合)
上のスライドの遷移は A→B→C→B→D→B→E という順になります
(Return to Zoomを使わなければA→B→C→D→E)

またZoomの各スライドをクリックするとそのセクション、スライドに遷移します。
そのため特定のスライドだけ見たい!と言われてもすぐに飛べたりします。

ところでSummary ZoomとSection Zoom/Slide Zoomの違いですが、Summary Zoomはスライドをセクション分割して遷移するZoomを作成しますが、Section ZoomとSlide Zoomはスライドに対して何かをするわけではなく、Zoomのみを作成します。
ただしSlide Zoomは特に複雑なのですが、スライドの位置関係によってはZoomを使うとうまく遷移できません
(例えばZoomスライドA、普通のスライドB、Zoomで遷移するスライドC,D,Eがある場合、Aから通常遷移すると→B→C→D→Eと行きますが、Zoomで遷移するとA→C→D→Eとなってしまう。Return to Zoomを有効にしても無視されるので注意(E→Bとなるがそのままスライドショーが終了する))
Zoomは対象スライドを連続で並べて使用するのが吉です。適当にやると本当におかしくなる…


個人的にはZoomは使ってスライド作ってみたいなぁという感じがします
とはいえMorphより派手なので結構使いどころが難しそう
アジェンダに使うと面白いかなぁという気もします
どこかでまたLTかなぁ
とりあえず最近あまりOfficeを触れていないのでまた触っていきたいなぁというところ

この辺で

Windows向けSlackクライアント、FluffyFromageの開発版を公開します

ようやく日の目を見ることになった…長かった…(触ってない時期が)

というわけで2月だか3月から作っていたWPFなSlackクライアントであるFluffyFromageの"開発版"を公開します。
正式版?そんなものはないというのはさておき、個人的にまだ正式に出すつもりはないというだけのやつです。
単純に言えば機能が明らかに足りていないという状態
じゃあなんでそんなもんだすんだっていうと、必要な機能がよくわからないというのが感想だからです。

そもそもElectron版なSlackのアプリの完全な代替となることを目的としていません。
あくまでメッセージをパッと確認したりそれにレスポンスを行うことができる程度のものがあればいいなぁという形で作っています
とはいえそれしかできないのも大変微妙なので適当に触ってもらって「この機能がほしい!」みたいなのが分かったらいいなぁという

まあはい、モチベーションが不足気味ということです。
主に2か月まったく触らないでいたら何一つ思い出せなくなってしまったのが問題
若干そのあたりを変えたいなぁということで公開することにしました

で、肝心のアプリケーションですがこんな感じです。

f:id:fantasticswallow:20160722200308p:plain

f:id:fantasticswallow:20160722200330p:plain

ザ・開発途中…

Modern UI for WPFが結構いい感じだったのでこれで攻めてみました。若干戸惑いましたがかなりよいかなぁと
機能的には
・起動時メッセージ取得
・Real Time Messagingによるリアルタイム取得
・普通にポストとか
・絵文字入力支援(バグある)
とかそんな感じです

ダウンロードは https://dl.dropboxusercontent.com/u/12260653/FluffyFromage-0-3b.zip からどうぞ(Dropbox...)

追記(7/30):Windows 7だと動かないという情報をいただいて調べた結果、なぜかWinRTのアセンブリを参照していて、なおかつ使ってもいないのに型を読み込んでいたので該当部分を削除しました。たぶん動くはず(Win7な環境がない…)
直し忘れて#e7のままですがダウンロードしたファイルが0-3bなら問題ないはずなので…


ちょっと長くなりましたが、上のもろもろを見てよさそう!って思ったらぜひ使ってほしいです。ついでに感想をください…
あっ「使い物にならない」だけだと私も知ってるので書かなくて大丈夫です
どうなったら使える、そもそも根本的に合わないその他あると思いますが、対応できる内容であればこちらも頑張りますので…

ちなみにバージョンですが、そもそも普通の人間はバージョンを見てもよくわからないのでは?って思ったのでリリース回数でつけることにしました。
現在は#e7です(devcussionで過去に何回か出したのを継続)
うまく正式リリースまで行ければいいなぁというあれ

この辺で

UWPのMessageWebSocketでSlackのReal Time Messagingにつなぐとき

おーーーっとふぁぼツバメ選手助走をつけてからの渾身の腹パンをMessageWebSocketに打ち込んだぁぁぁ!
はい、どうでもいいですね

というわけでタイトル通りです。UWPでReal Time Messagingにつなぎたいんだけど!っていう話ですが、MessageWebSocketでつなぐのがたいへんクソだったという話です
マジでわけわからなすぎる。そもそも情報がなさすぎる。助けてUWPのプロ

Real Time Messagingにつなぐのには

rtm.start method | Slack
Slackのrtm.startメソッドたたいて、戻ってきたデータのurlを用いてWebSocketで接続するだけです。

ちなみにWPFのときはwebsocket-sharpを使っています。
github.com
めっちゃ素直でいい子です。残念ながらUWPには対応していませんが…

で、UWPのときはMessageWebSocketとかいうのを使います
MessageWebSocket Class (Windows)
つなぎ方は最高に不可解です。もう嫌だ

MessageWebSocket.ConnectAsyncのやり方について

いつも通りダメパターンから書いていきましょうね

MessageWebSocketに指定したWebSocket Uriで接続して、MessageReceivedの結果をIObservable<string>で返すメソッドConnectAsyncを考えます。
とりあえず次のような感じで書いてみましょう

using System.Reactive.Linq;
using Windows.Networking.Sockets;
using System.IO;
using Windows.Storage.Streams;
using System.Threading.Tasks;
using System.Reactive.Subjects;

// ~~~~~~~

private MessageWebSocket webSockets { get; set; }
private DataWriter dataWriter { get; set; }

public async Task<IObservable<string>> ConnectAsync(string url)
{
    webSockets = new MessageWebSocket();
    webSockets.Control.MessageType = SocketMessageType.Utf8;

    webSockets.Closed += WebSockets_Closed;

    var observable = Observable.FromEventPattern(webSockets, "MessageReceived").Select(x => {
        var e = ((MessageWebSocketMessageReceivedEventArgs)x.EventArgs);
        using (var reader = new StreamReader(e.GetDataStream().AsStreamForRead()))
        {
            return reader.ReadToEnd();
        }
    });

    await webSockets.ConnectAsync(new Uri(url));
    dataWriter = new DataWriter(webSockets.OutputStream);

    return observable;
}

まあ普通のFromEventPatternです。FromEventは使い方がわからず…
とりあえず上のコードは返したobservableをSubscribeしてもイベント登録が行えていないらしく何も飛んできません。これはUWPの仕様?
FromEventなら動くぜ!って方はご連絡をください…

というわけでSubject<T>を使って実現してみましょう
このときも次のように書くことはできません。(以下のコードはConnectAsyncのみ記述)

public async Task<IObservable<string>> ConnectAsync(string url)
{
    webSockets = new MessageWebSocket();
    webSockets.Control.MessageType = SocketMessageType.Utf8;

    webSockets.Closed += WebSockets_Closed;
    
    var messageSubject = new Subject<string>();
    
    await webSockets.ConnectAsync(new Uri(url));
    dataWriter = new DataWriter(webSockets.OutputStream);

    webSockets.MessageReceived += (sender, e) =>
    {
        using (var reader = new StreamReader(e.GetDataStream().AsStreamForRead()))
        {
            messageSubject.OnNext(reader.ReadToEnd());
        }
    };

    return messageSubject;
}

このコードは、「MessageReceivedのAddHandlerの部分でInvalidOperationException」を起こします
何を言ってるのかよくわからないって? 私も知らんし…むしろどういう記述してたら+=のところで落ちんの…
推測だけだとConnectAsyncの時点でMessageReceivedのイベントハンドラを囲い込んで実行する、とかそんな感じでしょうか。どっちにしてもどこに書いてあるんだ

というわけで最終的には以下のコードが動きます。

public async Task<IObservable<string>> ConnectAsync(string url)
{
    webSockets = new MessageWebSocket();
    webSockets.Control.MessageType = SocketMessageType.Utf8;

    webSockets.Closed += WebSockets_Closed;

    var messageSubject = new Subject<string>();
    webSockets.MessageReceived += (sender, e) =>
    {
        using (var reader = new StreamReader(e.GetDataStream().AsStreamForRead()))
        {
            messageSubject.OnNext(reader.ReadToEnd());
        }
    };
    
    await webSockets.ConnectAsync(new Uri(url));
    dataWriter = new DataWriter(webSockets.OutputStream);

    return messageSubject;
}

というわけでコードの順序を間違えると落ちることを覚えておきましょう

Pingを送ろう

さて、Real Time Messagingでは一定時間通信できていなかったらpingを送って通信が持続しているか確認しろと書かれています。
MessageWebSocketではちゃんと送信もできますので(当然だ)そちらも実装していきましょう
こちらも落ちるコードの実例がいくつもあります。見ていきましょう
…いうほどなかった

送るときのメソッドはstringを受け取ったらWebSocketで送るSendAsync(string)を実装します
usingは上のusingで足りるはず(System抜く人はいないだろう…)

public async Task SendAsync(string text)
{
    using (var dataWriter = new DataWriter(webSockets.OutputStream))
    {
        dataWriter.WriteString(text);
        await dataWriter.StoreAsync();
    }
}

まずは落ちるパターン、usingで囲むです
これをするとOutputStreamが閉じます。2回目以降は送れません。閉じてるって言われて落ちます
とはいえこの記事のコードだと接続時にDataWriterを作成して退避しているのでこれをする人はいないでしょう…

というわけでこうなります

public async Task SendAsync(string text)
{
    dataWriter.WriteString(text);
    await dataWriter.StoreAsync();
}

このときStoreAsyncではなくFlushAsyncだと動きません。
なんだすんなりいくじゃん?ってなるでしょう?
このとき「不正なデータを転送するとその時点でWebSocketが切断」されます
おそらくなんですが通信エラーを引くと何も言わずに死んでるのでは…

まじめにデータが正しいかどうかは確認した方がいいです。できるならWPFのほうで同じping文字列送信して動くことを確認しましょう。
私はそれでようやく気付きました。変な動きのときはそちらに気を付けましょう。

ちなみに私はこんなんを毎回送りつけています

private const string pingText = "{ \"id\": 1234, \"type\": \"ping\"}";

確認用にでもどうぞ


というわけでまあはい、わけがわからないよ…という感想です。
もうかかわりたくない。というかMessageWebSocketで調べても簡単なサンプルみたいなのしか出てこないのが本当に困った

ラボ畜ワークは今週はさほど多くないので自分のプログラミングを進めたいなぁというところ

この辺で

ライブラリを.NET StandardにしたらDataContractがないって言われたとき

プログラミングしな過ぎて久々にプロジェクトを開いたら理解ができなかった

Portable Class Libraryでライブラリを作っていたのですが、最近は.NET Standard Libraryとかいうよさげなバージョンがあるそうです
というのをC#ググるサイトのスライドを見て知りました
ufcpp.net

上の一番最初のスライドですね。他も面白いのでついでに見ましょう

さて、私の手元にも無駄にPortable Class Libraryで作られているものがあるので.NET Standardにするか~と思ったのですが(どこで使うのか不明)、.NET Standard 1.1に変えてみたところエラーだらけに
こんな感じのコードだったのですがどの辺が悪いのかすぐに理解できなかった

[DataContract]
public class Team
{
    [DataMember(Name = "id")]
    public string Id { get; set; }

    [DataMember(Name = "name")]
    public string Name { get; set; }

    [DataMember(Name = "domain")]
    public string Domain { get; set; }

    [DataMember(Name = "email_domain")]
    public string EmailDomain{ get; set; }

    [DataMember(Name = "icon")]
    public Icons Icon { get; set; }
}

まあ普通のDataContractなクラスですね
これのDataContractAttributeとDataMemberAttributeがないと怒られるわけですよ。なぜPCLで書けるコードが.NET Standardで書けないんだ、という感じです

と思って調べてたらこんなNuGetパッケージがありました。
NuGet Gallery | System.Runtime.Serialization.Primitives 4.1.1
ここに.NET Standard 1.0以上に対応すると書いてあるので、まあつまるところ足りなかったらこれを入れろということなのでしょう。むしろどこでそれを察知すればよかったんだ…

System.Runtime.Serialization.Jsonもないのでおそらく使用率が低い標準ライブラリについて使う場合はNuGetから落とす必要があるようです。一歩学習したぞ


ってだけの記事です。誰向けなんだ

ようやくプログラミング欲が復活してきたのでいろいろ進めたいところ
そろそろ埃をかぶってきたアプリケーションとか世に送り出したい…

この辺で

Office 2016 ver 16.0.7070.2019が出てたらしい

なんというか何かをするためのメンタルが足りない

そんなこんなでラボにこもらされる時間が長すぎてそろそろ精神的にダメになってきた私です
まあ私のことはどうでもいいですね。Officeの話だ

昨日?あたりに16.0.7070.2019が出たようです
フォーラムの記事はこれ
http://answers.microsoft.com/en-us/office/forum/office_insider-registration/announcing-insider-build-16070702019-for-office/ae697df5-73d4-47d9-81a4-8ba21dabd0d9

適当に追ってみると
PowerPoint, Word, OutlookにText Highlightingの追加(?)
VisioへのDrawタブの機能追加
ExcelにShape Recognitionの追加
ExcelのPivotTableのパフォーマンス向上?

らしいです。Shape Recognitionは前に書いた気がするので(というかこの機能2010くらいからあるらしい)Excelでも使えるようになってうれしい!程度かなぁ
Shape Recognitionについては下の記事を見るとよさげ
support.office.com

とりあえず今回はText Highlightingについて取り上げてみましょう

Text Highlightingについて

まあぶっちゃけ蛍光ペンなんですが。というかこんな感じの色がつく機能あった気がするんですが…?

f:id:fantasticswallow:20160624224905p:plain

画像のような感じで文字の背景を塗りつぶすことができます。
やり方についても、Text Highlightingを選択した状態でハイライトする文字を選択するだけです。
動画にするとこんなの
f:id:fantasticswallow:20160624225716g:plain

文字の色を変える以外の手段で強調しやすくなったのは便利そうだなーという感じ
ただまあ相変わらず入力モードに戻すのが手間という
もうちょっと切り替えが楽ならいいんですけども


というわけでなかなか新しいすごい機能は来ませんが、細かいところでよくなってるなぁという感想
Office 2016はやはりMorph襲来が最高峰だったんかなぁ

もう少し開発とかにかけれる時間を増やしたい

この辺で