Skip to content

Commit 75fd59c

Browse files
committed
add logname and provider list window(#1, #2)
1 parent 2903941 commit 75fd59c

13 files changed

+405
-16
lines changed

src/WEventViewer/App.axaml.cs

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using Avalonia.Controls.ApplicationLifetimes;
33
using Avalonia.Markup.Xaml;
44
using Microsoft.Extensions.DependencyInjection;
5+
using WEventViewer.Model;
56
using WEventViewer.ViewModel;
67

78
namespace WEventViewer;
@@ -16,10 +17,23 @@ public override void Initialize()
1617
public override void OnFrameworkInitializationCompleted()
1718
{
1819
var collection = new ServiceCollection();
19-
20+
collection.AddSingleton<EventLogRepository>();
21+
collection.AddSingleton<MainWindowViewModel>(provider => new MainWindowViewModel(provider.GetRequiredService<EventLogRepository>()));
22+
collection.AddTransient<ErrorWindow>();
23+
collection.AddTransient<ErrorWindowViewModel>();
24+
collection.AddTransient<OpenLogWindowViewModel>();
25+
collection.AddTransient<OpenLogWindow>();
26+
collection.AddTransient<ProviderNameWindowViewModel>();
27+
collection.AddTransient<LogNameViewModel>();
28+
var serviceProvider = collection.BuildServiceProvider();
29+
var vm = serviceProvider.GetRequiredService<MainWindowViewModel>();
2030
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
2131
{
22-
desktop.MainWindow = new MainWindow();
32+
desktop.MainWindow = new MainWindow(serviceProvider) { DataContext = vm };
33+
}
34+
else if (ApplicationLifetime is ISingleViewApplicationLifetime singleViewPlatform)
35+
{
36+
singleViewPlatform.MainView = new MainWindow(serviceProvider) { DataContext = vm }; ;
2337
}
2438

2539
base.OnFrameworkInitializationCompleted();

src/WEventViewer/LogNameWindow.axaml

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<Window xmlns="https://github.com/avaloniaui"
2+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
3+
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
4+
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
5+
xmlns:vm="using:WEventViewer.ViewModel"
6+
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
7+
x:Class="WEventViewer.LogNameWindow"
8+
x:DataType="vm:LogNameViewModel"
9+
Loaded="Window_Loaded_1"
10+
Title="LogNameWindow">
11+
<Design.DataContext>
12+
<vm:LogNameViewModel/>
13+
</Design.DataContext>
14+
<Grid>
15+
<Grid.RowDefinitions>
16+
<RowDefinition Height="Auto"></RowDefinition>
17+
<RowDefinition Height="Auto"></RowDefinition>
18+
<RowDefinition Height="3*"></RowDefinition>
19+
<RowDefinition Height="Auto"></RowDefinition>
20+
</Grid.RowDefinitions>
21+
<Label Content="LogNames" Grid.Row="0" Margin="10"/>
22+
<StackPanel Orientation="Horizontal" Grid.Row="1" HorizontalAlignment="Stretch">
23+
<Label Content="Search:" Margin="10" VerticalAlignment="Center"/>
24+
<TextBox Text="{Binding SearchString}" Margin="10" VerticalAlignment="Center"/>
25+
</StackPanel>
26+
<ScrollViewer Grid.Row="2">
27+
<ListBox Name="LogNames" ItemsSource="{Binding LogNames}" MaxHeight="{Binding $parent.Bounds.Height}">
28+
<ListBox.ItemTemplate>
29+
<DataTemplate>
30+
<SelectableTextBlock Text="{Binding}"/>
31+
</DataTemplate>
32+
</ListBox.ItemTemplate>
33+
</ListBox>
34+
</ScrollViewer>
35+
<Button Name="CloseButton" Click="CloseButton_Click" Content="Close" HorizontalAlignment="Right" Margin="10" Grid.Row="3"/>
36+
</Grid>
37+
</Window>
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
using Avalonia;
2+
using Avalonia.Controls;
3+
using Avalonia.Markup.Xaml;
4+
using WEventViewer.ViewModel;
5+
6+
namespace WEventViewer;
7+
8+
public partial class LogNameWindow : Window
9+
{
10+
public LogNameWindow()
11+
{
12+
InitializeComponent();
13+
}
14+
private void CloseButton_Click(object? sender, Avalonia.Interactivity.RoutedEventArgs e)
15+
{
16+
this.Close();
17+
}
18+
19+
private void Window_Loaded_1(object? sender, Avalonia.Interactivity.RoutedEventArgs e)
20+
{
21+
if (this.DataContext is LogNameViewModel vm)
22+
{
23+
vm.LoadLogNames.Execute(null);
24+
}
25+
}
26+
}

src/WEventViewer/MainWindow.axaml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,12 @@
1818
<Menu DockPanel.Dock="Top" BorderBrush="Black" BorderThickness="1">
1919
<MenuItem Header="_File">
2020
<MenuItem Header="_Open" Command="{Binding OpenCommand}"/>
21+
<MenuItem Header="Show _Providers" Name="PrintProviders" Click="PrintProviderClick"/>
22+
<MenuItem Header="Show _LogNames" Name="PrintLogNames" Click="PrintLogNamesClick"/>
2123
<MenuItem Header="_Close" Command="{Binding CloseCommand}"/>
2224
</MenuItem>
2325
<MenuItem Header="_About"/>
26+
2427
</Menu>
2528
<ScrollViewer HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="20" MinHeight="200" MinWidth="200" Height="{Binding Mode=OneWay,Path=ScrollViewerHeight}" Name="LogViewer">
2629
<DataGrid
@@ -46,8 +49,6 @@
4649
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Margin="20" VerticalAlignment="Bottom">
4750
<Label Content="{Binding LogCount,Mode=OneWay}"/>
4851
<Label Content="{Binding LoadStatus,Mode=OneWay}"/>
49-
<Label Content="{Binding #LogViewer.Bounds.Height}"/>
50-
<Label Content="{Binding ScrollViewerHeight}"/>
5152
</StackPanel>
5253
</StackPanel>
5354
</Window>

src/WEventViewer/MainWindow.axaml.cs

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
using Avalonia.Controls;
2+
using Avalonia.Interactivity;
23
using CommunityToolkit.Mvvm.Input;
34
using CommunityToolkit.Mvvm.Messaging;
5+
using Microsoft.Extensions.DependencyInjection;
6+
using System;
47
using System.Diagnostics;
58
using WEventViewer.Model;
69
using WEventViewer.ViewModel;
@@ -11,9 +14,12 @@ internal record class OpenErrorLogWindow(string message);
1114
public partial class MainWindow : Window
1215
{
1316
DiagnosticListener _DS = new DiagnosticListener(nameof(MainWindow));
14-
public MainWindow()
17+
IServiceProvider? serviceProvider;
18+
public MainWindow() : this(null) { }
19+
public MainWindow(IServiceProvider? serviceProvider)
1520
{
16-
DataContext = new MainWindowViewModel();
21+
DataContext = serviceProvider != null ? serviceProvider.GetService<MainWindowViewModel>() : new MainWindowViewModel();
22+
this.serviceProvider = serviceProvider;
1723
InitializeComponent();
1824
WeakReferenceMessenger.Default.Register<MainWindow, OpenLogRequest>(this, async (recpient, req) =>
1925
{
@@ -61,4 +67,26 @@ private void DataGrid_DoubleTapped_1(object? sender, Avalonia.Input.TappedEventA
6167
}
6268
}
6369
}
70+
71+
private void PrintProviderClick(object? sender, Avalonia.Interactivity.RoutedEventArgs e)
72+
{
73+
_DS.Write("OnPrintProviderClick", new { e.Source, t = e.GetType() });
74+
if (serviceProvider != null)
75+
{
76+
var vm = serviceProvider.GetService<ProviderNameWindowViewModel>();
77+
var w = new ProviderNamesWindow() { DataContext = vm };
78+
w.Show(this);
79+
}
80+
81+
}
82+
83+
private void PrintLogNamesClick(object? sender, RoutedEventArgs e)
84+
{
85+
if (serviceProvider != null)
86+
{
87+
var vm = serviceProvider.GetService<LogNameViewModel>();
88+
var w = new LogNameWindow() { DataContext = vm };
89+
w.Show(this);
90+
}
91+
}
6492
}

src/WEventViewer/Model/EventLogRepository.cs

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
using System.Diagnostics.Eventing;
77
using System.Diagnostics.Eventing.Reader;
88
using System.Threading;
9-
using Microsoft.CodeAnalysis.CSharp.Syntax;
109
using System.Diagnostics;
1110
using System.Runtime.CompilerServices;
1211
using System.Collections.ObjectModel;
@@ -147,5 +146,31 @@ public async Task Load(string logName, PathType pathType, string? query, Cancell
147146
dispatch(lst);
148147
}
149148
}
149+
public async Task LoadProviderNames(Action<IList<string>> callback, CancellationToken ct = default)
150+
{
151+
using var session = new EventLogSession();
152+
foreach(var chunk in session.GetProviderNames().Order().Chunk(256))
153+
{
154+
if(ct.IsCancellationRequested)
155+
{
156+
break;
157+
}
158+
callback(chunk);
159+
await Task.Delay(10);
160+
}
161+
}
162+
public async Task LoadLogNames(Action<IList<string>> callback, CancellationToken ct = default)
163+
{
164+
using var session = new EventLogSession();
165+
foreach(var chunk in session.GetLogNames().Order().Chunk(256))
166+
{
167+
if (ct.IsCancellationRequested)
168+
{
169+
break;
170+
}
171+
callback(chunk);
172+
await Task.Delay(10);
173+
}
174+
}
150175
}
151176
}

src/WEventViewer/Program.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,6 @@ public static AppBuilder BuildAvaloniaApp()
1717
=> AppBuilder.Configure<App>()
1818
.UsePlatformDetect()
1919
.WithInterFont()
20+
.UseR3()
2021
.LogToTrace();
2122
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<Window xmlns="https://github.com/avaloniaui"
2+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
3+
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
4+
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
5+
mc:Ignorable="d" d:DesignWidth="600" d:DesignHeight="450"
6+
xmlns:vm="using:WEventViewer.ViewModel"
7+
x:Class="WEventViewer.ProviderNamesWindow"
8+
x:DataType="vm:ProviderNameWindowViewModel"
9+
Loaded="Window_Loaded_1"
10+
Title="ProviderNamesWindow">
11+
<Design.DataContext>
12+
<vm:ProviderNameWindowViewModel></vm:ProviderNameWindowViewModel>
13+
</Design.DataContext>
14+
<Grid>
15+
<Grid.RowDefinitions>
16+
<RowDefinition Height="Auto"></RowDefinition>
17+
<RowDefinition Height="Auto"></RowDefinition>
18+
<RowDefinition Height="3*"></RowDefinition>
19+
<RowDefinition Height="Auto"></RowDefinition>
20+
</Grid.RowDefinitions>
21+
<Label Content="Providers" Grid.Row="0" Margin="10"/>
22+
<StackPanel Orientation="Horizontal" Grid.Row="1" HorizontalAlignment="Stretch">
23+
<Label Content="Search:" Margin="10" VerticalAlignment="Center"/>
24+
<TextBox Text="{Binding SearchString}" Margin="10" VerticalAlignment="Center"/>
25+
</StackPanel>
26+
<ScrollViewer Grid.Row="2">
27+
<ListBox Name="Providers" ItemsSource="{Binding Providers}" MaxHeight="{Binding $parent.Bounds.Height}">
28+
<ListBox.ItemTemplate>
29+
<DataTemplate>
30+
<SelectableTextBlock Text="{Binding}"/>
31+
</DataTemplate>
32+
</ListBox.ItemTemplate>
33+
</ListBox>
34+
</ScrollViewer>
35+
<Button Name="CloseButton" Click="Button_Click" Content="Close" HorizontalAlignment="Right" Margin="10" Grid.Row="3"/>
36+
</Grid>
37+
</Window>
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
using Avalonia;
2+
using Avalonia.Controls;
3+
using Avalonia.Markup.Xaml;
4+
using WEventViewer.ViewModel;
5+
6+
namespace WEventViewer;
7+
8+
public partial class ProviderNamesWindow : Window
9+
{
10+
public ProviderNamesWindow()
11+
{
12+
InitializeComponent();
13+
}
14+
15+
private void Button_Click(object? sender, Avalonia.Interactivity.RoutedEventArgs e)
16+
{
17+
this.Close();
18+
}
19+
20+
private void Window_Loaded_1(object? sender, Avalonia.Interactivity.RoutedEventArgs e)
21+
{
22+
if (this.DataContext is ProviderNameWindowViewModel vm)
23+
{
24+
vm.LoadCommand.Execute(null);
25+
}
26+
}
27+
}
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
using CommunityToolkit.Mvvm.Input;
2+
using System;
3+
using System.Collections.Generic;
4+
using System.Collections.ObjectModel;
5+
using System.ComponentModel;
6+
using System.Linq;
7+
using System.Text;
8+
using System.Threading.Tasks;
9+
using System.Windows.Input;
10+
using WEventViewer.Model;
11+
using R3;
12+
13+
namespace WEventViewer.ViewModel
14+
{
15+
internal class LogNameViewModel : INotifyPropertyChanged, IDisposable
16+
{
17+
EventLogRepository EventLogRepository;
18+
public LogNameViewModel(): this(new EventLogRepository())
19+
{
20+
21+
}
22+
List<string> Original = new List<string>();
23+
ObservableCollection<string> _LogNames = new ObservableCollection<string>();
24+
public ObservableCollection<string> LogNames => _LogNames;
25+
public LogNameViewModel(EventLogRepository eventLogRepository)
26+
{
27+
this.EventLogRepository = eventLogRepository;
28+
LoadLogNames = new AsyncRelayCommand(async () =>
29+
{
30+
if (EventLogRepository != null)
31+
{
32+
Original.Clear();
33+
LogNames.Clear();
34+
await EventLogRepository.LoadLogNames(lst =>
35+
{
36+
Original.AddRange(lst);
37+
foreach (var item in lst.Where(x => !string.IsNullOrEmpty(SearchString) ? x.Contains(SearchString) : true))
38+
{
39+
LogNames.Add(item);
40+
}
41+
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(LogNames)));
42+
});
43+
}
44+
});
45+
_SearchStringSubscription = Observable.EveryValueChanged(this, x => x.SearchString)
46+
.ThrottleLast(TimeSpan.FromMilliseconds(500))
47+
.Subscribe(searchstr =>
48+
{
49+
LogNames.Clear();
50+
foreach (var item in Original.Where(x => !string.IsNullOrEmpty(searchstr) ? x.Contains(searchstr, StringComparison.InvariantCultureIgnoreCase) : true))
51+
{
52+
LogNames.Add(item);
53+
}
54+
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(LogNames)));
55+
});
56+
}
57+
public ICommand LoadLogNames;
58+
string _SearchString = string.Empty;
59+
IDisposable? _SearchStringSubscription;
60+
public string SearchString
61+
{
62+
get => _SearchString;
63+
set
64+
{
65+
if (_SearchString != value)
66+
{
67+
_SearchString = value;
68+
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(SearchString)));
69+
}
70+
}
71+
}
72+
private bool disposedValue;
73+
74+
public event PropertyChangedEventHandler? PropertyChanged;
75+
76+
protected virtual void Dispose(bool disposing)
77+
{
78+
if (!disposedValue)
79+
{
80+
if (disposing)
81+
{
82+
_SearchStringSubscription?.Dispose();
83+
}
84+
85+
// TODO: アンマネージド リソース (アンマネージド オブジェクト) を解放し、ファイナライザーをオーバーライドします
86+
// TODO: 大きなフィールドを null に設定します
87+
disposedValue = true;
88+
}
89+
}
90+
91+
// // TODO: 'Dispose(bool disposing)' にアンマネージド リソースを解放するコードが含まれる場合にのみ、ファイナライザーをオーバーライドします
92+
// ~LogNameViewModel()
93+
// {
94+
// // このコードを変更しないでください。クリーンアップ コードを 'Dispose(bool disposing)' メソッドに記述します
95+
// Dispose(disposing: false);
96+
// }
97+
98+
public void Dispose()
99+
{
100+
// このコードを変更しないでください。クリーンアップ コードを 'Dispose(bool disposing)' メソッドに記述します
101+
Dispose(disposing: true);
102+
GC.SuppressFinalize(this);
103+
}
104+
}
105+
}

0 commit comments

Comments
 (0)