intent : в моем приложении C#/WPF у меня есть logger (реализован как синглтон), который широко используется на протяжении всего приложения для регистрации различных Поведение: < /p>
Код: Выделить всё
public class Logger
{
public ReadOnlyCollection Log => _logRo;
private readonly ObservableCollection _log;
private readonly ReadOnlyObservableCollection _logRo;
private static Logger? _instance;
private Dictionary _logActors;
public static Logger GetInstance()
{
return _instance ??= new Logger();
}
public Logger()
{
_log = [];
_logRo = new(_log);
_logActors = new Dictionary
{
{ LogLevels.Trace, [new ConsoleWriter(), new FileWriter()] },
{ LogLevels.Debug, [new ConsoleWriter(), new FileWriter()] },
{ LogLevels.Info, [new ConsoleWriter(), new FileWriter()] },
{ LogLevels.Warning, [new ConsoleWriter(), new FileWriter()] },
{ LogLevels.Error, [new ConsoleWriter(), new FileWriter()] },
{ LogLevels.Fatal, [new ConsoleWriter(), new FileWriter()] },
};
}
public static void Add(LogLevels level, string message)
{
var instance = GetInstance();
LogEntry entry = new(level, message);
instance?._log.Add(entry);
List? actors = instance?._logActors[level];
if (actors == null) return;
foreach (var actor in actors)
{
actor.Perform(entry);
}
}
public void Clear()
{
_log.Clear();
}
private interface ILogActor
{
void Perform(LogEntry entry);
}
private class ConsoleWriter : ILogActor
{
public void Perform(LogEntry entry)
{
Console.WriteLine(entry.ToString());
}
}
private class FileWriter : ILogActor
{
public void Perform(LogEntry entry)
{
var folder = Utilities.FileOperations.GetAppPath();
const string name = "debug.log";
var path = folder + name;
Utilities.FileOperations.AppendToFile(path, entry.ToString() + Environment.NewLine);
}
}
public class LogEntry(LogLevels level, string message)
{
public DateTime Time { get; init; } = DateTime.Now;
public LogLevels Level { get; init; } = level;
public string Message { get; init; } = message;
public override string ToString()
{
List entryItems = [Time.ToString(CultureInfo.InvariantCulture), Utilities.EnumTools.GetEnumDescription(Level), Message];
return entryItems.Aggregate(string.Empty, (current, item) => current + (item + "\t"));
}
}
}
[Flags]
public enum LogLevels
{
[Description("TRACE")]
Trace = 1,
[Description("DEBUG")]
Debug = 2,
[Description("INFO")]
Info = 4,
[Description("WARNING")]
Warning = 8,
[Description("ERROR")]
Error = 16,
[Description("FATAL")]
Fatal = 32
}
Страница:
Код: Выделить всё
public partial class LoggerPage : Page
{
LoggerPageViewModel vm;
public LoggerPage(AppSettingsData.GeneralSettings generalSettings)
{
InitializeComponent();
vm = new LoggerPageViewModel(generalSettings);
DataContext = vm;
}
private void Page_Loaded(object sender, RoutedEventArgs e)
{
var view = (CollectionView)CollectionViewSource.GetDefaultView(Log_ListView.ItemsSource);
view.Filter = UserFilter;
}
private bool UserFilter(object item)
{
var level = (item as Logger.LogEntry).Level;
if (vm.LogDisplayLevels.HasFlag(level))
{
return true;
}
return false;
}
private void CheckboxChanged(object sender, RoutedEventArgs e)
{
CollectionViewSource.GetDefaultView(Log_ListView.ItemsSource).Refresh();
}
public class LoggerPageViewModel
{
public ReadOnlyCollection Log { get; set; }
public LogLevels LogDisplayLevels { get; init; }
public LoggerPageViewModel(AppSettingsData.GeneralSettings generalSettings)
{
Log = Logger.GetInstance().Log;
LogDisplayLevels = generalSettings.DisplayLogLevels;
}
}
}
public class LogMaskValueConverter : IValueConverter
{
private LogLevels target;
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var mask = (LogLevels)parameter;
target = (LogLevels)value;
return (mask & target) != 0;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
target ^= (LogLevels)parameter;
return target;
}
}
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:MyApplication"
xmlns:gui="clr-namespace:MyApplication.GUI"
xmlns:loggingUtils="clr-namespace:LoggingUtils;assembly=LoggingUtils"
mc:Ignorable="d"
d:DesignHeight="200" d:DesignWidth="350"
Title="LoggerPage" Loaded="Page_Loaded">
Код: Выделить всё
public partial class LoggerWindow : Window
{
public LoggerWindow(AppSettingsData.GeneralSettings generalSettings)
{
InitializeComponent();
LogDisplay_Frame.Navigate(new LoggerPage(generalSettings));
}
private void ClearButton_Click(object sender, RoutedEventArgs e)
{
Logger.GetInstance().Clear();
}
}
< /code>
Теперь я хочу отобразить это окно, когда начинается приложение, и для того, чтобы обновить его содержимое в прямом эфире, когда приложение запускается без замораживания, обновление, как только новые записи добавляются в Logger .Log Код: Выделить всё
public partial class App : System.Windows.Application
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
var loggerWindow = new LoggerWindow(GeneralSettings);
loggerWindow.Show();
RunTestsAsync();
}
private async void RunTestsAsync()
{
await Task.Run(() =>
{
Tests.Run(); //Various calls that take ~1 minute to complete, with many calls to Logger.Add
});
}
}
Код: Выделить всё
public static class GeneralSettings
{
public LogLevels DisplayLogLevels { get; init; } = LogLevels.Info | LogLevels.Error | LogLevels.Fatal;
}
Этот тип CollectionVie />
Как я понимаю, проблема заключается в том, что logger.log (asbustablecollection) обрабатывается двумя потоками - один, который его модифицирует, и один, который подписывается на Это события изменения контента, которые не допускаются. Это, однако, является моим фактическим намерением - я хочу, чтобы ядро приложения продолжало запись в этот logger.log и для LoggerPage , чтобы немедленно заметить эти изменения и обновить пользовательский интерфейс. Я не знаю, как решить это. < /P>
Что я здесь делаю не так? Мой подход неверен? Если да, то как мне справиться с этим?
Подробнее здесь: https://stackoverflow.com/questions/793 ... her-thread
Мобильная версия