検索条件
起動時に押せるボタン:ファイルオープン、CSVインポート
データ入力後に押せるボタン:保存、印刷プレビュー、印刷
データを空にすると起動時と同じ状態
View側は楽勝。TextBoxやCheckBoxはスタイルの指定すら不要。
ToolBarのRegionをどうするかで迷いましたが、とりあえずModule側の基本画面に表示することに。
<ToolBarTray DockPanel.Dock="Top">
<ToolBar Style="{DynamicResource MaterialDesignToolBar}" ClipToBounds="True">
<Button ToolTip="ファイルを開く" Command="{Binding FileOpenCommand}">
<materialDesign:PackIcon Kind="Folder" />
</Button>
<Button ToolTip="データを保存" Command="{Binding FileSaveCommand}">
<materialDesign:PackIcon Kind="Floppy" />
</Button>
<Button ToolTip="CSVファイルをインポート" Command="{Binding CsvImportCommand}">
<materialDesign:PackIcon Kind="FileDelimited" />
</Button>
<Separator />
<Button ToolTip="印刷プレビュー" Command="{Binding PrintPreviewCommand}">
<materialDesign:PackIcon Kind="FileFind" />
</Button>
<Button ToolTip="印刷" Command="{Binding PrintCommand}">
<materialDesign:PackIcon Kind="Printer" />
</Button>
</ToolBar>
</ToolBarTray>
using Prism.Commands;
public DelegateCommand FileOpenCommand { get; private set; }
public DelegateCommand FileSaveCommand { get; private set; }
public DelegateCommand CsvImportCommand { get; private set; }
public DelegateCommand PrintPreviewCommand { get; private set; }
public DelegateCommand PrintCommand { get; private set; }
チェックボックスで制御するのはサンプル通りなので直ぐに出来ましたが、保存・印刷可能なコンテンツがあるかどうかで制御したいわけでTextBoxが空かどうかで制御しようとしたらどうしたらいいのか分からず。
テキストボックスの値が変わった時にRaiseCanExecuteChangedを呼んでも動きましたが、最終的にはObservesPropertyを使ってとりあえず動いたよ。
// bootをプロパティに変える
private bool HaveData()
{
return !string.IsNullOrEmpty(InputData);
}
private bool NoData()
{
// 微妙ですが…
return string.IsNullOrEmpty(InputData);
}
public DelegateCommand FileOpenCommand { get; private set; }
public DelegateCommand FileSaveCommand { get; private set; }
public DelegateCommand CsvImportCommand { get; private set; }
public DelegateCommand PrintPreviewCommand { get; private set; }
public DelegateCommand PrintCommand { get; private set; }
public CashbookViewModel()
{
// ObservesPropertyでInputDataの変化を監視し、NoDataを再評価する感じ?
FileOpenCommand = new DelegateCommand(FileOpen, NoData).ObservesProperty(() => InputData);
FileSaveCommand = new DelegateCommand(FileSave, HaveData).ObservesProperty(() => InputData);
CsvImportCommand = new DelegateCommand(CsvImport, NoData).ObservesProperty(() => InputData);
PrintPreviewCommand = new DelegateCommand(PrintPreview, HaveData).ObservesProperty(() => InputData);
PrintCommand = new DelegateCommand(Print, HaveData).ObservesProperty(() => InputData);
}
監視対象のフィールドが複数ある場合はチェインでつなぐことも可能なようです。
またまたいてまえ系コーディング。やってみたら動いたよ…。
HomeModuleのViewAのViewModelで。
public ViewAViewModel(IMenuService menuService)
{
MainMenuItems = menuService.GetMainMenuItems();
Message = "Home Module";
}
デバッグしてここで待ち受けているとMainMenuItemsの中は空(HomeModuleのOnInitializedよりも先にこちらを通る)だったのですが、実行するとメニューが表示されました。
Cardで包んでボタンをAccentButtonに変えたらグッと良くなるはず、と思ってましたがいまいち垢抜けません…。
WrapPanelがWrapしてくれず苦労しました。MenuItemを拡張してグリッドの位置をモデルから渡そうかと思ったくらい。
<Grid>
<ItemsControl ItemsSource="{Binding MainMenuItems}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<materialDesign:Card Margin="12" Padding="16" Width="280">
<StackPanel>
<TextBlock Style="{DynamicResource MaterialDesignTitleTextBlock}" Text="{Binding Title}"></TextBlock>
<TextBlock Text="{Binding Description}" Margin="10 8 0 0"></TextBlock>
<Button
Margin="12 16 12 0"
Style="{StaticResource MaterialDesignRaisedAccentButton}"
Command="{Binding Path=DataContext.NavigateCommand, RelativeSource={RelativeSource AncestorType=ItemsControl}}" CommandParameter="{Binding NavigatePath}">
<TextBlock Margin="6 0 0 0" Style="{StaticResource MaterialDesignBody1TextBlock}"
Text="OPEN" />
</Button>
</StackPanel>
</materialDesign:Card>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
発行方法は3種類あるようですが、一番簡単そうなXCOPYでいくことに。
ところがその方法を書いてくれていない。
普通に「発行」するとexeが出来ずにインストーラーが出来てました。
ビルドをリリースに変えてbinフォルダの中にできたものをデスクトップに移動しexeをクリックしたらちゃんと動きました。
現在は親からモジュールへ参照を張っているのでモジュールのdllも一緒にリリースビルドに含まれています。
dllの並び見ているとモジュールのプロジェクト名を変えたくなってきて一旦終了。
起動時はHomeモジュール表示
ハンバーガートグルボタンでメインメニュー表示
ドロワー上のボタンをクリックしてモジュール切り替え
Prism6版を確認したら、NavigateCommandを親プロジェクトの既存のViewModelに移動しても問題なく動いたとあった(記憶には無かった)のでモジュール側のメニューはViewだけを残して他はバッサリ削除。
「動かん!?」と思ったらNavigate先のRegion名を間違えてました(Typo)。
エラー出してよ、と思いました。
Viewもテンプレート化すれば重複減らせそうですが、それは次の課題。
デスクトップアプリでメインメニューにDrawer使うとか他人様にやられると「はぁ?」という感じですが、ものは試しで(^^;)。
setの見慣れない書き方はよく分かってませんが、Titleの真似で。
private bool _mainMenuIsOpen = false;
public bool MainMenuIsOpen
{
get { return _mainMenuIsOpen; }
set { SetProperty(ref _mainMenuIsOpen, value); }
}
2箇所あるので要注意
<materialDesign:DrawerHost IsLeftDrawerOpen="{Binding ElementName=MenuToggleButton, Path=IsChecked}">
<materialDesign:DrawerHost.LeftDrawerContent>
<DockPanel MinWidth="212">
<ToggleButton Style="{StaticResource MaterialDesignHamburgerToggleButton}"
DockPanel.Dock="Top"
HorizontalAlignment="Right" Margin="16"
IsChecked="{Binding MainMenuIsOpen}" />
<StackPanel Margin="0">
<ItemsControl x:Name="NavigationItemsControl" prism:RegionManager.RegionName="MainNavigationRegion" Margin="0" Padding="0" />
</StackPanel>
</DockPanel>
</materialDesign:DrawerHost.LeftDrawerContent>
<DockPanel>
<materialDesign:ColorZone Padding="16" materialDesign:ShadowAssist.ShadowDepth="Depth2"
Mode="PrimaryMid" DockPanel.Dock="Top">
<DockPanel>
<ToggleButton Style="{StaticResource MaterialDesignHamburgerToggleButton}" IsChecked="{Binding MainMenuIsOpen}"
x:Name="MenuToggleButton"/>
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="22" Text="{Binding Title}"></TextBlock>
</DockPanel>
</materialDesign:ColorZone>
・・・・
private void Navigate(string navigatePath)
{
MainMenuIsOpen = false;
if (navigatePath != null)
_regionManager.RequestNavigate("ContentRegion", navigatePath);
}
MaterialDesignThemesとMaterialDesignColors
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Light.xaml" />
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Defaults.xaml" />
<ResourceDictionary Source="pack://application:,,,/MaterialDesignColors;component/Themes/Recommended/Primary/MaterialDesignColor.DeepPurple.xaml" />
<ResourceDictionary Source="pack://application:,,,/MaterialDesignColors;component/Themes/Recommended/Accent/MaterialDesignColor.Lime.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
<Window x:Class="TreasurerHelper.Views.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:prism="http://prismlibrary.com/"
prism:ViewModelLocator.AutoWireViewModel="True"
Title="{Binding Title}" Height="400" Width="650"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
TextElement.Foreground="{DynamicResource MaterialDesignBody}"
TextElement.FontWeight="Regular"
TextElement.FontSize="13"
TextOptions.TextFormattingMode="Ideal"
TextOptions.TextRenderingMode="Auto"
Background="{DynamicResource MaterialDesignPaper}"
FontFamily="{DynamicResource MaterialDesignFont}">
<DockPanel>
<materialDesign:ColorZone Padding="16" materialDesign:ShadowAssist.ShadowDepth="Depth2"
Mode="PrimaryMid" DockPanel.Dock="Top">
<DockPanel>
<TextBlock HorizontalAlignment="Left" VerticalAlignment="Center" FontSize="22" Text="{Binding Title}"></TextBlock>
</DockPanel>
</materialDesign:ColorZone>
<Grid>
<ContentControl prism:RegionManager.RegionName="ContentRegion" />
</Grid>
</DockPanel>
</Window>
…
prism:ViewModelLocator.AutoWireViewModel="True"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes">
<Grid ShowGridLines="True">
<materialDesign:Card Padding="32" Margin="16">
<TextBlock Text="{Binding Message}" Style="{DynamicResource MaterialDesignTitleTextBlock}"></TextBlock>
</materialDesign:Card>
</Grid>
PrismとMaterialDesignを使って初めてのWPFアプリを作成中。
機能はエクセル使えよ!(実際に現在はエクセル使用中)なものですが、勉強のため。
独学でどこまでいけるでしょうか。
チュートリアル放置していた間に-Prismのバージョン上がってやる気が失せたので仕切りなおし。
1日目 | Prism Blank App(WPF)とPrism Module(WPF)を使ってプロジェクトを作成 |
2日目 | ModuleにViewを追加しApp側に表示 |
3日目 | MaterialDesign(MaterialDesignThemesとMaterialDesignColors)を適用する |
4日目 | モジュール間の切り替えを行うメインメニュー追加 |
5日目 | モジュール間の切り替えをBasicRegionNavigationに変更 メインメニューをMaterialDesignのDrawerに変更 |
6日目 | モジュール間の切り替えをMenuServiceに変更 ItemTemplateを使ってViewの重複を除く |
7日目 | トップページにMaterialDesignのCardを使ってモジュール一覧表示 |
8日目 | 画像の表示 親ViewのViewModelのコマンドをモジュールのViewから呼び出す |
9日目 | MaterialDesignToolBarでツールバーをつくる DelegateCommandでボタンの活性/非活性を制御する |
10日目 | PrismのCustomPopupを使う CustomPopupの見た目をMaterialDesignのDialogっぽくする |
11日目 | NavigationCallbackを使ってMainWindowにモジュールのタイトル追加 |
12日目 | MVVM1回目 DomainObjectを継承したModelのListをDataGridにバインド |
13日目 | MVVM2回目 行合計(subtotal)の総合計(grandtotal)の取り方が分からない |
結局決算に間に合わず中断中。GitHubに上げていますが初心者のためのチュートリアルではなく、WPF初心者が試行錯誤中のものですのでとんでもないバグが潜んでいるかも知れません。
WPFWPFWPFWPFWPFWPFWPFWPFWPFWPFWPF