using CommunityToolkit.Mvvm.ComponentModel; using OpenTap; using OpenTap.Diagnostic; using OpenTapEditor.Util; using System.Collections.ObjectModel; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Threading; using UtilLib; namespace OpenTapEditor { public enum LevelType { /// /// Recoverable error. /// Error = 10, /// /// Noncritical problem. /// Warning = 20, /// /// Informational message. /// Info = 30, /// /// Debugging trace. /// Debug = 40 } public class LogItem { public Event e { get; internal set; } public int Type => e.EventType; public override string ToString() { return $"{(LevelType)e.EventType} {new DateTime(e.Timestamp).ToString("HH:mm:ss.fff")} : {e.Source} : {e.Message}"; } } /// /// LogControl.xaml 的交互逻辑 /// [ObservableObject] public partial class LogControl : UserControl, ILogListener { [ObservableProperty] private ObservableCollection datasource = new ObservableCollection(); [ObservableProperty] private bool showError = true; [ObservableProperty] private bool showWarn = true; [ObservableProperty] private bool showInfo = true; [ObservableProperty] private bool showDebug = true; [ObservableProperty] private CollectionViewSource viewSource; public LogControl() { DataContext = this; ViewSource = new CollectionViewSource(); ViewSource.Filter += CollectionViewSource_Filter; BindingOperations.SetBinding(viewSource, CollectionViewSource.SourceProperty, new Binding(nameof(Datasource)) { Source = this, Mode = BindingMode.TwoWay, NotifyOnSourceUpdated = true, }); InitializeComponent(); InitFromSetting(); } private void InitFromSetting() { ShowError = bool.Parse(IniHelper.ReadIniData("Log", nameof(ShowError), "True", PathHelper.SettingIniPath)); ShowWarn = bool.Parse(IniHelper.ReadIniData("Log", nameof(ShowWarn), "True", PathHelper.SettingIniPath)); ShowInfo = bool.Parse(IniHelper.ReadIniData("Log", nameof(ShowInfo), "True", PathHelper.SettingIniPath)); ShowDebug = bool.Parse(IniHelper.ReadIniData("Log", nameof(ShowDebug), "True", PathHelper.SettingIniPath)); } private void WriteSetting(string name, object value) { IniHelper.WriteIniData("Log", name, value.ToString(), PathHelper.SettingIniPath); } partial void OnShowErrorChanged(bool value) { WriteSetting(nameof(ShowError), value); ViewSource.View.Refresh(); } partial void OnShowWarnChanged(bool value) { WriteSetting(nameof(ShowWarn), value); ViewSource.View.Refresh(); } partial void OnShowInfoChanged(bool value) { WriteSetting(nameof(ShowInfo), value); ViewSource.View.Refresh(); } partial void OnShowDebugChanged(bool value) { WriteSetting(nameof(ShowDebug), value); ViewSource.View.Refresh(); } public void EventsLogged(IEnumerable Events) { foreach (var e in Events) { HandleLog(e); } } private void HandleLog(Event e) { Dispatcher.BeginInvoke( () => { lock (this) { var item = new LogItem() { e = e }; Datasource.Add(item); log.ScrollIntoView(item); } }, DispatcherPriority.Background); } public void Flush() { } private void CollectionViewSource_Filter(object sender, System.Windows.Data.FilterEventArgs e) { if (e.Item is LogItem item) { switch (item.Type) { case 10: e.Accepted = ShowError; break; case 20: e.Accepted = ShowWarn; break; case 30: e.Accepted = ShowInfo; break; case 40: e.Accepted = ShowDebug; break; default: e.Accepted = true; break; } } } private void Button_Click(object sender, System.Windows.RoutedEventArgs e) { Datasource.Clear(); } } }