C# WPF ちょっとしたログ表示用機構
趣旨
コードビハインド側で ObservableCollection
にログを持ってもらい、xaml 側の ScrollViewer
内部で表示させる。
この時、xaml 側では ItemsSource
属性で Binding させておくのがクソデカポイント
( 紐づけされないと、いくらログを増やしてもフォーム反映されない )
また、以下条件を整えないと Binding がうまくいかず、フォーム上のログが更新されなかったので注意
- 用意した
LogCollection
の注意点- フィールドではなくプロパティで持つ
Qiita - プロパティ?フィールド?メンバー?C#のクラス構造のおさらい - private や internal ではなく public で持つ
- フィールドではなくプロパティで持つ
個人的オススメ
static class で独立気味に。
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Log.Add("ログ"); // 使い方
Log.LogCollection.Add("Hoge"); // 何ならこっちでも良い
}
// ログ表示用
public static class Log
{
private static ObservableCollection<string> _logCollection = new ObservableCollection<string>();
public static ObservableCollection<string> LogCollection { get { return _logCollection; } }
public static void Add(string _text) { LogCollection.Add(_text); }
}
}
<Grid>
<DockPanel LastChildFill="True">
<ScrollViewer CanContentScroll="True">
<ItemsControl ItemsSource="{Binding Path=(local:Log.LogCollection)}"/>
</ScrollViewer>
</DockPanel>
</Grid>
一緒で良いなら
事前に DataContext
へ登録しておく必要アリ
public partial class MainWindow : Window
{
// フィールドではなくプロパティ かつ public で持つこと
public ObservableCollection<string> LogCollection { get; set; }
public MainWindow()
{
LogCollection = new ObservableCollection<string>();
// ※ データコンテキストへ丸ごと登録しておくこと
DataContext = this;
InitializeComponent();
// 以下要領でログを増やせば、任意タイミングでフォーム上でも更新される
LogCollection.Add("ログ表示1");
LogCollection.Add("ログ表示2");
}
}
<Grid>
<DockPanel LastChildFill="True">
<StackPanel Margin="0,0,5,0">
<TextBlock>なんちゃらかんちゃら</TextBlock>
</StackPanel>
<DockPanel LastChildFill="True">
<ScrollViewer CanContentScroll="True">
<ItemsControl ItemsSource="{Binding Path=LogCollection}" />
</ScrollViewer>
</DockPanel>
</DockPanel>
</Grid>
DataContext 登録省略版
やってることは上記とほぼ変わらない
xaml 側で行ってたログデータとの紐づけ相当を、コードビハインド側に移しただけ
x:Name
で引っぱり出せるように名前付けしたりしなきゃなので、さっきのほうがスッキリしてて良さそう
public partial class MainWindow : Window
{
// private でもOK フィールドでもOK
private readonly ObservableCollection<string> logCollection = new ObservableCollection<string>();
public MainWindow()
{
InitializeComponent();
var itemsControl = new ItemsControl();
itemsControl.ItemsSource = logCollection;
ScrollViewer scrollViewer = (ScrollViewer)FindName("LogScrollViewer");
scrollViewer.Content = itemsControl;
logCollection.Add("ログ表示1");
logCollection.Add("ログ表示2");
}
}
<Grid>
<DockPanel LastChildFill="True">
<StackPanel Margin="0,0,5,0">
<TextBlock>なんちゃらかんちゃら</TextBlock>
</StackPanel>
<DockPanel LastChildFill="True">
<ScrollViewer x:Name="LogScrollViewer" CanContentScroll="True"/>
</DockPanel>
</DockPanel>
</Grid>
余談:DataContext への丸ごと登録
上記で述べた DataContext
へのまるごと登録はざっくり2種あって、
まずは以下のコードビハインド側で代入した処理。
これは1つめの例で用いられてたもの
public MainWindow()
{
DataContext = this; // 登録!
InitializeComponent();
// 以下略
}
もう一つが xaml 側で登録する方法。
<Window x:Class="HogeProject.MainWindow"
...中略...
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Grid>
...中略...
</Grid>
</Window>
お好みでどうぞ
動作イメージ
参考リンクなど
teratail - WPFでログ出力のようなことをしたい
Stack Overflow - Make ScrollViewer fill dynamic area