AvalonDockについて

作成中のアプリのサイドバーにExtenderコントロールでサブ情報を表示するようにしていたが、どうにも見た目が気に入らないのでIDEみたいなドッキングウィンドウ(?)にしてみたくて色々調べていると有名どころを見つけたので利用してみた。

1.インストール。


2.ソースコード
Windowのところに
「xmlns:xcad="http://schemas.xceed.com/wpf/xaml/avalondock"」を追加しておいて、下記のようなソースを記載

            <xcad:DockingManager
                           AllowMixedOrientation="True"
                           BorderBrush="Black"
                           BorderThickness="1" >
                <xcad:DockingManager.DocumentHeaderTemplate>
                    <DataTemplate>
                        <StackPanel Orientation="Horizontal">
                            <Image Source="{Binding IconSource}" Margin="0,0,4,0" Height="5" Width="5" MaxHeight="5" MaxWidth="5" Stretch="None" />
                            <TextBlock Text="{Binding Title}" />
                        </StackPanel>
                    </DataTemplate>
                </xcad:DockingManager.DocumentHeaderTemplate>
                <xcad:LayoutRoot x:Name="_layoutRoot">

                    <xcad:LayoutRoot.LeftSide>
                        <xcad:LayoutAnchorSide>
                            <xcad:LayoutAnchorGroup>
                                <xcad:LayoutAnchorable Title="プロジェクト" ContentId="Project" IconSource="images/document.png" CanClose="False" CanHide="False" >
                                    <StackPanel>
                                        <ItemsControl x:Name="tSxtack" ItemsSource="{Binding Projects}">
                                            <ItemsControl.ItemsPanel>
                                                <ItemsPanelTemplate>
                                                    <StackPanel Orientation="Vertical">
                                                    </StackPanel>
                                                </ItemsPanelTemplate>
                                            </ItemsControl.ItemsPanel>
                                            <ItemsControl.ItemTemplate>
                                                <DataTemplate>
                                                    <DockPanel>
                                                        <Expander Style="{DynamicResource ExpanderCustomStyle}" >
                                                            <Expander.Header>
                                                                <StackPanel Orientation="Horizontal">
                                                                    <CheckBox Content="{Binding Name}" IsChecked="{Binding Showing}" ></CheckBox>
                                                                    <Button Name="btnProjectDetail" Content="..." Background="Transparent"  Width="25" BorderBrush="Silver"  BorderThickness="0.5" FontFamily="MS Gothic" Click="btnProjectDetail_Click"/>
                                                                </StackPanel>
                                                            </Expander.Header>
                                                            <StackPanel Margin="25,0,0,0" >
                                                                <TextBlock Text="{Binding StartDay,StringFormat=開始日:{0:yy/MM/dd}}"></TextBlock>
                                                                <TextBlock Text="{Binding EndDay,StringFormat=終了日:{0:yy/MM/dd}}"></TextBlock>
                                                                <TextBlock Text="{Binding Info}"></TextBlock>
                                                            </StackPanel>
                                                        </Expander>
                                                    </DockPanel>
                                                </DataTemplate>
                                            </ItemsControl.ItemTemplate>
                                        </ItemsControl>
                                    </StackPanel>
                                </xcad:LayoutAnchorable>
                                <xcad:LayoutAnchorable x:Name="AvalondockDelayCard" Title="遅延カード" ContentId="DelayCardList" IconSource="images/document.png" CanClose="False" CanHide="False" >
                                    <ListView Name="lvLimitCardList" ItemsSource="{Binding DelayCardList}">
                                        <ListView.View>
                                            <GridView>
                                                <GridViewColumn Header="タイトル" Width="120" DisplayMemberBinding="{Binding CardTitle}" />
                                                <GridViewColumn Header="メンバー" Width="50" DisplayMemberBinding="{Binding Members}" />
                                            </GridView>
                                        </ListView.View>
                                        <ListView.GroupStyle>
                                            <GroupStyle>
                                                <GroupStyle.ContainerStyle>
                                                    <Style TargetType="{x:Type GroupItem}">
                                                        <Setter Property="Template">
                                                            <Setter.Value>
                                                                <ControlTemplate>
                                                                    <Expander IsExpanded="True" >
                                                                        <Expander.Header>
                                                                            <StackPanel Orientation="Horizontal">
                                                                                <!-- GroupItemのNameプロパティをバインド -->
                                                                                <TextBlock Text="{Binding Name}" FontWeight="Bold" Foreground="Gray" FontSize="22" VerticalAlignment="Bottom" />
                                                                                <TextBlock Text="{Binding ItemCount}" FontSize="22" Foreground="Green" FontWeight="Bold" FontStyle="Italic" Margin="10,0,0,0" VerticalAlignment="Bottom" />
                                                                                <TextBlock Text=" item(s)" FontSize="22" Foreground="Silver" FontStyle="Italic" VerticalAlignment="Bottom" />
                                                                            </StackPanel>
                                                                        </Expander.Header>
                                                                        <ItemsPresenter />
                                                                    </Expander>
                                                                </ControlTemplate>
                                                            </Setter.Value>
                                                        </Setter>
                                                    </Style>
                                                </GroupStyle.ContainerStyle>
                                            </GroupStyle>
                                        </ListView.GroupStyle>
                                    </ListView>
                                </xcad:LayoutAnchorable>
                            </xcad:LayoutAnchorGroup>
                        </xcad:LayoutAnchorSide>
                    </xcad:LayoutRoot.LeftSide>


                    <xcad:LayoutPanel Orientation="Horizontal">
                        <xcad:LayoutAnchorablePane DockWidth="200">
                            <xcad:LayoutAnchorable ContentId="MainWindow" Title="メイン画面" CanHide="False" CanClose="False" CanFloat="True" AutoHideWidth="240" CanAutoHide="False" IconSource="images/dokking.png">
                                <DockPanel>
                                    <ListView ItemsSource="{Binding CardLists,Mode=TwoWay}" ScrollViewer.VerticalScrollBarVisibility="Hidden" Style="{StaticResource NormalListView}">
                                        <ListView.ItemsPanel>
                                            <ItemsPanelTemplate>
                                                <StackPanel Orientation="Horizontal"/>
                                            </ItemsPanelTemplate>
                                        </ListView.ItemsPanel>

                                        <ListView.ItemTemplate>
                                            <DataTemplate>
                                                <DockPanel Height="{Binding ActualHeight,RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListView}}}">
                                                    <control:CardList Margin="10" CardChanged="CardList_CardChanged"
                                          PreviewMouseLeftButtonDown="CardList_PreviewMouseLeftButtonDown"
                                          PreviewMouseMove="CardList_PreviewMouseMove"
                                          PreviewMouseUp="CardList_PreviewMouseUp"
                                          PreviewDrop="CardList_PreviewDrop"
                                          AllowDrop="True"
                                          PreviewDragEnter="CardList_PreviewDragEnter"
                                          PreviewDragLeave="CardList_PreviewDragLeave"
                                          />
                                                </DockPanel>
                                            </DataTemplate>
                                        </ListView.ItemTemplate>
                                    </ListView>
                                </DockPanel>
                            </xcad:LayoutAnchorable>
                        </xcad:LayoutAnchorablePane>
                    </xcad:LayoutPanel>

                </xcad:LayoutRoot>
            </xcad:DockingManager>

3.結果


本当はDataGridとかもWPF Extended Toolkitにあるものを使おうかと思ったけど各機能の資料とかサンプルが見つけられなかったので早々に諦めた。

早く公開できるレベルまで仕上げたい・・・・!!



DataGridTextColumnの半角文字のフォントについて

いろいろと落ち着いてきたので作りかけのあれこれを修正中。
プログラムを作るのが数か月以上空いていたので、改めていろいろとみているとZipファイルに圧縮するよりもsqliteを使ったほうがいいんじゃないかと思い直して修正したり、いろいろとしてみた。

それはさておき、DataGridコントロールのDataGridTextColumnに半角文字をバインドしたときにフォントがにじんで見える現象があったので、いろいろと対処してみた。

<修正前>

<修正後>



個人的な趣味で「MS ゴシック」を採用したかったのでTextOptionsを変更して対応をした。

                    <DataGridTextColumn Header="開始日" Binding="{Binding StartDay,StringFormat={}yy/MM/dd}" Width="80">
                        <DataGridTextColumn.ElementStyle>
                            <Style TargetType="{x:Type TextBlock}" >
                                <Setter Property="TextAlignment" Value="Center" />
                                <Setter Property="TextOptions.TextFormattingMode" Value="Display" />
                            </Style>
                        </DataGridTextColumn.ElementStyle>
                    </DataGridTextColumn>

TextOptions.TextFormattingModeを「Display」にすることで対応をした。
WindowのStyleでも設定してあるはずだが、上手く設定されなかった。

画面を拡大するとにじむ可能性があるが、そのことには今は目をつぶっておこうと思う。

久しぶりの更新

半年ぶりぐらいで更新。
勉強がてら、趣味グラマーとしてずっとちょこちょこ作ってきたアプリがそれっぽく出来てきた。

タスク内容をカードに書き込んでそのタスクを各担当者に振り分け看板方式のように状態が確認できるアプリ。
っていうか「Trello」みたいなアプリをオフラインで使いたかったから頑張ってみた。

共有フォルダに配置すれば複数人でも更新できる。ようになるはず。
保存されたデータはExcelやWordと同じようにZip形式にして拡張子の名前を変えて保存。
データを修正しているときには一時的にZipファイルを解凍し、隠しフォルダに展開して展開されたものを修正するような仕組みを実装してみた。

WPFならDataBindingで結構作れるなーと思いながら、頑張ってみた。

間違いなく、「Trello」が使える環境ならそっちのほうが便利。
(Trello使ったことないけど)

データをネットにアップしたくない場合とかには使える。かもしれない。

まぁWPFの勉強がてらのんびり作っていこうと思う。
上手くできたら、フリーで公開してみたいなぁと思ってみたり。

最後はProjectManagerと合わせ技ができたらいいなーと思ってはいるけどいつになるやら・・・。


WPFのお勉強

WPFで何らかのシステムを組む際のサンプルがあまりないので自分でいろいろ勉強してみる。

とりあえずログイン画面を作ってみた。


正直、販売管理システムやワークフローシステムなどを作るのにWPFが適しているかいまだに疑問ではある。
個人的には作ってみたいが、Windowsフォームのほうが安定しているし、メンバーも集めやすいし、アニメーションにこだわる必要など皆無。カーソルの動きやフォーカスの当て方などをいろいろ用途によって変える必要があるのでMVVMの分離も一癖ある。
特殊な独自コントロールもほとんど必要ない。
趣味でやるのならこだわってみてもいいが、原価やコストなどを考えるとWPFでやるメリットを見いだせない。

とかいろいろ考えているとお勉強にならないのでとりあえず趣味の範囲で組んでみようと思う。

まずコントロールの配置のためのパネルをどうするかで悩んだ。
Gridで綺麗に分けることができればいいが、項目一つ一つにGridの列や行を定義するのはめんどくさい。項目が増えた時に変更箇所も多い。

ということで、Gridをベースとしてその上にCanvasコントロールを配置することにした。

Login.xaml

<Window x:Class="SystemSample.win00_0000"
        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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:SystemSample"
        xmlns:control="clr-namespace:SystemSample.Controls"
        mc:Ignorable="d"
        Title="ログイン画面" Height="250" Width="450" Style="{StaticResource LoginWindowStyle}" WindowStartupLocation="CenterScreen">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="5"/>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="5"/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="5"/>
            <RowDefinition Height="*"/>
            <RowDefinition Height="5"/>
        </Grid.RowDefinitions>

        <Canvas Grid.Column="1" Grid.Row="1">
            <Label x:Name="lblTitle" Content="販売管理システム" Canvas.Left="10" Canvas.Top="10" Width="412" FontSize="32" FontFamily="Arphic Kaisho4JIS" VerticalContentAlignment="Center" HorizontalContentAlignment="Center" />
            <control:CsTextBox x:Name="txtUserID" Canvas.Left="167" Text="{Binding UserID}"   Canvas.Top="79"  Width="205" Style="{StaticResource NormalTextBox}"/>
            <control:CsTextBox x:Name="txtPass"   Canvas.Left="167" Text="{Binding PassWord}" Canvas.Top="108" Width="205" Style="{StaticResource NormalTextBox}"/>
            <Label x:Name="lblUserID" Content="ユーザーID" Canvas.Left="60" Canvas.Top="79" Width="105" Style="{StaticResource RequiredLabel}"/>
            <Label x:Name="lblPass"   Content="パスワード" Canvas.Left="60" Canvas.Top="108" Width="105" Style="{StaticResource RequiredLabel}" />
            <Button x:Name="btnLogin" Content="ログイン" Canvas.Left="280" Canvas.Top="159" Width="95" Style="{StaticResource NormalButton}" />
        </Canvas>

    </Grid>
</Window>

CsTextBoxはTextBoxを継承しただけの独自コントロール。
まだ何の制御も実装していない。
本当は数値入力のみとか半角英数字のみ入力できるようにするなど実装したいがそれはそのうちということで。

StaticResourceについてはプロジェクト内でスタイルを共通化したいので、App.xamlに定義を行っている。

・App.xaml

<Application x:Class="SystemSample.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:SystemSample"
             xmlns:controls="clr-namespace:SystemSample.Controls"
             StartupUri="win00_0000.xaml">
    <Application.Resources>


        <!--#region 色など-->

        <!-- Active状態の背景色 -->
        <SolidColorBrush x:Key="ActiveBackColor" Color="Yellow"></SolidColorBrush>
       
        <!-- テーマカラー -->
        <LinearGradientBrush x:Key="BlueGradientBrush" EndPoint="0,1" StartPoint="0,0">
            <GradientStop Color="#FFFFFFFF" Offset="0"/>
            <GradientStop Color="#FFC4DDFF" Offset="0.987"/>
            <GradientStop Color="#FFDEECFF" Offset="0.535"/>
        </LinearGradientBrush>
        <!--#endregion-->


        <!--#region 継承元のスタイル-->
        <!-- 継承元のフォームベースのスタイル -->
        <Style x:Key="WindowStyleBase" TargetType="Window">
            <Setter Property="FontFamily" Value="MS Gothic" />
            <Setter Property="FontSize" Value="15"/>
            <Setter Property="Background" Value="{StaticResource BlueGradientBrush}"></Setter>
            <Setter Property="WindowStyle" Value="SingleBorderWindow"></Setter>
        </Style>

        <Style x:Key="CsTextBoxStyleBase" TargetType="controls:CsTextBox">
            <Setter Property="FontFamily" Value="MS Gothic" />
            <Setter Property="FontSize" Value="15"/>
            <Setter Property="TextAlignment" Value="Left"/>
            <Setter Property="VerticalContentAlignment" Value="Center"/>
            <Setter Property="Height" Value="25"/>


            <Style.Triggers>
               
                <!-- フォーカス時の背景色 -->
                <Trigger Property="IsFocused" Value="True">
                    <Setter Property="Background" Value="{StaticResource ActiveBackColor}"></Setter>
                </Trigger>
            </Style.Triggers>

        </Style>

        <Style x:Key="TextBlockStyleBase" TargetType="TextBlock">
            <Setter Property="FontFamily" Value="MS Gothic" />
            <Setter Property="FontSize" Value="15"/>
            <Setter Property="TextAlignment" Value="Left"/>
            <Setter Property="VerticalAlignment" Value="Center"/>
            <Setter Property="Height" Value="25"/>
        </Style>

        <Style x:Key="LabelStyleBase" TargetType="Label">
            <Setter Property="FontFamily" Value="MS Gothic" />
            <Setter Property="FontSize" Value="15"/>
            <Setter Property="VerticalAlignment" Value="Center"/>
            <Setter Property="BorderBrush" Value="Black"/>
            <Setter Property="BorderThickness" Value="1"/>
            <Setter Property="Height" Value="25"/>
        </Style>

        <Style x:Key="ButtonStyleBase" TargetType="Button">
            <Setter Property="FontFamily" Value="MS Gothic" />
            <Setter Property="FontSize" Value="15"/>
            <Setter Property="BorderBrush" Value="Black"/>
            <Setter Property="BorderThickness" Value="1"/>
            <Setter Property="Height" Value="25"/>
            <Setter Property="Background" >
                <Setter.Value>
                <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                    <GradientStop Color="Gainsboro" Offset="0"/>
                    <GradientStop Color="#FF919191" Offset="1"/>
                    </LinearGradientBrush>
                </Setter.Value>
            </Setter>

           
            <Style.Triggers>

                <!-- フォーカス時の背景色 -->
                <Trigger Property="IsFocused" Value="True">
                    <Setter Property="Background" Value="{StaticResource ActiveBackColor}"></Setter>
                </Trigger>
            </Style.Triggers>

        </Style>

        <!--#endregion -->

        <!--#region 継承後のスタイル-->

        <Style x:Key="NormalLabel" TargetType="Label" BasedOn="{StaticResource LabelStyleBase}">
        </Style>
        <Style x:Key="RequiredLabel" TargetType="Label" BasedOn="{StaticResource LabelStyleBase}">
            <!--<Setter Property="Background" Value="#FFFF997B" />-->
            <Setter Property="Background" Value="#FF7BB7FF" />
        </Style>

        <Style x:Key="NormalTextBox" TargetType="controls:CsTextBox" BasedOn="{StaticResource CsTextBoxStyleBase}">
        </Style>
       
        <Style x:Key="NormalTextBlock" TargetType="TextBox" BasedOn="{StaticResource TextBlockStyleBase}">
        </Style>

        <Style x:Key="NormalButton" TargetType="Button" BasedOn="{StaticResource ButtonStyleBase}">
        </Style>

        <Style x:Key="LoginWindowStyle" TargetType="Window" BasedOn="{StaticResource WindowStyleBase}">
            <!--<Setter Property="Background">
                    <Setter.Value>
                        <LinearGradientBrush StartPoint="0,0" EndPoint="1,1">
                            <LinearGradientBrush.GradientStops>
                                <GradientStop Offset="0.0" Color="#FFB0FFB0"/>
                                --><!--<GradientStop Offset="1.0" Color="#FFD6D6D6"/>--><!--
                                <GradientStop Offset="1.0" Color="#FFB6DAA2"/>
                            </LinearGradientBrush.GradientStops>
                        </LinearGradientBrush>
                    </Setter.Value>
            </Setter>-->
        </Style>

        <Style x:Key="MenuWindowStyle" TargetType="Window" BasedOn="{StaticResource WindowStyleBase}">
        </Style>

        <!--#endregion-->

    </Application.Resources>
</Application>

Styleを継承するにはBaseOnを指定することでできる。
そのため、各コントロールのBaseStyleを定義し、それらを継承したスタイルを個別に作成するようにしている。
また、コントロールにフォーカスがあるときにはコントロールの背景色を変更したいので、Triggerを定義している。

どこかのタイミングでプロジェクトを上げたいと思う。

ガントチャート作成日記

久しぶり更新。
前回の稼働率の計算式でやった結果うまくいったのでバージョンを更新。


<DownLoad>
https://sites.google.com/site/mmbloguserfile/wai-bufairu/ProjectManager_Beta_0.0.0.3.zip

いろいろ忙しくて、少し間が空いてしまったので少しづつ思い出しながら直していこうと思う。

ガントチャート作成日記

土日を挟んだ進捗率の計算のメモ。


下記のようなスケジュールの場合で、進捗率が7割の場合はこんな感じで進捗が求まる気がする。

 水|木|金|土|日|月|火
 □|■|■|■|■|■|□

  ・土日は稼働日から外す。
  ・稼働日3日
  ・休日2日
  ・進捗率7割
  ・タスクのWidth:100

  ① 稼働予定の日数:3日
    進捗率の7割をかけると、2.1日分の作業が進んでいる
    そのため、月曜日を過ぎたところを進捗線したい。

  ② タスクの開始日に+1日ずつしていき、休日判定を行う。
    平日の場合は、稼働日変数に+1
    休日の場合は、休日日数を+1

    稼働日日数が2.1日を超えたらストップ。
    その時の休日日数を2.1日に足しこむ
    進捗線
       (2.1日+休日日数)÷5日(稼働日+休日)×タスクのWidth

これで線が引けるのではないだろうか!
後は実際に試してみてうまくいくかな・・・・。

LINQ to Objectについて

今日はLINQ to Objectをクエリ形式で利用してGroupBy句を作成。
GroupByで集計単位を指定しinto句でGroupオブジェクトを生成。

SQLと違ってまとまったGroupオブジェクトをループで取得できるので帳票を作りるときや総合計を出しつつ、明細を表示する場合などに便利。

WPFのDataGridでGroupingしたりTreeListViewなどで表示するといい感じに見える。

販売管理システムとかだと請求書などで鏡の部分を作成しつつ、明細の部分も表示するようなときに使いやすい。

    Private Sub btnGroup_Click(sender As Object, e As EventArgs) Handles btnGroup.Click
        Dim dtUri As New DataTable
        Dim drUriSample As DataRow

        ' ▼ 売上データ
        dtUri.Columns.Add(New DataColumn("売上No", GetType(Integer)))
        dtUri.Columns.Add(New DataColumn("売上日", GetType(String)))
        dtUri.Columns.Add(New DataColumn("得意先CD", GetType(String)))
        dtUri.Columns.Add(New DataColumn("商品名", GetType(String)))
        dtUri.Columns.Add(New DataColumn("売上数量", GetType(Decimal)))
        dtUri.Columns.Add(New DataColumn("売上金額", GetType(Decimal)))

        '   テストデータ
        drUriSample = dtUri.NewRow
        drUriSample("売上No") = 1
        drUriSample("売上日") = "20171031"
        drUriSample("得意先CD") = "00001"
        drUriSample("商品名") = "パソコン"
        drUriSample("売上数量") = 1
        drUriSample("売上金額") = 150000
        dtUri.Rows.Add(drUriSample)

        drUriSample = dtUri.NewRow
        drUriSample("売上No") = 2
        drUriSample("売上日") = "20171031"
        drUriSample("得意先CD") = "00002"
        drUriSample("商品名") = "マウス"
        drUriSample("売上数量") = 1
        drUriSample("売上金額") = 3000
        dtUri.Rows.Add(drUriSample)

        drUriSample = dtUri.NewRow
        drUriSample("売上No") = 1
        drUriSample("売上日") = "20171031"
        drUriSample("得意先CD") = "00001"
        drUriSample("商品名") = "モニター"
        drUriSample("売上数量") = 2
        drUriSample("売上金額") = 30000
        dtUri.Rows.Add(drUriSample)

        Dim lnqGroup = From drUri In dtUri.AsEnumerable
                       Group By TokCD = drUri("得意先CD")
                           Into grp = Group
                       Select New With {
                             .得意先CD = TokCD,
                             .grp = grp
                             }



        Dim strMsg As String = ""

        For Each lnqdr In lnqGroup
            strMsg += "得意先CD:" & lnqdr.得意先CD & vbCrLf
            strMsg += "合計金額:" & lnqdr.grp.Sum(Function(drChild) drChild("売上金額")) & vbCrLf

            'まとまった単位
            For Each drGrpChild In lnqdr.grp
                strMsg += "商品名:" & drGrpChild("商品名") & " 数量:" & drGrpChild("売上数量") & " 金額:" & drGrpChild("売上金額") & vbCrLf
            Next

            MsgBox(strMsg)
            strMsg = ""

        Next

    End Sub


PowerShellでWPFアプリケーションをBindingするときの注意点

 1.PowerShellでWPFアプリケーションのBindingについて マニアックだけどPowerShellでWPFアプリケーションを作っている。INotifyChangedを実装したいけど、PowerShellにはgetterやsetterがないので通知が発行できない。 そ...