2014年6月25日水曜日

リボンUI

個人的には、WinFormsではなくWPFを使うモチベーションとして、「リボンUIが使える」というものが挙げられます。

.NET4.0時代からMicrosoftはRibbonのライブラリを自社のページで公開していましたし、.NET4.5からはSystem.Windows.Controls.Ribbon名前空間内にRibbonクラスが組み込まれました。これにより、特に別途外部ライブラリを追加しなくてもリボンインターフェースを使ったアプリケーションが作れるようになりました。

そもそもWin32API時代から身からすると、さまざまなUIのコントロールはOS、もしくはそれに準ずるフレームワークが提供するのが常識でした(IEに新しいUIのコントロールが付いてきた時代を思い返せばとても懐かしいと思える人もいるかもしれません)。
そうやって多くのUIを共通パーツとしてDLLに入れてプログラマーに提供することで、アプリケーションからOSまで含めたシステム全体のサイズを小さくすることができ、ユーザーにとっても異なるアプリケーションで似たような一貫性のあるUIで操作できるというメリットが生まれます。
しかし、現代ではHDDやSSDの大容量化が進み、システム全体のサイズを気にするような時代でもありませんし、.NETなんかはかなりソフトウェアをパッケージングして提供する仕組みが(言語としてや、Nugetなどのサービスとしての両面から見て)とても優れています。
そのせいもあってか、Microsoftは最近あまりユーザーインターフェースの開発に積極的じゃないイメージがあります。基本的なボタンやコンボボックスなどのコントロールはさすがに提供してくれますが、WinFormsやWin32APIにあってWPFに無いコントロールもちらほら見かけます。さらに、IEやOfficeなどのMicrosoftのアプリケーションの中核商品に使われているコントロールも、昔はIEの新バージョンをインストールすれば使えるようになりましたが、今はあまり配布しているようには見えません。

しかし、リボンUIのライブラリはなぜかちゃんと提供してくれていたんですね。
やっぱり、当初VistaやOffice2007と同時に導入されてものすごく叩かれたからなんですかね。できるだけ多くのアプリケーションにリボンUIを使ってもらえれば、それだけリボンUIが世間に受け入れらていくものになるでしょう。


さて、それではリボンUIを導入してみましょう。

WPFのプロジェクトを作ります。私の場合はLivetのテンプレートから作ります。.NET4.5にすることを忘れないで下さい。


こんなかんじでウィンドウが出てきました。
次に、System.Windows.Controls.Ribbonへの参照を追加します。


つづいてソースコードを改造します。
と言っても非常に単純で、ウィンドウの親クラスがWindowからRibbonWindowになるだけです。
MainWindow.xamlとMainWindow.xaml.csの当該箇所を修正します。



あっれ~~~~~?????
なんかウィンドウ枠が小さくなってすごくダサくなっています。この現象が起こったのは.NET4.5からで、.NET4.0向けのライブラリでは問題ありませんでした。
まあそもそもリボンウィンドウの日本語記事があまり多くないのもあるのですが、これに関する日本語の情報は私が調べた限りでは皆無、英語の掲示板とかを見ても、結局有用な解決方法までは出てきませんでした。
例えばこのスレでは、最後にMicrosoftのWPF開発チームが書き込みをしていますが、もっと優先度が高い仕事はたくさんあるし、もしこれが本当にバグだと思うなら再現に必要な情報をもっと出せみたいなことを言っているようです。えー…再現できない環境とかあるのかよ…。

私が実際に条件を変えてコンパイルして実行してみた限りだと…
.NET4.0向けのライブラリ+.NET4.0=通常表示
.NET4.5内蔵ライブラリ=枠が細くなる
.NET4.0向けのライブラリ+.NET4.5=枠が細くなる
という再現結果になり、.NET4.5は使うなってことになってしまいました。
なんかこういうのは気に食わないですねえ。新しい機能が使えなくなってしまいます。
どちらかというと私はAppleよりMicrosoft信者ですが、こういうデザインに関する根本的な問題がでてきたら「Appleなら…」という気持ちも出てきてしまいます。

そのような中途方に暮れていると、こんなライブラリを発見しました。

Fluent Ribbon Control Suite

デザインがとても忠実にOffice2010のスタイルを再現しています。
これはもう公式ライブラリを捨ててこれを使うしか無いんじゃないか!?
ドキュメンテーションも結構しっかりと書いてあったりします。サンプルコードも充実しています。

というわけで導入してみました。
導入でつまずいたところは、最新のLivetのプロジェクトテンプレートだとなんかのファイルで競合を起こしてうまくビルドができない点ですかね。
仕方がないので、ただのWPFプロジェクトを立ち上げてから、Fluent RibbonとLivetの両方をNuget経由で入手しました。

Livetの流儀でウィンドウをViewsディレクトリ下に入れるの好きなので、デフォルトでついてくるMainWindow.xamlは削除し、Viewsディレクトリの中にMainWindow.xamlを入れます。そうすると、スタートアップウィンドウのパスが変わるので、App.xamlを修正してやります。
ついでに、 テーマのリソースを指定してやる必要があるので、それを追加します。

<Application x:Class="RibbonTest.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             StartupUri="Views\MainWindow.xaml">
    <Application.Resources>
        <ResourceDictionary Source="pack://application:,,,/Fluent;Component/Themes/Office2010/Silver.xaml" />
    </Application.Resources>
</Application>

あとは、標準のリボンライブラリとほとんど同じです。
 親クラスをWindowからFluent.RibbonWindowにしてやって、一通りのコントロールをXAMLで記述します。こんなかんじです。

<Fluent:RibbonWindow x:Class="RibbonTest.Views.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
        xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
        xmlns:l="http://schemas.livet-mvvm.net/2011/wpf"
        xmlns:v="clr-namespace:RibbonTest.Views"
        xmlns:vm="clr-namespace:RibbonTest.ViewModels"
        xmlns:Fluent="clr-namespace:Fluent;assembly=Fluent"
        Title="MainWindow" Width="640" Height="480">
    
    <Window.DataContext>
        <vm:MainWindowViewModel/>
    </Window.DataContext>
    
     <i:Interaction.Triggers>     
        <i:EventTrigger EventName="ContentRendered">
            <l:LivetCallMethodAction MethodTarget="{Binding}" MethodName="Initialize"/>
        </i:EventTrigger>

        <i:EventTrigger EventName="Closed">
            <l:DataContextDisposeAction/>
        </i:EventTrigger>
    </i:Interaction.Triggers>
    
    <DockPanel>
        <Fluent:Ribbon DockPanel.Dock="Top">
            <Fluent:Ribbon.Menu>
                <Fluent:Backstage Header="Menu" >
                    <Fluent:BackstageTabControl>
                        <Fluent:BackstageTabItem Header="New" />
                        <Fluent:BackstageTabItem Header="Open" />
                    </Fluent:BackstageTabControl>
                </Fluent:Backstage>
            </Fluent:Ribbon.Menu>
            <Fluent:RibbonTabItem Header="Home">
                <Fluent:RibbonGroupBox Header="Group1">
                    <Fluent:Button Header="Button1" />
                    <Fluent:Button Header="Button2" />
                </Fluent:RibbonGroupBox>
            </Fluent:RibbonTabItem>
            <Fluent:RibbonTabItem Header="Insert">
                <Fluent:RibbonGroupBox Header="Group2">
                    <Fluent:Button Header="Button3" />
                    <Fluent:Button Header="Button4" />
                </Fluent:RibbonGroupBox>
            </Fluent:RibbonTabItem>
        </Fluent:Ribbon>
        <TextBox />
    </DockPanel>
</Fluent:RibbonWindow>

これを起動するとこんな感じになります。


見事にそれっぽいリボンUIができました。
ついでに、Menuを押すとこのような画面に遷移します。


ウッヒョオオオオオォォォォォォ!!めっちゃOffice2010っぽい!!
Microsoftの標準ライブラリはOffice2007スタイルで、メニューボタンを押すとドロップダウンメニューが出てくるだけなんですよね。

ただ1つ、なんかフォントが小さいですね…。
FontSizeとかLayoutTransformとかでいじってみましたが、どれも満足行く結果は得られずじまいでした。
ただ、テーマという概念があるっぽいので、どうにかできないかちょっと検討してみます…。

0 件のコメント:

コメントを投稿