Sicherung
@@ -1,9 +1,9 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.31321.278
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.0.32112.339
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FSI.Lib", "FSI.Lib\FSI.Lib.csproj", "{1394B606-4AAC-4D8D-BAF4-DB38E1FCEAAA}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FSI.Lib", "FSI.Lib\FSI.Lib.csproj", "{1394B606-4AAC-4D8D-BAF4-DB38E1FCEAAA}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Management.Infrastructure" Version="2.0.0" />
|
||||
<PackageReference Include="NLog.Extensions.Logging" Version="5.2.1" />
|
||||
<PackageReference Include="System.Configuration.ConfigurationManager" Version="6.0.0" />
|
||||
<PackageReference Include="System.Text.Encoding.CodePages" Version="7.0.0" />
|
||||
<PackageReference Include="TextCopy" Version="6.2.1" />
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
using System;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using NLog;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
@@ -19,11 +22,13 @@ namespace FSI.Lib.Guis.AutoPw
|
||||
/// </summary>
|
||||
public partial class FrmMain : Window
|
||||
{
|
||||
private Logger _log;
|
||||
public bool CloseAtLostFocus { get; set; }
|
||||
public bool PwOk { get; set; }
|
||||
public FrmMain()
|
||||
{
|
||||
InitializeComponent();
|
||||
_log = LogManager.GetCurrentClassLogger();
|
||||
|
||||
BtnOk.IsEnabled = false;
|
||||
Deactivated += FrmMain_Deactivated;
|
||||
@@ -38,6 +43,8 @@ namespace FSI.Lib.Guis.AutoPw
|
||||
|
||||
private void BtnOk_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
|
||||
_log.Info(GetType().Namespace);
|
||||
Close();
|
||||
}
|
||||
|
||||
@@ -80,10 +87,5 @@ namespace FSI.Lib.Guis.AutoPw
|
||||
Close();
|
||||
|
||||
}
|
||||
|
||||
private void TbPw_KeyDown_1(object sender, KeyEventArgs e)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -148,8 +148,6 @@
|
||||
<control:FilterDataGrid.InputBindings>
|
||||
<MouseBinding MouseAction="LeftDoubleClick"
|
||||
Command="{Binding CmdOpen}" />
|
||||
<MouseBinding MouseAction="RightDoubleClick"
|
||||
Command="{Binding CmdCopyToClip}" />
|
||||
|
||||
</control:FilterDataGrid.InputBindings>
|
||||
<control:FilterDataGrid.Columns>
|
||||
|
||||
@@ -174,6 +174,9 @@ namespace FSI.Lib.Guis.Folder.Mgt
|
||||
|
||||
newDatas.Add(newData);
|
||||
}
|
||||
|
||||
newDatas = new ObservableCollection<Model>(newDatas.OrderBy(i => i.DescriptionDtl));
|
||||
|
||||
return newDatas;
|
||||
}
|
||||
}
|
||||
|
||||
9
FSI.Lib/FSI.Lib/Guis/IbaDirSync/Model.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace FSI.Lib.Guis.IbaDirSync
|
||||
{
|
||||
public interface IInterface
|
||||
{
|
||||
public bool AutoStart { get; set; }
|
||||
public string Source { get; set; }
|
||||
public string Destination { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
namespace FSI.Lib.Guis.IbaDirSync.Model
|
||||
{
|
||||
public class Iba
|
||||
{
|
||||
public string Source { get; set; }
|
||||
public string Destination { get; set; }
|
||||
public bool AutoStart { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,59 +1,30 @@
|
||||
using FSI.Lib.Guis.IbaDirSync.Model;
|
||||
using FSI.Lib.MVVM;
|
||||
using FSI.Lib.MVVM;
|
||||
using RoboSharp;
|
||||
using System.Text;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace FSI.Lib.Guis.IbaDirSync.ViewModel
|
||||
namespace FSI.Lib.Guis.IbaDirSync
|
||||
{
|
||||
public class ViewModelIba : ViewModelBase
|
||||
public class ViewModel : ViewModelBase
|
||||
{
|
||||
private ICommand _cmdStart;
|
||||
private ICommand _cmdStop;
|
||||
|
||||
private Iba _iba;
|
||||
|
||||
public ViewModelIba()
|
||||
{
|
||||
Iba = new Model.Iba();
|
||||
Init();
|
||||
}
|
||||
|
||||
public ViewModelIba(string destination, string source, bool autoStart)
|
||||
{
|
||||
_iba = new Model.Iba()
|
||||
{
|
||||
Destination = destination,
|
||||
Source = source,
|
||||
AutoStart = autoStart,
|
||||
};
|
||||
Init();
|
||||
}
|
||||
|
||||
private void Init()
|
||||
public ViewModel()
|
||||
{
|
||||
_cmdStart = new RelayCommand<object>(ExecuteStart, CanExecuteStart);
|
||||
_cmdStop = new RelayCommand<object>(ExecuteStop, CanExecuteStop);
|
||||
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
|
||||
RoboCopy = new RoboSharp.RoboCommand();
|
||||
|
||||
if (_iba.AutoStart)
|
||||
ExecuteStart(null);
|
||||
}
|
||||
|
||||
public Model.Iba Iba
|
||||
public IInterface Data { get; set; }
|
||||
|
||||
public void Init()
|
||||
{
|
||||
get
|
||||
if (Data.AutoStart)
|
||||
{
|
||||
return _iba;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (_iba != value & _iba != null)
|
||||
{
|
||||
_iba = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
ExecuteStart(null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,8 +64,8 @@ namespace FSI.Lib.Guis.IbaDirSync.ViewModel
|
||||
|
||||
private void ExecuteStart(object obj)
|
||||
{
|
||||
RoboCopy.CopyOptions.Source = Iba.Source;
|
||||
RoboCopy.CopyOptions.Destination = Iba.Destination;
|
||||
RoboCopy.CopyOptions.Source = Data.Source;
|
||||
RoboCopy.CopyOptions.Destination = Data.Destination;
|
||||
RoboCopy.CopyOptions.CopySubdirectories = true;
|
||||
RoboCopy.CopyOptions.MonitorSourceChangesLimit = 1;
|
||||
RoboCopy.StopIfDisposing = true;
|
||||
@@ -4,13 +4,14 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace FSI.Lib.Guis.SetSizePosExWindow.Model
|
||||
namespace FSI.Lib.Guis.SetSizePosExWindow
|
||||
{
|
||||
public class Window
|
||||
public class IInterface
|
||||
{
|
||||
public string Bezeichnung { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string ClassName { get; set; }
|
||||
public bool AutoStart { get; set; }
|
||||
public int Height { get; set; }
|
||||
public int Width { get; set; }
|
||||
public int X { get; set; }
|
||||
@@ -1,5 +1,4 @@
|
||||
using FSI.Lib.Guis.SetSizePosExWindow.Model;
|
||||
using FSI.Lib.MVVM;
|
||||
using FSI.Lib.MVVM;
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.ComponentModel;
|
||||
@@ -8,9 +7,9 @@ using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace FSI.Lib.Guis.SetSizePosExWindow.ViewModel
|
||||
namespace FSI.Lib.Guis.SetSizePosExWindow
|
||||
{
|
||||
public class ViewModelWindow : ViewModelBase
|
||||
public class ViewModel : ViewModelBase
|
||||
{
|
||||
[DllImport("user32.dll")]
|
||||
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
|
||||
@@ -65,39 +64,15 @@ namespace FSI.Lib.Guis.SetSizePosExWindow.ViewModel
|
||||
private BackgroundWorker backgroundWorker;
|
||||
private ICommand _cmdStart;
|
||||
private ICommand _cmdStop;
|
||||
private ObservableCollection<Model.Window> _windows;
|
||||
private ObservableCollection<IInterface> _windows;
|
||||
private int _updateIntervall;
|
||||
private bool _autoStart;
|
||||
private Window _selectedWindow;
|
||||
private IInterface _selectedWindow;
|
||||
|
||||
public ViewModelWindow()
|
||||
public ViewModel()
|
||||
{
|
||||
_windows = new ObservableCollection<Model.Window>();
|
||||
_windows = new ObservableCollection<IInterface>();
|
||||
|
||||
Init();
|
||||
|
||||
if (AutoStart)
|
||||
{
|
||||
ExecuteStart(null);
|
||||
}
|
||||
}
|
||||
|
||||
public ViewModelWindow(bool autoStart)
|
||||
{
|
||||
_windows = new ObservableCollection<Model.Window>();
|
||||
|
||||
Init();
|
||||
|
||||
AutoStart = autoStart;
|
||||
|
||||
if (AutoStart)
|
||||
{
|
||||
ExecuteStart(null);
|
||||
}
|
||||
}
|
||||
|
||||
private void Init()
|
||||
{
|
||||
_cmdStart = new RelayCommand<object>(ExecuteStart, CanExecuteStart);
|
||||
_cmdStop = new RelayCommand<object>(ExecuteStop, CanExecuteStop);
|
||||
|
||||
@@ -110,7 +85,17 @@ namespace FSI.Lib.Guis.SetSizePosExWindow.ViewModel
|
||||
backgroundWorker.ProgressChanged += BackgroundWorker_ProgressChanged;
|
||||
}
|
||||
|
||||
public ObservableCollection<Model.Window> Windows
|
||||
public IInterface Data { get; set; }
|
||||
|
||||
public void Init()
|
||||
{
|
||||
if (Data.AutoStart)
|
||||
{
|
||||
ExecuteStart(null);
|
||||
}
|
||||
}
|
||||
|
||||
public ObservableCollection<IInterface> Windows
|
||||
{
|
||||
get
|
||||
{
|
||||
@@ -126,7 +111,7 @@ namespace FSI.Lib.Guis.SetSizePosExWindow.ViewModel
|
||||
}
|
||||
}
|
||||
|
||||
public Model.Window SelectedWindow
|
||||
public IInterface SelectedWindow
|
||||
{
|
||||
get
|
||||
{
|
||||
@@ -232,7 +217,7 @@ namespace FSI.Lib.Guis.SetSizePosExWindow.ViewModel
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (Window window in Windows)
|
||||
foreach (IInterface window in Windows)
|
||||
{
|
||||
// Perform a time consuming operation and report progress.
|
||||
Thread.Sleep(UpdateIntervall);
|
||||
@@ -28,7 +28,7 @@ namespace FSI.Lib.Guis.SieTiaWinCCMsgMgt
|
||||
|
||||
private void btnStart_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
//WinCC.Start();
|
||||
// WinCC.Start();
|
||||
CtrlMgt();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +1,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace FSI.Lib.Guis.SieTiaWinCCMsgMgt.Model
|
||||
namespace FSI.Lib.Guis.SieTiaWinCCMsgMgt
|
||||
{
|
||||
public class WinCC
|
||||
public interface IInterface
|
||||
{
|
||||
public bool AutoStart { get; set; }
|
||||
public int UpdateIntervall { get; set; }
|
||||
@@ -14,4 +10,5 @@ namespace FSI.Lib.Guis.SieTiaWinCCMsgMgt.Model
|
||||
public string WindowsClassName { get; set; }
|
||||
public string ButtonName { get; set; }
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
using FSI.Lib.Guis.SieTiaWinCCMsgMgt.Model;
|
||||
using FSI.Lib.MVVM;
|
||||
using FSI.Lib.MVVM;
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.InteropServices;
|
||||
@@ -7,9 +6,9 @@ using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace FSI.Lib.Guis.SieTiaWinCCMsgMgt.ViewModel
|
||||
namespace FSI.Lib.Guis.SieTiaWinCCMsgMgt
|
||||
{
|
||||
public class ViewModelWinCC : MVVM.ViewModelBase
|
||||
public class ViewModel : MVVM.ViewModelBase
|
||||
{
|
||||
[DllImport("user32.dll")]
|
||||
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
|
||||
@@ -37,43 +36,14 @@ namespace FSI.Lib.Guis.SieTiaWinCCMsgMgt.ViewModel
|
||||
const int WM_LBUTTONUP = 0x0202; // message for Mouse up
|
||||
|
||||
private CancellationTokenSource tokenSource = null;
|
||||
private CancellationToken token;
|
||||
private Task task = null;
|
||||
|
||||
|
||||
private BackgroundWorker backgroundWorker;
|
||||
private ICommand _cmdStart;
|
||||
private ICommand _cmdStop;
|
||||
private WinCC _winCC;
|
||||
|
||||
public ViewModelWinCC()
|
||||
{
|
||||
WinCC = new Model.WinCC();
|
||||
Init();
|
||||
}
|
||||
|
||||
public ViewModelWinCC(bool autoStart, int updateIntervall, string windowsName, string windowsClassName, string buttonName)
|
||||
{
|
||||
_winCC = new Model.WinCC
|
||||
{
|
||||
AutoStart = autoStart,
|
||||
UpdateIntervall = updateIntervall,
|
||||
WindowsName = windowsName,
|
||||
WindowsClassName = windowsClassName,
|
||||
ButtonName = buttonName
|
||||
};
|
||||
|
||||
//_seletctedWinCC = WinCC;
|
||||
|
||||
Init();
|
||||
|
||||
if (WinCC.AutoStart)
|
||||
{
|
||||
ExecuteStart(null);
|
||||
}
|
||||
}
|
||||
|
||||
private void Init()
|
||||
public ViewModel()
|
||||
{
|
||||
_cmdStart = new RelayCommand<object>(ExecuteStart, CanExecuteStart);
|
||||
_cmdStop = new RelayCommand<object>(ExecuteStop, CanExecuteStop);
|
||||
@@ -84,22 +54,16 @@ namespace FSI.Lib.Guis.SieTiaWinCCMsgMgt.ViewModel
|
||||
WorkerSupportsCancellation = true
|
||||
};
|
||||
backgroundWorker.DoWork += BackgroundWorker_DoWork;
|
||||
backgroundWorker.ProgressChanged += BackgroundWorker_ProgressChanged;
|
||||
backgroundWorker.ProgressChanged += BackgroundWorker_ProgressChanged; ;
|
||||
}
|
||||
|
||||
public Model.WinCC WinCC
|
||||
public IInterface Data { get; set; }
|
||||
|
||||
public void Init()
|
||||
{
|
||||
get
|
||||
if (Data.AutoStart)
|
||||
{
|
||||
return _winCC;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (_winCC != value & _winCC != null)
|
||||
{
|
||||
_winCC = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
ExecuteStart(null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,7 +93,6 @@ namespace FSI.Lib.Guis.SieTiaWinCCMsgMgt.ViewModel
|
||||
set => _cmdStop = value;
|
||||
}
|
||||
|
||||
|
||||
private bool CanExecuteStart(object obj)
|
||||
{
|
||||
return !Status;
|
||||
@@ -163,44 +126,23 @@ namespace FSI.Lib.Guis.SieTiaWinCCMsgMgt.ViewModel
|
||||
else
|
||||
{
|
||||
// Perform a time consuming operation and report progress.
|
||||
Thread.Sleep(WinCC.UpdateIntervall);
|
||||
Thread.Sleep(Data.UpdateIntervall);
|
||||
|
||||
// Find windos by Name
|
||||
var windowHandle = FindWindow(WinCC.WindowsClassName, WinCC.WindowsName);
|
||||
var windowHandle = FindWindow(Data.WindowsClassName, Data.WindowsName);
|
||||
|
||||
if (windowHandle != IntPtr.Zero && IsWindowVisible(windowHandle))
|
||||
{
|
||||
SetForegroundWindow(windowHandle);
|
||||
var btnHandle = FindWindowEx(windowHandle, IntPtr.Zero, null, WinCC.ButtonName);
|
||||
var btnHandle = FindWindowEx(windowHandle, IntPtr.Zero, null, Data.ButtonName);
|
||||
SendMessage(btnHandle, BM_CLICK, IntPtr.Zero, IntPtr.Zero);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public bool Status { get; set; }
|
||||
|
||||
private void WinCCMsgMgt()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (token.IsCancellationRequested)
|
||||
{
|
||||
token.ThrowIfCancellationRequested();
|
||||
}
|
||||
//MessageBox.Show("13456");
|
||||
Thread.Sleep(5000);
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
bool disposedValue = false;
|
||||
@@ -229,6 +171,5 @@ namespace FSI.Lib.Guis.SieTiaWinCCMsgMgt.ViewModel
|
||||
task = null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace FSI.Lib.Guis.TxtToClip.Mgt
|
||||
{
|
||||
|
||||
@@ -143,6 +143,8 @@ namespace FSI.Lib.Guis.TxtToClip.Mgt
|
||||
|
||||
newDatas.Add(newData);
|
||||
}
|
||||
|
||||
newDatas = new ObservableCollection<Model>(newDatas.OrderBy(i => i.DescriptionDtl));
|
||||
return newDatas;
|
||||
}
|
||||
}
|
||||
|
||||
42
FSI.Lib/NLogViewer/ActionCommand.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
using System;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace DJ
|
||||
{
|
||||
public sealed class ActionCommand : ICommand
|
||||
{
|
||||
private readonly Action _Action;
|
||||
private readonly Action<object> _ObjectAction;
|
||||
|
||||
public ActionCommand(Action action)
|
||||
{
|
||||
_Action = action;
|
||||
}
|
||||
|
||||
public ActionCommand(Action<object> objectAction)
|
||||
{
|
||||
_ObjectAction = objectAction;
|
||||
}
|
||||
|
||||
private event EventHandler CanExecuteChanged;
|
||||
|
||||
event EventHandler ICommand.CanExecuteChanged
|
||||
{
|
||||
add => CanExecuteChanged += value;
|
||||
remove => CanExecuteChanged -= value;
|
||||
}
|
||||
|
||||
bool ICommand.CanExecute(object parameter)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Execute(object parameter)
|
||||
{
|
||||
if (_ObjectAction != null)
|
||||
_ObjectAction(parameter);
|
||||
else
|
||||
_Action();
|
||||
}
|
||||
}
|
||||
}
|
||||
72
FSI.Lib/NLogViewer/Extensions/DependencyObjectExtensions.cs
Normal file
@@ -0,0 +1,72 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace DJ.Extensions
|
||||
{
|
||||
public static class DependencyObjectExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Analyzes both visual and logical tree in order to find all elements of a given
|
||||
/// type that are descendants of the <paramref name="source"/> item.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the queried items.</typeparam>
|
||||
/// <param name="source">The root element that marks the source of the search. If the
|
||||
/// source is already of the requested type, it will not be included in the result.</param>
|
||||
/// <param name="uid">The UID of the <see cref="UIElement"/></param>
|
||||
/// <returns>All descendants of <paramref name="source"/> that match the requested type.</returns>
|
||||
public static T FindChildByUid<T>(this DependencyObject source, string uid) where T : UIElement
|
||||
{
|
||||
if (source != null)
|
||||
{
|
||||
var childs = GetChildObjects(source);
|
||||
foreach (DependencyObject child in childs)
|
||||
{
|
||||
//analyze if children match the requested type
|
||||
if (child != null && child is T dependencyObject && dependencyObject.Uid.Equals(uid))
|
||||
{
|
||||
return dependencyObject;
|
||||
}
|
||||
|
||||
var descendant = FindChildByUid<T>(child, uid);
|
||||
if (descendant != null)
|
||||
return descendant;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This method is an alternative to WPF's
|
||||
/// <see cref="VisualTreeHelper.GetChild"/> method, which also
|
||||
/// supports content elements. Keep in mind that for content elements,
|
||||
/// this method falls back to the logical tree of the element.
|
||||
/// </summary>
|
||||
/// <param name="parent">The item to be processed.</param>
|
||||
/// <returns>The submitted item's child elements, if available.</returns>
|
||||
public static IEnumerable<DependencyObject> GetChildObjects(this DependencyObject parent)
|
||||
{
|
||||
if (parent == null) yield break;
|
||||
|
||||
if (parent is ContentElement || parent is FrameworkElement)
|
||||
{
|
||||
//use the logical tree for content / framework elements
|
||||
foreach (object obj in LogicalTreeHelper.GetChildren(parent))
|
||||
{
|
||||
var depObj = obj as DependencyObject;
|
||||
if (depObj != null) yield return (DependencyObject) obj;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//use the visual tree per default
|
||||
int count = VisualTreeHelper.GetChildrenCount(parent);
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
yield return VisualTreeHelper.GetChild(parent, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
43
FSI.Lib/NLogViewer/Helper/AutoSizedGridView.cs
Normal file
@@ -0,0 +1,43 @@
|
||||
using System;
|
||||
using System.Reactive.Linq;
|
||||
using System.Threading;
|
||||
using System.Windows.Controls;
|
||||
using NLog;
|
||||
|
||||
namespace DJ.Helper
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a view mode that displays data items in columns for a System.Windows.Controls.ListView control with auto sized columns based on the column content
|
||||
/// Used to fix the column width: https://stackoverflow.com/questions/60147905/column-width-adjustment-is-broken-if-using-multibinding-on-displaymemberbinding
|
||||
/// </summary>
|
||||
public class AutoSizedGridView : GridView
|
||||
{
|
||||
private int _MaxLoggerNameLength;
|
||||
|
||||
protected override void PrepareItem(ListViewItem item)
|
||||
{
|
||||
if (item.DataContext is LogEventInfo info)
|
||||
{
|
||||
if (info.LoggerName.Length > _MaxLoggerNameLength)
|
||||
{
|
||||
_MaxLoggerNameLength = info.LoggerName.Length;
|
||||
Observable.Timer(TimeSpan.FromMilliseconds(1)).ObserveOn(SynchronizationContext.Current).Subscribe(l =>
|
||||
{
|
||||
foreach (GridViewColumn column in Columns)
|
||||
{
|
||||
//setting NaN for the column width automatically determines the required width enough to hold the content completely.
|
||||
//if column width was set to NaN already, set it ActualWidth temporarily and set to NaN. This raises the property change event and re computes the width.
|
||||
if (double.IsNaN(column.Width))
|
||||
{
|
||||
column.Width = column.ActualWidth;
|
||||
column.Width = double.NaN;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
base.PrepareItem(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace DJ.Helper.ListViewLayoutManager
|
||||
{
|
||||
public abstract class ConverterGridViewColumn : GridViewColumn, IValueConverter
|
||||
{
|
||||
public Type BindingType => _BindingType;
|
||||
private readonly Type _BindingType;
|
||||
|
||||
// ##############################################################################################################################
|
||||
// Constructor
|
||||
// ##############################################################################################################################
|
||||
|
||||
#region Constructor
|
||||
|
||||
protected ConverterGridViewColumn(Type bindingType)
|
||||
{
|
||||
if (bindingType == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(bindingType));
|
||||
}
|
||||
|
||||
this._BindingType = bindingType;
|
||||
|
||||
Binding binding = new Binding {Mode = BindingMode.OneWay, Converter = this};
|
||||
DisplayMemberBinding = binding;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
// ##############################################################################################################################
|
||||
// IValueConverter
|
||||
// ##############################################################################################################################
|
||||
|
||||
#region IValueConverter
|
||||
|
||||
object IValueConverter.Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (!_BindingType.IsInstanceOfType(value))
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
return ConvertValue(value);
|
||||
}
|
||||
|
||||
object IValueConverter.ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
protected abstract object ConvertValue(object value);
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace DJ.Helper.ListViewLayoutManager
|
||||
{
|
||||
public sealed class FixedColumn : LayoutColumn
|
||||
{
|
||||
public static bool IsFixedColumn(GridViewColumn column)
|
||||
{
|
||||
if (column == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return HasPropertyValue(column, WidthProperty);
|
||||
}
|
||||
|
||||
public static double? GetFixedWidth(GridViewColumn column)
|
||||
{
|
||||
return GetColumnWidth(column, WidthProperty);
|
||||
}
|
||||
|
||||
public static GridViewColumn ApplyWidth(GridViewColumn gridViewColumn, double width)
|
||||
{
|
||||
SetWidth(gridViewColumn, width);
|
||||
return gridViewColumn;
|
||||
}
|
||||
|
||||
// ##############################################################################################################################
|
||||
// AttachedProperties
|
||||
// ##############################################################################################################################
|
||||
|
||||
#region AttachedProperties
|
||||
|
||||
public static double GetWidth(DependencyObject obj)
|
||||
{
|
||||
return (double) obj.GetValue(WidthProperty);
|
||||
}
|
||||
|
||||
public static void SetWidth(DependencyObject obj, double width)
|
||||
{
|
||||
obj.SetValue(WidthProperty, width);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty WidthProperty = DependencyProperty.RegisterAttached("Width", typeof(double), typeof(FixedColumn));
|
||||
|
||||
#endregion
|
||||
|
||||
// ##############################################################################################################################
|
||||
// Constructor
|
||||
// ##############################################################################################################################
|
||||
|
||||
#region Constructor
|
||||
|
||||
private FixedColumn()
|
||||
{
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace DJ.Helper.ListViewLayoutManager
|
||||
{
|
||||
public abstract class ImageGridViewColumn : GridViewColumn, IValueConverter
|
||||
{
|
||||
// ##############################################################################################################################
|
||||
// Constructor
|
||||
// ##############################################################################################################################
|
||||
|
||||
#region Constructor
|
||||
|
||||
protected ImageGridViewColumn(Stretch imageStretch)
|
||||
{
|
||||
FrameworkElementFactory imageElement = new FrameworkElementFactory(typeof(Image));
|
||||
|
||||
Binding imageSourceBinding = new Binding {Converter = this, Mode = BindingMode.OneWay};
|
||||
imageElement.SetBinding(Image.SourceProperty, imageSourceBinding);
|
||||
|
||||
Binding imageStretchBinding = new Binding {Source = imageStretch};
|
||||
imageElement.SetBinding(Image.StretchProperty, imageStretchBinding);
|
||||
|
||||
DataTemplate template = new DataTemplate {VisualTree = imageElement};
|
||||
CellTemplate = template;
|
||||
}
|
||||
|
||||
protected ImageGridViewColumn() : this(Stretch.None)
|
||||
{
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
// ##############################################################################################################################
|
||||
// IValueConverter
|
||||
// ##############################################################################################################################
|
||||
|
||||
#region IValueConverter
|
||||
|
||||
object IValueConverter.Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
return GetImageSource(value);
|
||||
}
|
||||
|
||||
object IValueConverter.ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
protected abstract ImageSource GetImageSource(object value);
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace DJ.Helper.ListViewLayoutManager
|
||||
{
|
||||
public abstract class LayoutColumn
|
||||
{
|
||||
protected static bool HasPropertyValue(GridViewColumn column, DependencyProperty dp)
|
||||
{
|
||||
if (column == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(column));
|
||||
}
|
||||
|
||||
object value = column.ReadLocalValue(dp);
|
||||
if (value?.GetType() == dp.PropertyType)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected static double? GetColumnWidth(GridViewColumn column, DependencyProperty dp)
|
||||
{
|
||||
if (column == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(column));
|
||||
}
|
||||
|
||||
object value = column.ReadLocalValue(dp);
|
||||
if (value?.GetType() == dp.PropertyType)
|
||||
{
|
||||
return (double) value;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,623 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Controls.Primitives;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace DJ.Helper.ListViewLayoutManager
|
||||
{
|
||||
public class ListViewLayoutManager
|
||||
{
|
||||
// ##############################################################################################################################
|
||||
// Properties
|
||||
// ##############################################################################################################################
|
||||
|
||||
#region Properties
|
||||
|
||||
// ##########################################################################################
|
||||
// Public Properties
|
||||
// ##########################################################################################
|
||||
|
||||
public ListView ListView => _ListView;
|
||||
|
||||
public ScrollBarVisibility VerticalScrollBarVisibility
|
||||
{
|
||||
get => _VerticalScrollBarVisibility;
|
||||
set => _VerticalScrollBarVisibility = value;
|
||||
}
|
||||
|
||||
// ##########################################################################################
|
||||
// Private Properties
|
||||
// ##########################################################################################
|
||||
|
||||
private readonly ListView _ListView;
|
||||
private ScrollViewer _ScrollViewer;
|
||||
private bool _Loaded;
|
||||
private bool _Resizing;
|
||||
private Cursor _ResizeCursor;
|
||||
private ScrollBarVisibility _VerticalScrollBarVisibility = ScrollBarVisibility.Auto;
|
||||
private GridViewColumn _AutoSizedColumn;
|
||||
|
||||
private const double _ZERO_WIDTH_RANGE = 0.1;
|
||||
|
||||
#endregion
|
||||
|
||||
// ##############################################################################################################################
|
||||
// AttachedProperties
|
||||
// ##############################################################################################################################
|
||||
|
||||
#region AttachedProperties
|
||||
|
||||
public static void SetEnabled(DependencyObject dependencyObject, bool enabled)
|
||||
{
|
||||
dependencyObject.SetValue(EnabledProperty, enabled);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty EnabledProperty = DependencyProperty.RegisterAttached("Enabled",
|
||||
typeof(bool), typeof(ListViewLayoutManager), new FrameworkPropertyMetadata(_OnLayoutManagerEnabledChanged));
|
||||
|
||||
#endregion
|
||||
|
||||
// ##############################################################################################################################
|
||||
// Constructor
|
||||
// ##############################################################################################################################
|
||||
|
||||
#region Constructor
|
||||
|
||||
public ListViewLayoutManager(ListView listView)
|
||||
{
|
||||
_ListView = listView ?? throw new ArgumentNullException(nameof(listView));
|
||||
_ListView.Loaded += ListView_Loaded;
|
||||
_ListView.Unloaded += ListView_Unloaded;
|
||||
}
|
||||
|
||||
private void ListView_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
_RegisterEvents(_ListView);
|
||||
_InitColumns();
|
||||
_DoResizeColumns();
|
||||
_Loaded = true;
|
||||
}
|
||||
|
||||
|
||||
private void ListView_Unloaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (!_Loaded)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_UnRegisterEvents(_ListView);
|
||||
_Loaded = false;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
// ##############################################################################################################################
|
||||
// public methods
|
||||
// ##############################################################################################################################
|
||||
|
||||
#region public methods
|
||||
|
||||
public void Refresh()
|
||||
{
|
||||
_InitColumns();
|
||||
_DoResizeColumns();
|
||||
}
|
||||
|
||||
protected virtual void ResizeColumns()
|
||||
{
|
||||
GridView view = _ListView.View as GridView;
|
||||
if (view == null || view.Columns.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// listview width
|
||||
double actualWidth = double.PositiveInfinity;
|
||||
if (_ScrollViewer != null)
|
||||
{
|
||||
actualWidth = _ScrollViewer.ViewportWidth;
|
||||
}
|
||||
|
||||
if (double.IsInfinity(actualWidth))
|
||||
{
|
||||
actualWidth = _ListView.ActualWidth;
|
||||
}
|
||||
|
||||
if (double.IsInfinity(actualWidth) || actualWidth <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
double resizeableRegionCount = 0;
|
||||
double otherColumnsWidth = 0;
|
||||
// determine column sizes
|
||||
foreach (GridViewColumn gridViewColumn in view.Columns)
|
||||
{
|
||||
if (ProportionalColumn.IsProportionalColumn(gridViewColumn))
|
||||
{
|
||||
double? proportionalWidth = ProportionalColumn.GetProportionalWidth(gridViewColumn);
|
||||
if (proportionalWidth != null)
|
||||
{
|
||||
resizeableRegionCount += proportionalWidth.Value;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
otherColumnsWidth += gridViewColumn.ActualWidth;
|
||||
}
|
||||
}
|
||||
|
||||
if (resizeableRegionCount <= 0)
|
||||
{
|
||||
// no proportional columns present: commit the regulation to the scroll viewer
|
||||
if (_ScrollViewer != null)
|
||||
{
|
||||
_ScrollViewer.HorizontalScrollBarVisibility = ScrollBarVisibility.Auto;
|
||||
}
|
||||
|
||||
// search the first fill column
|
||||
GridViewColumn fillColumn = null;
|
||||
for (int i = 0; i < view.Columns.Count; i++)
|
||||
{
|
||||
GridViewColumn gridViewColumn = view.Columns[i];
|
||||
if (_IsFillColumn(gridViewColumn))
|
||||
{
|
||||
fillColumn = gridViewColumn;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (fillColumn != null)
|
||||
{
|
||||
double otherColumnsWithoutFillWidth = otherColumnsWidth - fillColumn.ActualWidth;
|
||||
double fillWidth = actualWidth - otherColumnsWithoutFillWidth;
|
||||
if (fillWidth > 0)
|
||||
{
|
||||
double? minWidth = RangeColumn.GetRangeMinWidth(fillColumn);
|
||||
double? maxWidth = RangeColumn.GetRangeMaxWidth(fillColumn);
|
||||
|
||||
bool setWidth = !(minWidth.HasValue && fillWidth < minWidth.Value);
|
||||
if (maxWidth.HasValue && fillWidth > maxWidth.Value)
|
||||
{
|
||||
setWidth = false;
|
||||
}
|
||||
|
||||
if (setWidth)
|
||||
{
|
||||
if (_ScrollViewer != null)
|
||||
{
|
||||
_ScrollViewer.HorizontalScrollBarVisibility = ScrollBarVisibility.Hidden;
|
||||
}
|
||||
|
||||
fillColumn.Width = fillWidth;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
double resizeableColumnsWidth = actualWidth - otherColumnsWidth;
|
||||
if (resizeableColumnsWidth <= 0)
|
||||
{
|
||||
return; // missing space
|
||||
}
|
||||
|
||||
// resize columns
|
||||
double resizeableRegionWidth = resizeableColumnsWidth / resizeableRegionCount;
|
||||
foreach (GridViewColumn gridViewColumn in view.Columns)
|
||||
{
|
||||
if (ProportionalColumn.IsProportionalColumn(gridViewColumn))
|
||||
{
|
||||
double? proportionalWidth = ProportionalColumn.GetProportionalWidth(gridViewColumn);
|
||||
if (proportionalWidth != null)
|
||||
{
|
||||
gridViewColumn.Width = proportionalWidth.Value * resizeableRegionWidth;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
// ##############################################################################################################################
|
||||
// private methods
|
||||
// ##############################################################################################################################
|
||||
|
||||
#region private methods
|
||||
|
||||
private void _DoResizeColumns()
|
||||
{
|
||||
if (_Resizing)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_Resizing = true;
|
||||
try
|
||||
{
|
||||
ResizeColumns();
|
||||
}
|
||||
finally
|
||||
{
|
||||
_Resizing = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void _RegisterEvents(DependencyObject start)
|
||||
{
|
||||
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(start); i++)
|
||||
{
|
||||
Visual childVisual = VisualTreeHelper.GetChild(start, i) as Visual;
|
||||
if (childVisual is Thumb)
|
||||
{
|
||||
GridViewColumn gridViewColumn = _FindParentColumn(childVisual);
|
||||
if (gridViewColumn != null)
|
||||
{
|
||||
Thumb thumb = childVisual as Thumb;
|
||||
if (ProportionalColumn.IsProportionalColumn(gridViewColumn) ||
|
||||
FixedColumn.IsFixedColumn(gridViewColumn) || _IsFillColumn(gridViewColumn))
|
||||
{
|
||||
thumb.IsHitTestVisible = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
thumb.PreviewMouseMove += _ThumbPreviewMouseMove;
|
||||
thumb.PreviewMouseLeftButtonDown +=
|
||||
_ThumbPreviewMouseLeftButtonDown;
|
||||
DependencyPropertyDescriptor.FromProperty(
|
||||
GridViewColumn.WidthProperty,
|
||||
typeof(GridViewColumn)).AddValueChanged(gridViewColumn, _GridColumnWidthChanged);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (childVisual is GridViewColumnHeader)
|
||||
{
|
||||
GridViewColumnHeader columnHeader = childVisual as GridViewColumnHeader;
|
||||
columnHeader.SizeChanged += _GridColumnHeaderSizeChanged;
|
||||
}
|
||||
else if (_ScrollViewer == null && childVisual is ScrollViewer)
|
||||
{
|
||||
_ScrollViewer = childVisual as ScrollViewer;
|
||||
_ScrollViewer.ScrollChanged += _ScrollViewerScrollChanged;
|
||||
// assume we do the regulation of the horizontal scrollbar
|
||||
_ScrollViewer.HorizontalScrollBarVisibility = ScrollBarVisibility.Hidden;
|
||||
_ScrollViewer.VerticalScrollBarVisibility = _VerticalScrollBarVisibility;
|
||||
}
|
||||
|
||||
_RegisterEvents(childVisual);
|
||||
}
|
||||
}
|
||||
|
||||
private void _UnRegisterEvents(DependencyObject start)
|
||||
{
|
||||
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(start); i++)
|
||||
{
|
||||
Visual childVisual = VisualTreeHelper.GetChild(start, i) as Visual;
|
||||
if (childVisual is Thumb)
|
||||
{
|
||||
GridViewColumn gridViewColumn = _FindParentColumn(childVisual);
|
||||
if (gridViewColumn != null)
|
||||
{
|
||||
Thumb thumb = childVisual as Thumb;
|
||||
if (ProportionalColumn.IsProportionalColumn(gridViewColumn) ||
|
||||
FixedColumn.IsFixedColumn(gridViewColumn) || _IsFillColumn(gridViewColumn))
|
||||
{
|
||||
thumb.IsHitTestVisible = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
thumb.PreviewMouseMove -= _ThumbPreviewMouseMove;
|
||||
thumb.PreviewMouseLeftButtonDown -=
|
||||
_ThumbPreviewMouseLeftButtonDown;
|
||||
DependencyPropertyDescriptor.FromProperty(
|
||||
GridViewColumn.WidthProperty,
|
||||
typeof(GridViewColumn)).RemoveValueChanged(gridViewColumn, _GridColumnWidthChanged);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (childVisual is GridViewColumnHeader)
|
||||
{
|
||||
GridViewColumnHeader columnHeader = childVisual as GridViewColumnHeader;
|
||||
columnHeader.SizeChanged -= _GridColumnHeaderSizeChanged;
|
||||
}
|
||||
else if (_ScrollViewer == null && childVisual is ScrollViewer)
|
||||
{
|
||||
_ScrollViewer = childVisual as ScrollViewer;
|
||||
_ScrollViewer.ScrollChanged -= _ScrollViewerScrollChanged;
|
||||
}
|
||||
|
||||
_UnRegisterEvents(childVisual);
|
||||
}
|
||||
}
|
||||
|
||||
private GridViewColumn _FindParentColumn(DependencyObject element)
|
||||
{
|
||||
if (element == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
while (element != null)
|
||||
{
|
||||
GridViewColumnHeader gridViewColumnHeader = element as GridViewColumnHeader;
|
||||
if (gridViewColumnHeader != null)
|
||||
{
|
||||
return (gridViewColumnHeader).Column;
|
||||
}
|
||||
|
||||
element = VisualTreeHelper.GetParent(element);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private GridViewColumnHeader _FindColumnHeader(DependencyObject start, GridViewColumn gridViewColumn)
|
||||
{
|
||||
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(start); i++)
|
||||
{
|
||||
Visual childVisual = VisualTreeHelper.GetChild(start, i) as Visual;
|
||||
if (childVisual is GridViewColumnHeader)
|
||||
{
|
||||
GridViewColumnHeader gridViewHeader = childVisual as GridViewColumnHeader;
|
||||
if (gridViewHeader.Column == gridViewColumn)
|
||||
{
|
||||
return gridViewHeader;
|
||||
}
|
||||
}
|
||||
|
||||
GridViewColumnHeader childGridViewHeader = _FindColumnHeader(childVisual, gridViewColumn);
|
||||
if (childGridViewHeader != null)
|
||||
{
|
||||
return childGridViewHeader;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void _InitColumns()
|
||||
{
|
||||
GridView view = _ListView.View as GridView;
|
||||
if (view == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (GridViewColumn gridViewColumn in view.Columns)
|
||||
{
|
||||
if (!RangeColumn.IsRangeColumn(gridViewColumn))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
double? minWidth = RangeColumn.GetRangeMinWidth(gridViewColumn);
|
||||
double? maxWidth = RangeColumn.GetRangeMaxWidth(gridViewColumn);
|
||||
if (!minWidth.HasValue && !maxWidth.HasValue)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
GridViewColumnHeader columnHeader = _FindColumnHeader(_ListView, gridViewColumn);
|
||||
if (columnHeader == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
double actualWidth = columnHeader.ActualWidth;
|
||||
if (minWidth.HasValue)
|
||||
{
|
||||
columnHeader.MinWidth = minWidth.Value;
|
||||
if (!double.IsInfinity(actualWidth) && actualWidth < columnHeader.MinWidth)
|
||||
{
|
||||
gridViewColumn.Width = columnHeader.MinWidth;
|
||||
}
|
||||
}
|
||||
|
||||
if (maxWidth.HasValue)
|
||||
{
|
||||
columnHeader.MaxWidth = maxWidth.Value;
|
||||
if (!double.IsInfinity(actualWidth) && actualWidth > columnHeader.MaxWidth)
|
||||
{
|
||||
gridViewColumn.Width = columnHeader.MaxWidth;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// returns the delta
|
||||
private double _SetRangeColumnToBounds(GridViewColumn gridViewColumn)
|
||||
{
|
||||
double startWidth = gridViewColumn.Width;
|
||||
|
||||
double? minWidth = RangeColumn.GetRangeMinWidth(gridViewColumn);
|
||||
double? maxWidth = RangeColumn.GetRangeMaxWidth(gridViewColumn);
|
||||
|
||||
if ((minWidth.HasValue && maxWidth.HasValue) && (minWidth > maxWidth))
|
||||
{
|
||||
return 0; // invalid case
|
||||
}
|
||||
|
||||
if (minWidth.HasValue && gridViewColumn.Width < minWidth.Value)
|
||||
{
|
||||
gridViewColumn.Width = minWidth.Value;
|
||||
}
|
||||
else if (maxWidth.HasValue && gridViewColumn.Width > maxWidth.Value)
|
||||
{
|
||||
gridViewColumn.Width = maxWidth.Value;
|
||||
}
|
||||
|
||||
return gridViewColumn.Width - startWidth;
|
||||
}
|
||||
|
||||
private bool _IsFillColumn(GridViewColumn gridViewColumn)
|
||||
{
|
||||
if (gridViewColumn == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
GridView view = _ListView.View as GridView;
|
||||
if (view == null || view.Columns.Count == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool? isFillColumn = RangeColumn.GetRangeIsFillColumn(gridViewColumn);
|
||||
return isFillColumn.HasValue && isFillColumn.Value;
|
||||
}
|
||||
|
||||
private void _ThumbPreviewMouseMove(object sender, MouseEventArgs e)
|
||||
{
|
||||
Thumb thumb = sender as Thumb;
|
||||
if (thumb == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
GridViewColumn gridViewColumn = _FindParentColumn(thumb);
|
||||
if (gridViewColumn == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// suppress column resizing for proportional, fixed and range fill columns
|
||||
if (ProportionalColumn.IsProportionalColumn(gridViewColumn) ||
|
||||
FixedColumn.IsFixedColumn(gridViewColumn) ||
|
||||
_IsFillColumn(gridViewColumn))
|
||||
{
|
||||
thumb.Cursor = null;
|
||||
return;
|
||||
}
|
||||
|
||||
// check range column bounds
|
||||
if (thumb.IsMouseCaptured && RangeColumn.IsRangeColumn(gridViewColumn))
|
||||
{
|
||||
double? minWidth = RangeColumn.GetRangeMinWidth(gridViewColumn);
|
||||
double? maxWidth = RangeColumn.GetRangeMaxWidth(gridViewColumn);
|
||||
|
||||
if ((minWidth.HasValue && maxWidth.HasValue) && (minWidth > maxWidth))
|
||||
{
|
||||
return; // invalid case
|
||||
}
|
||||
|
||||
if (_ResizeCursor == null)
|
||||
{
|
||||
_ResizeCursor = thumb.Cursor; // save the resize cursor
|
||||
}
|
||||
|
||||
if (minWidth.HasValue && gridViewColumn.Width <= minWidth.Value)
|
||||
{
|
||||
thumb.Cursor = Cursors.No;
|
||||
}
|
||||
else if (maxWidth.HasValue && gridViewColumn.Width >= maxWidth.Value)
|
||||
{
|
||||
thumb.Cursor = Cursors.No;
|
||||
}
|
||||
else
|
||||
{
|
||||
thumb.Cursor = _ResizeCursor; // between valid min/max
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void _ThumbPreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
Thumb thumb = sender as Thumb;
|
||||
GridViewColumn gridViewColumn = _FindParentColumn(thumb);
|
||||
|
||||
// suppress column resizing for proportional, fixed and range fill columns
|
||||
if (ProportionalColumn.IsProportionalColumn(gridViewColumn) ||
|
||||
FixedColumn.IsFixedColumn(gridViewColumn) ||
|
||||
_IsFillColumn(gridViewColumn))
|
||||
{
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void _GridColumnWidthChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (!_Loaded)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
GridViewColumn gridViewColumn = sender as GridViewColumn;
|
||||
|
||||
// suppress column resizing for proportional and fixed columns
|
||||
if (ProportionalColumn.IsProportionalColumn(gridViewColumn) || FixedColumn.IsFixedColumn(gridViewColumn))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// ensure range column within the bounds
|
||||
if (RangeColumn.IsRangeColumn(gridViewColumn))
|
||||
{
|
||||
// special case: auto column width - maybe conflicts with min/max range
|
||||
if (gridViewColumn != null && gridViewColumn.Width.Equals(double.NaN))
|
||||
{
|
||||
_AutoSizedColumn = gridViewColumn;
|
||||
return; // handled by the change header size event
|
||||
}
|
||||
|
||||
// ensure column bounds
|
||||
if (Math.Abs(_SetRangeColumnToBounds(gridViewColumn) - 0) > _ZERO_WIDTH_RANGE)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
_DoResizeColumns();
|
||||
}
|
||||
|
||||
// handle autosized column
|
||||
private void _GridColumnHeaderSizeChanged(object sender, SizeChangedEventArgs e)
|
||||
{
|
||||
if (_AutoSizedColumn == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
GridViewColumnHeader gridViewColumnHeader = sender as GridViewColumnHeader;
|
||||
if (gridViewColumnHeader != null && gridViewColumnHeader.Column == _AutoSizedColumn)
|
||||
{
|
||||
if (gridViewColumnHeader.Width.Equals(double.NaN))
|
||||
{
|
||||
// sync column with
|
||||
gridViewColumnHeader.Column.Width = gridViewColumnHeader.ActualWidth;
|
||||
_DoResizeColumns();
|
||||
}
|
||||
|
||||
_AutoSizedColumn = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void _ScrollViewerScrollChanged(object sender, ScrollChangedEventArgs e)
|
||||
{
|
||||
if (_Loaded && Math.Abs(e.ViewportWidthChange - 0) > _ZERO_WIDTH_RANGE)
|
||||
{
|
||||
_DoResizeColumns();
|
||||
}
|
||||
}
|
||||
|
||||
private static void _OnLayoutManagerEnabledChanged(DependencyObject dependencyObject,
|
||||
DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
ListView listView = dependencyObject as ListView;
|
||||
if (listView != null)
|
||||
{
|
||||
bool enabled = (bool) e.NewValue;
|
||||
if (enabled)
|
||||
{
|
||||
new ListViewLayoutManager(listView);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace DJ.Helper.ListViewLayoutManager
|
||||
{
|
||||
public sealed class ProportionalColumn : LayoutColumn
|
||||
{
|
||||
public static bool IsProportionalColumn(GridViewColumn column)
|
||||
{
|
||||
if (column == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return HasPropertyValue(column, WidthProperty);
|
||||
}
|
||||
|
||||
public static double? GetProportionalWidth(GridViewColumn column)
|
||||
{
|
||||
return GetColumnWidth(column, WidthProperty);
|
||||
}
|
||||
|
||||
public static GridViewColumn ApplyWidth(GridViewColumn gridViewColumn, double width)
|
||||
{
|
||||
SetWidth(gridViewColumn, width);
|
||||
return gridViewColumn;
|
||||
}
|
||||
|
||||
// ##############################################################################################################################
|
||||
// AttachedProperties
|
||||
// ##############################################################################################################################
|
||||
|
||||
#region AttachedProperties
|
||||
|
||||
public static double GetWidth(DependencyObject obj)
|
||||
{
|
||||
return (double) obj.GetValue(WidthProperty);
|
||||
}
|
||||
|
||||
public static void SetWidth(DependencyObject obj, double width)
|
||||
{
|
||||
obj.SetValue(WidthProperty, width);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty WidthProperty = DependencyProperty.RegisterAttached("Width", typeof(double), typeof(ProportionalColumn));
|
||||
|
||||
#endregion
|
||||
|
||||
// ##############################################################################################################################
|
||||
// Constructor
|
||||
// ##############################################################################################################################
|
||||
|
||||
#region Constructor
|
||||
|
||||
private ProportionalColumn()
|
||||
{
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
136
FSI.Lib/NLogViewer/Helper/ListViewLayoutManager/RangeColumn.cs
Normal file
@@ -0,0 +1,136 @@
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace DJ.Helper.ListViewLayoutManager
|
||||
{
|
||||
|
||||
|
||||
public sealed class RangeColumn : LayoutColumn
|
||||
{
|
||||
|
||||
|
||||
public static readonly DependencyProperty MinWidthProperty =
|
||||
DependencyProperty.RegisterAttached(
|
||||
"MinWidth",
|
||||
typeof( double ),
|
||||
typeof( RangeColumn ) );
|
||||
|
||||
|
||||
public static readonly DependencyProperty MaxWidthProperty =
|
||||
DependencyProperty.RegisterAttached(
|
||||
"MaxWidth",
|
||||
typeof( double ),
|
||||
typeof( RangeColumn ) );
|
||||
|
||||
|
||||
public static readonly DependencyProperty IsFillColumnProperty =
|
||||
DependencyProperty.RegisterAttached(
|
||||
"IsFillColumn",
|
||||
typeof( bool ),
|
||||
typeof( RangeColumn ) );
|
||||
|
||||
|
||||
private RangeColumn()
|
||||
{
|
||||
} // RangeColumn
|
||||
|
||||
|
||||
public static double GetMinWidth( DependencyObject obj )
|
||||
{
|
||||
return (double)obj.GetValue( MinWidthProperty );
|
||||
} // GetMinWidth
|
||||
|
||||
|
||||
public static void SetMinWidth( DependencyObject obj, double minWidth )
|
||||
{
|
||||
obj.SetValue( MinWidthProperty, minWidth );
|
||||
} // SetMinWidth
|
||||
|
||||
|
||||
public static double GetMaxWidth( DependencyObject obj )
|
||||
{
|
||||
return (double)obj.GetValue( MaxWidthProperty );
|
||||
} // GetMaxWidth
|
||||
|
||||
|
||||
public static void SetMaxWidth( DependencyObject obj, double maxWidth )
|
||||
{
|
||||
obj.SetValue( MaxWidthProperty, maxWidth );
|
||||
} // SetMaxWidth
|
||||
|
||||
|
||||
public static bool GetIsFillColumn( DependencyObject obj )
|
||||
{
|
||||
return (bool)obj.GetValue( IsFillColumnProperty );
|
||||
} // GetIsFillColumn
|
||||
|
||||
|
||||
public static void SetIsFillColumn( DependencyObject obj, bool isFillColumn )
|
||||
{
|
||||
obj.SetValue( IsFillColumnProperty, isFillColumn );
|
||||
} // SetIsFillColumn
|
||||
|
||||
|
||||
public static bool IsRangeColumn( GridViewColumn column )
|
||||
{
|
||||
if ( column == null )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return
|
||||
HasPropertyValue( column, MinWidthProperty ) ||
|
||||
HasPropertyValue( column, MaxWidthProperty ) ||
|
||||
HasPropertyValue( column, IsFillColumnProperty );
|
||||
} // IsRangeColumn
|
||||
|
||||
|
||||
public static double? GetRangeMinWidth( GridViewColumn column )
|
||||
{
|
||||
return GetColumnWidth( column, MinWidthProperty );
|
||||
} // GetRangeMinWidth
|
||||
|
||||
|
||||
public static double? GetRangeMaxWidth( GridViewColumn column )
|
||||
{
|
||||
return GetColumnWidth( column, MaxWidthProperty );
|
||||
} // GetRangeMaxWidth
|
||||
|
||||
|
||||
public static bool? GetRangeIsFillColumn( GridViewColumn column )
|
||||
{
|
||||
if ( column == null )
|
||||
{
|
||||
throw new ArgumentNullException( nameof(column) );
|
||||
}
|
||||
object value = column.ReadLocalValue( IsFillColumnProperty );
|
||||
if ( value != null && value.GetType() == IsFillColumnProperty.PropertyType )
|
||||
{
|
||||
return (bool)value;
|
||||
}
|
||||
|
||||
return null;
|
||||
} // GetRangeIsFillColumn
|
||||
|
||||
|
||||
public static GridViewColumn ApplyWidth( GridViewColumn gridViewColumn, double minWidth,
|
||||
double width, double maxWidth )
|
||||
{
|
||||
return ApplyWidth( gridViewColumn, minWidth, width, maxWidth, false );
|
||||
} // ApplyWidth
|
||||
|
||||
|
||||
public static GridViewColumn ApplyWidth( GridViewColumn gridViewColumn, double minWidth,
|
||||
double width, double maxWidth, bool isFillColumn )
|
||||
{
|
||||
SetMinWidth( gridViewColumn, minWidth );
|
||||
gridViewColumn.Width = width;
|
||||
SetMaxWidth( gridViewColumn, maxWidth );
|
||||
SetIsFillColumn( gridViewColumn, isFillColumn );
|
||||
return gridViewColumn;
|
||||
} // ApplyWidth
|
||||
|
||||
} // class RangeColumn
|
||||
|
||||
} // namespace Itenso.Windows.Controls.ListViewLayout
|
||||
// -- EOF -------------------------------------------------------------------
|
||||
28
FSI.Lib/NLogViewer/Helper/PredicateBuilder.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
|
||||
namespace DJ.Helper
|
||||
{
|
||||
public static class PredicateBuilder
|
||||
{
|
||||
public static Expression<Func<T, bool>> True<T> () { return f => true; }
|
||||
public static Expression<Func<T, bool>> False<T> () { return f => false; }
|
||||
|
||||
public static Expression<Func<T, bool>> Or<T> (this Expression<Func<T, bool>> expr1,
|
||||
Expression<Func<T, bool>> expr2)
|
||||
{
|
||||
var invokedExpr = Expression.Invoke (expr2, expr1.Parameters.Cast<Expression> ());
|
||||
return Expression.Lambda<Func<T, bool>>
|
||||
(Expression.OrElse (expr1.Body, invokedExpr), expr1.Parameters);
|
||||
}
|
||||
|
||||
public static Expression<Func<T, bool>> And<T> (this Expression<Func<T, bool>> expr1,
|
||||
Expression<Func<T, bool>> expr2)
|
||||
{
|
||||
var invokedExpr = Expression.Invoke (expr2, expr1.Parameters.Cast<Expression> ());
|
||||
return Expression.Lambda<Func<T, bool>>
|
||||
(Expression.AndAlso (expr1.Body, invokedExpr), expr1.Parameters);
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
FSI.Lib/NLogViewer/Images/Glyphs/SortDownArrow.png
Normal file
|
After Width: | Height: | Size: 264 B |
BIN
FSI.Lib/NLogViewer/Images/Glyphs/SortUpArrow.png
Normal file
|
After Width: | Height: | Size: 278 B |
BIN
FSI.Lib/NLogViewer/Images/Large/Add.png
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
BIN
FSI.Lib/NLogViewer/Images/Large/Context.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
FSI.Lib/NLogViewer/Images/Large/Debug.png
Normal file
|
After Width: | Height: | Size: 3.9 KiB |
BIN
FSI.Lib/NLogViewer/Images/Large/DebugSource.png
Normal file
|
After Width: | Height: | Size: 984 B |
BIN
FSI.Lib/NLogViewer/Images/Large/Error.png
Normal file
|
After Width: | Height: | Size: 5.7 KiB |
BIN
FSI.Lib/NLogViewer/Images/Large/Exception.png
Normal file
|
After Width: | Height: | Size: 6.3 KiB |
BIN
FSI.Lib/NLogViewer/Images/Large/Exit.png
Normal file
|
After Width: | Height: | Size: 6.6 KiB |
BIN
FSI.Lib/NLogViewer/Images/Large/Export.png
Normal file
|
After Width: | Height: | Size: 4.0 KiB |
BIN
FSI.Lib/NLogViewer/Images/Large/Fatal.png
Normal file
|
After Width: | Height: | Size: 5.6 KiB |
BIN
FSI.Lib/NLogViewer/Images/Large/Info.png
Normal file
|
After Width: | Height: | Size: 4.3 KiB |
BIN
FSI.Lib/NLogViewer/Images/Large/Network.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
FSI.Lib/NLogViewer/Images/Large/Open.png
Normal file
|
After Width: | Height: | Size: 5.2 KiB |
BIN
FSI.Lib/NLogViewer/Images/Large/Save.png
Normal file
|
After Width: | Height: | Size: 2.9 KiB |
BIN
FSI.Lib/NLogViewer/Images/Large/Settings.png
Normal file
|
After Width: | Height: | Size: 7.0 KiB |
BIN
FSI.Lib/NLogViewer/Images/Large/Thread.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
FSI.Lib/NLogViewer/Images/Large/Trace.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
FSI.Lib/NLogViewer/Images/Large/Unknown.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
FSI.Lib/NLogViewer/Images/Large/Warning.png
Normal file
|
After Width: | Height: | Size: 5.6 KiB |
BIN
FSI.Lib/NLogViewer/Images/Medium/Add.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
FSI.Lib/NLogViewer/Images/Medium/Debug.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
FSI.Lib/NLogViewer/Images/Medium/Error.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
FSI.Lib/NLogViewer/Images/Medium/Exception.png
Normal file
|
After Width: | Height: | Size: 2.4 KiB |
BIN
FSI.Lib/NLogViewer/Images/Medium/Exit.png
Normal file
|
After Width: | Height: | Size: 4.6 KiB |
BIN
FSI.Lib/NLogViewer/Images/Medium/Export.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
FSI.Lib/NLogViewer/Images/Medium/Fatal.png
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
FSI.Lib/NLogViewer/Images/Medium/Info.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
FSI.Lib/NLogViewer/Images/Medium/Network.png
Normal file
|
After Width: | Height: | Size: 787 B |
BIN
FSI.Lib/NLogViewer/Images/Medium/Open.png
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
FSI.Lib/NLogViewer/Images/Medium/Save.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
FSI.Lib/NLogViewer/Images/Medium/Settings.png
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
BIN
FSI.Lib/NLogViewer/Images/Medium/Thread.png
Normal file
|
After Width: | Height: | Size: 3.3 KiB |
BIN
FSI.Lib/NLogViewer/Images/Medium/Trace.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
FSI.Lib/NLogViewer/Images/Medium/Unknown.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
FSI.Lib/NLogViewer/Images/Medium/Warning.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
FSI.Lib/NLogViewer/Images/Small/Add.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
FSI.Lib/NLogViewer/Images/Small/Clear.png
Normal file
|
After Width: | Height: | Size: 475 B |
BIN
FSI.Lib/NLogViewer/Images/Small/Clock.png
Normal file
|
After Width: | Height: | Size: 365 B |
BIN
FSI.Lib/NLogViewer/Images/Small/Context.png
Normal file
|
After Width: | Height: | Size: 451 B |
BIN
FSI.Lib/NLogViewer/Images/Small/Debug.png
Normal file
|
After Width: | Height: | Size: 774 B |
BIN
FSI.Lib/NLogViewer/Images/Small/DebugSource.png
Normal file
|
After Width: | Height: | Size: 400 B |
BIN
FSI.Lib/NLogViewer/Images/Small/Error.png
Normal file
|
After Width: | Height: | Size: 782 B |
BIN
FSI.Lib/NLogViewer/Images/Small/Exception.png
Normal file
|
After Width: | Height: | Size: 943 B |
BIN
FSI.Lib/NLogViewer/Images/Small/Exit.png
Normal file
|
After Width: | Height: | Size: 629 B |
BIN
FSI.Lib/NLogViewer/Images/Small/Export.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
FSI.Lib/NLogViewer/Images/Small/Fatal.png
Normal file
|
After Width: | Height: | Size: 589 B |
BIN
FSI.Lib/NLogViewer/Images/Small/Info.png
Normal file
|
After Width: | Height: | Size: 778 B |
BIN
FSI.Lib/NLogViewer/Images/Small/Layout.png
Normal file
|
After Width: | Height: | Size: 372 B |
BIN
FSI.Lib/NLogViewer/Images/Small/MonoLightning.png
Normal file
|
After Width: | Height: | Size: 520 B |
BIN
FSI.Lib/NLogViewer/Images/Small/Network.png
Normal file
|
After Width: | Height: | Size: 506 B |
BIN
FSI.Lib/NLogViewer/Images/Small/Open.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
FSI.Lib/NLogViewer/Images/Small/Pause.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
FSI.Lib/NLogViewer/Images/Small/Save.png
Normal file
|
After Width: | Height: | Size: 1.0 KiB |
BIN
FSI.Lib/NLogViewer/Images/Small/ScrollDown.png
Normal file
|
After Width: | Height: | Size: 623 B |
BIN
FSI.Lib/NLogViewer/Images/Small/Settings.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
FSI.Lib/NLogViewer/Images/Small/Thread.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
FSI.Lib/NLogViewer/Images/Small/Trace.png
Normal file
|
After Width: | Height: | Size: 631 B |
BIN
FSI.Lib/NLogViewer/Images/Small/Unknown.png
Normal file
|
After Width: | Height: | Size: 582 B |
BIN
FSI.Lib/NLogViewer/Images/Small/Warning.png
Normal file
|
After Width: | Height: | Size: 813 B |
154
FSI.Lib/NLogViewer/NLogViewer.csproj
Normal file
@@ -0,0 +1,154 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6-windows</TargetFramework>
|
||||
<UseWPF>true</UseWPF>
|
||||
<RootNamespace>DJ</RootNamespace>
|
||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||
<PackageId>Sentinel.NLogViewer</PackageId>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="Images\Glyphs\SortDownArrow.png" />
|
||||
<None Remove="Images\Glyphs\SortUpArrow.png" />
|
||||
<None Remove="Images\Large\Add.png" />
|
||||
<None Remove="Images\Large\Context.png" />
|
||||
<None Remove="Images\Large\Debug.png" />
|
||||
<None Remove="Images\Large\DebugSource.png" />
|
||||
<None Remove="Images\Large\Error.png" />
|
||||
<None Remove="Images\Large\Exception.png" />
|
||||
<None Remove="Images\Large\Exit.png" />
|
||||
<None Remove="Images\Large\Export.png" />
|
||||
<None Remove="Images\Large\Fatal.png" />
|
||||
<None Remove="Images\Large\Info.png" />
|
||||
<None Remove="Images\Large\Network.png" />
|
||||
<None Remove="Images\Large\Open.png" />
|
||||
<None Remove="Images\Large\Save.png" />
|
||||
<None Remove="Images\Large\Settings.png" />
|
||||
<None Remove="Images\Large\Thread.png" />
|
||||
<None Remove="Images\Large\Trace.png" />
|
||||
<None Remove="Images\Large\Unknown.png" />
|
||||
<None Remove="Images\Large\Warning.png" />
|
||||
<None Remove="Images\Medium\Add.png" />
|
||||
<None Remove="Images\Medium\Debug.png" />
|
||||
<None Remove="Images\Medium\Error.png" />
|
||||
<None Remove="Images\Medium\Exception.png" />
|
||||
<None Remove="Images\Medium\Exit.png" />
|
||||
<None Remove="Images\Medium\Export.png" />
|
||||
<None Remove="Images\Medium\Fatal.png" />
|
||||
<None Remove="Images\Medium\Info.png" />
|
||||
<None Remove="Images\Medium\Network.png" />
|
||||
<None Remove="Images\Medium\Open.png" />
|
||||
<None Remove="Images\Medium\Save.png" />
|
||||
<None Remove="Images\Medium\Settings.png" />
|
||||
<None Remove="Images\Medium\Thread.png" />
|
||||
<None Remove="Images\Medium\Trace.png" />
|
||||
<None Remove="Images\Medium\Unknown.png" />
|
||||
<None Remove="Images\Medium\Warning.png" />
|
||||
<None Remove="Images\Small\Add.png" />
|
||||
<None Remove="Images\Small\Clear.png" />
|
||||
<None Remove="Images\Small\Clock.png" />
|
||||
<None Remove="Images\Small\Context.png" />
|
||||
<None Remove="Images\Small\Debug.png" />
|
||||
<None Remove="Images\Small\DebugSource.png" />
|
||||
<None Remove="Images\Small\Error.png" />
|
||||
<None Remove="Images\Small\Exception.png" />
|
||||
<None Remove="Images\Small\Exit.png" />
|
||||
<None Remove="Images\Small\Export.png" />
|
||||
<None Remove="Images\Small\Fatal.png" />
|
||||
<None Remove="Images\Small\Info.png" />
|
||||
<None Remove="Images\Small\Layout.png" />
|
||||
<None Remove="Images\Small\MonoLightning.png" />
|
||||
<None Remove="Images\Small\Network.png" />
|
||||
<None Remove="Images\Small\Open.png" />
|
||||
<None Remove="Images\Small\Pause.png" />
|
||||
<None Remove="Images\Small\Save.png" />
|
||||
<None Remove="Images\Small\ScrollDown.png" />
|
||||
<None Remove="Images\Small\Settings.png" />
|
||||
<None Remove="Images\Small\Thread.png" />
|
||||
<None Remove="Images\Small\Trace.png" />
|
||||
<None Remove="Images\Small\Unknown.png" />
|
||||
<None Remove="Images\Small\Warning.png" />
|
||||
<None Remove="NLogViewer.xaml" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="GitVersion.MsBuild" Version="5.10.3">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="NLog" Version="5.0.1" />
|
||||
<PackageReference Include="System.Reactive" Version="5.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Resource Include="Images\Glyphs\SortDownArrow.png" />
|
||||
<Resource Include="Images\Glyphs\SortUpArrow.png" />
|
||||
<Resource Include="Images\Large\Add.png" />
|
||||
<Resource Include="Images\Large\Context.png" />
|
||||
<Resource Include="Images\Large\Debug.png" />
|
||||
<Resource Include="Images\Large\DebugSource.png" />
|
||||
<Resource Include="Images\Large\Error.png" />
|
||||
<Resource Include="Images\Large\Exception.png" />
|
||||
<Resource Include="Images\Large\Exit.png" />
|
||||
<Resource Include="Images\Large\Export.png" />
|
||||
<Resource Include="Images\Large\Fatal.png" />
|
||||
<Resource Include="Images\Large\Info.png" />
|
||||
<Resource Include="Images\Large\Network.png" />
|
||||
<Resource Include="Images\Large\Open.png" />
|
||||
<Resource Include="Images\Large\Save.png" />
|
||||
<Resource Include="Images\Large\Settings.png" />
|
||||
<Resource Include="Images\Large\Thread.png" />
|
||||
<Resource Include="Images\Large\Trace.png" />
|
||||
<Resource Include="Images\Large\Unknown.png" />
|
||||
<Resource Include="Images\Large\Warning.png" />
|
||||
<Resource Include="Images\Medium\Add.png" />
|
||||
<Resource Include="Images\Medium\Debug.png" />
|
||||
<Resource Include="Images\Medium\Error.png" />
|
||||
<Resource Include="Images\Medium\Exception.png" />
|
||||
<Resource Include="Images\Medium\Exit.png" />
|
||||
<Resource Include="Images\Medium\Export.png" />
|
||||
<Resource Include="Images\Medium\Fatal.png" />
|
||||
<Resource Include="Images\Medium\Info.png" />
|
||||
<Resource Include="Images\Medium\Network.png" />
|
||||
<Resource Include="Images\Medium\Open.png" />
|
||||
<Resource Include="Images\Medium\Save.png" />
|
||||
<Resource Include="Images\Medium\Settings.png" />
|
||||
<Resource Include="Images\Medium\Thread.png" />
|
||||
<Resource Include="Images\Medium\Trace.png" />
|
||||
<Resource Include="Images\Medium\Unknown.png" />
|
||||
<Resource Include="Images\Medium\Warning.png" />
|
||||
<Resource Include="Images\Small\Add.png" />
|
||||
<Resource Include="Images\Small\Clear.png" />
|
||||
<Resource Include="Images\Small\Clock.png" />
|
||||
<Resource Include="Images\Small\Context.png" />
|
||||
<Resource Include="Images\Small\Debug.png" />
|
||||
<Resource Include="Images\Small\DebugSource.png" />
|
||||
<Resource Include="Images\Small\Error.png" />
|
||||
<Resource Include="Images\Small\Exception.png" />
|
||||
<Resource Include="Images\Small\Exit.png" />
|
||||
<Resource Include="Images\Small\Export.png" />
|
||||
<Resource Include="Images\Small\Fatal.png" />
|
||||
<Resource Include="Images\Small\Info.png" />
|
||||
<Resource Include="Images\Small\Layout.png" />
|
||||
<Resource Include="Images\Small\MonoLightning.png" />
|
||||
<Resource Include="Images\Small\Network.png" />
|
||||
<Resource Include="Images\Small\Open.png" />
|
||||
<Resource Include="Images\Small\Pause.png" />
|
||||
<Resource Include="Images\Small\Save.png" />
|
||||
<Resource Include="Images\Small\ScrollDown.png" />
|
||||
<Resource Include="Images\Small\Settings.png" />
|
||||
<Resource Include="Images\Small\Thread.png" />
|
||||
<Resource Include="Images\Small\Trace.png" />
|
||||
<Resource Include="Images\Small\Unknown.png" />
|
||||
<Resource Include="Images\Small\Warning.png" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="NLogView.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
213
FSI.Lib/NLogViewer/NLogViewer.xaml
Normal file
@@ -0,0 +1,213 @@
|
||||
<UserControl x:Class="DJ.NLogViewer"
|
||||
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:dj="clr-namespace:DJ"
|
||||
xmlns:nLog="clr-namespace:NLog;assembly=NLog"
|
||||
xmlns:listViewLayoutManager="clr-namespace:DJ.Helper.ListViewLayoutManager"
|
||||
xmlns:xamlMultiValueConverter="clr-namespace:DJ.XamlMultiValueConverter"
|
||||
xmlns:helper="clr-namespace:DJ.Helper"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<StackPanel
|
||||
Grid.Row="1"
|
||||
Orientation="Horizontal"
|
||||
Margin="0,5,0,5">
|
||||
<ToggleButton
|
||||
Width="120"
|
||||
Height="20"
|
||||
IsChecked="{Binding Path=AutoScroll, Mode=TwoWay}">
|
||||
<ToggleButton.Content>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Image Source="Images/Small/ScrollDown.png"
|
||||
RenderOptions.BitmapScalingMode="HighQuality" Stretch="Uniform" />
|
||||
<TextBlock Text="Auto-Scroll" VerticalAlignment="Center" Margin="5,0,0,0" />
|
||||
</StackPanel>
|
||||
</ToggleButton.Content>
|
||||
</ToggleButton>
|
||||
<Button
|
||||
Margin="5,0,0,0"
|
||||
Width="120"
|
||||
Height="20"
|
||||
Command="{Binding Path=ClearCommand}">
|
||||
<Button.Content>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Image Source="Images/Small/Clear.png"
|
||||
RenderOptions.BitmapScalingMode="HighQuality" Stretch="Uniform" />
|
||||
<TextBlock Text="Clear" VerticalAlignment="Center" Margin="5,0,0,0" />
|
||||
</StackPanel>
|
||||
</Button.Content>
|
||||
</Button>
|
||||
<ToggleButton
|
||||
Margin="5,0,0,0"
|
||||
Width="120"
|
||||
Height="20"
|
||||
IsChecked="{Binding Path=Pause, Mode=TwoWay}">
|
||||
<ToggleButton.Content>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Image Source="Images/Small/Pause.png"
|
||||
RenderOptions.BitmapScalingMode="NearestNeighbor" Stretch="Uniform" />
|
||||
<TextBlock Text="Pause" VerticalAlignment="Center" Margin="5,0,0,0" />
|
||||
</StackPanel>
|
||||
</ToggleButton.Content>
|
||||
</ToggleButton>
|
||||
</StackPanel>
|
||||
|
||||
<ListView
|
||||
x:Name="ListView"
|
||||
Grid.Row="2"
|
||||
ItemsSource="{Binding Path=LogEvents.View, IsAsync=True}"
|
||||
BorderThickness="0"
|
||||
ScrollViewer.CanContentScroll="True"
|
||||
listViewLayoutManager:ListViewLayoutManager.Enabled="true">
|
||||
<ListView.Resources>
|
||||
<xamlMultiValueConverter:ILogEventResolverToStringConverter x:Key="ILogEventResolverToStringConverter"/>
|
||||
</ListView.Resources>
|
||||
<ListView.ItemContainerStyle>
|
||||
<Style TargetType="ListViewItem">
|
||||
<Setter Property="BorderBrush" Value="Black" />
|
||||
<Setter Property="BorderThickness" Value="1" />
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding Path=Level}"
|
||||
Value="{x:Static nLog:LogLevel.Trace}">
|
||||
<Setter Property="Background"
|
||||
Value="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=dj:NLogViewer}, Path=TraceBackground}" />
|
||||
<Setter Property="Foreground"
|
||||
Value="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=dj:NLogViewer}, Path=TraceForeground}" />
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Path=Level}"
|
||||
Value="{x:Static nLog:LogLevel.Debug}">
|
||||
<Setter Property="Foreground"
|
||||
Value="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=dj:NLogViewer}, Path=DebugForeground}" />
|
||||
<Setter Property="Background"
|
||||
Value="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=dj:NLogViewer}, Path=DebugBackground}" />
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Path=Level}"
|
||||
Value="{x:Static nLog:LogLevel.Info}">
|
||||
<Setter Property="Foreground"
|
||||
Value="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=dj:NLogViewer}, Path=InfoForeground}" />
|
||||
<Setter Property="Background"
|
||||
Value="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=dj:NLogViewer}, Path=InfoBackground}" />
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Path=Level}"
|
||||
Value="{x:Static nLog:LogLevel.Warn}">
|
||||
<Setter Property="Foreground"
|
||||
Value="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=dj:NLogViewer}, Path=WarnForeground}" />
|
||||
<Setter Property="Background"
|
||||
Value="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=dj:NLogViewer}, Path=WarnBackground}" />
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Path=Level}"
|
||||
Value="{x:Static nLog:LogLevel.Error}">
|
||||
<Setter Property="Foreground"
|
||||
Value="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=dj:NLogViewer}, Path=ErrorForeground}" />
|
||||
<Setter Property="Background"
|
||||
Value="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=dj:NLogViewer}, Path=ErrorBackground}" />
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Path=Level}"
|
||||
Value="{x:Static nLog:LogLevel.Fatal}">
|
||||
<Setter Property="Foreground"
|
||||
Value="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=dj:NLogViewer}, Path=FatalForeground}" />
|
||||
<Setter Property="Background"
|
||||
Value="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=dj:NLogViewer}, Path=FatalBackground}" />
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</ListView.ItemContainerStyle>
|
||||
<ListView.View>
|
||||
<helper:AutoSizedGridView>
|
||||
<GridViewColumn Header="ID" Width="40">
|
||||
<GridViewColumn.DisplayMemberBinding>
|
||||
<MultiBinding Converter="{StaticResource ILogEventResolverToStringConverter}">
|
||||
<Binding Path="."/>
|
||||
<Binding RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType=dj:NLogViewer}" Path="IdResolver"/>
|
||||
</MultiBinding>
|
||||
</GridViewColumn.DisplayMemberBinding>
|
||||
</GridViewColumn>
|
||||
<GridViewColumn Header="Level" Width="Auto">
|
||||
<GridViewColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<Image x:Name="Image" RenderOptions.BitmapScalingMode="Linear"
|
||||
Height="18" VerticalAlignment="Center" HorizontalAlignment="Center" />
|
||||
<DataTemplate.Triggers>
|
||||
<DataTrigger Binding="{Binding Path=Level}"
|
||||
Value="{x:Static nLog:LogLevel.Trace}">
|
||||
<Setter TargetName="Image" Property="Source"
|
||||
Value="Images/Small/Trace.png" />
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Path=Level}"
|
||||
Value="{x:Static nLog:LogLevel.Debug}">
|
||||
<Setter TargetName="Image" Property="Source"
|
||||
Value="Images/Small/Debug.png" />
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Path=Level}"
|
||||
Value="{x:Static nLog:LogLevel.Info}">
|
||||
<Setter TargetName="Image" Property="Source"
|
||||
Value="Images/Small/Info.png" />
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Path=Level}"
|
||||
Value="{x:Static nLog:LogLevel.Warn}">
|
||||
<Setter TargetName="Image" Property="Source"
|
||||
Value="Images/Small/Warning.png" />
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Path=Level}"
|
||||
Value="{x:Static nLog:LogLevel.Error}">
|
||||
<Setter TargetName="Image" Property="Source"
|
||||
Value="Images/Small/Error.png" />
|
||||
</DataTrigger>
|
||||
<DataTrigger Binding="{Binding Path=Level}"
|
||||
Value="{x:Static nLog:LogLevel.Fatal}">
|
||||
<Setter TargetName="Image" Property="Source"
|
||||
Value="Images/Small/Fatal.png" />
|
||||
</DataTrigger>
|
||||
</DataTemplate.Triggers>
|
||||
</DataTemplate>
|
||||
</GridViewColumn.CellTemplate>
|
||||
</GridViewColumn>
|
||||
<GridViewColumn Header="TimeStamp" Width="Auto">
|
||||
<GridViewColumn.DisplayMemberBinding>
|
||||
<MultiBinding Converter="{StaticResource ILogEventResolverToStringConverter}">
|
||||
<Binding Path="."/>
|
||||
<Binding RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType=dj:NLogViewer}" Path="TimeStampResolver"/>
|
||||
</MultiBinding>
|
||||
</GridViewColumn.DisplayMemberBinding>
|
||||
</GridViewColumn>
|
||||
<GridViewColumn Header="LoggerName" Width="Auto">
|
||||
<GridViewColumn.DisplayMemberBinding>
|
||||
<MultiBinding Converter="{StaticResource ILogEventResolverToStringConverter}">
|
||||
<Binding Path="."/>
|
||||
<Binding RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType=dj:NLogViewer}" Path="LoggerNameResolver"/>
|
||||
</MultiBinding>
|
||||
</GridViewColumn.DisplayMemberBinding>
|
||||
</GridViewColumn>
|
||||
<GridViewColumn Header="Message" Width="Auto" listViewLayoutManager:RangeColumn.IsFillColumn="True">
|
||||
<GridViewColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<TextBox
|
||||
IsReadOnly="True"
|
||||
Background="Transparent"
|
||||
BorderThickness="0"
|
||||
TextWrapping="Wrap"
|
||||
Foreground="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ListViewItem}, Path=Foreground}">
|
||||
<TextBox.Text>
|
||||
<MultiBinding Converter="{StaticResource ILogEventResolverToStringConverter}">
|
||||
<Binding Path="." Mode="OneWay"/>
|
||||
<Binding RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType=dj:NLogViewer}" Path="MessageResolver"/>
|
||||
</MultiBinding>
|
||||
</TextBox.Text>
|
||||
</TextBox>
|
||||
</DataTemplate>
|
||||
</GridViewColumn.CellTemplate>
|
||||
</GridViewColumn>
|
||||
</helper:AutoSizedGridView>
|
||||
</ListView.View>
|
||||
</ListView>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
543
FSI.Lib/NLogViewer/NLogViewer.xaml.cs
Normal file
@@ -0,0 +1,543 @@
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Reactive.Concurrency;
|
||||
using System.Reactive.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Threading;
|
||||
using DJ.Extensions;
|
||||
using DJ.Resolver;
|
||||
using DJ.Targets;
|
||||
using NLog;
|
||||
|
||||
namespace DJ
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaktionslogik für NLogViewer.xaml
|
||||
/// </summary>
|
||||
public partial class NLogViewer : UserControl
|
||||
{
|
||||
// ##############################################################################################################################
|
||||
// Dependency Properties
|
||||
// ##############################################################################################################################
|
||||
|
||||
#region Dependency Properties
|
||||
|
||||
// ##########################################################################################
|
||||
// Colors
|
||||
// ##########################################################################################
|
||||
|
||||
#region Colors
|
||||
|
||||
/// <summary>
|
||||
/// The background for the trace output
|
||||
/// </summary>
|
||||
[Category("NLogViewerColors")]
|
||||
public Brush TraceBackground
|
||||
{
|
||||
get => (Brush) GetValue(TraceBackgroundProperty);
|
||||
set => SetValue(TraceBackgroundProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="TraceBackground"/> DependencyProperty.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty TraceBackgroundProperty =
|
||||
DependencyProperty.Register("TraceBackground", typeof(Brush), typeof(NLogViewer),
|
||||
new PropertyMetadata((Brush) (new BrushConverter().ConvertFrom("#D3D3D3"))));
|
||||
|
||||
/// <summary>
|
||||
/// The foreground for the trace output
|
||||
/// </summary>
|
||||
[Category("NLogViewerColors")]
|
||||
public Brush TraceForeground
|
||||
{
|
||||
get => (Brush) GetValue(TraceForegroundProperty);
|
||||
set => SetValue(TraceForegroundProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="TraceForeground"/> DependencyProperty.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty TraceForegroundProperty =
|
||||
DependencyProperty.Register("TraceForeground", typeof(Brush), typeof(NLogViewer),
|
||||
new PropertyMetadata((Brush) (new BrushConverter().ConvertFrom("#042271"))));
|
||||
|
||||
/// <summary>
|
||||
/// The background for the debug output
|
||||
/// </summary>
|
||||
[Category("NLogViewerColors")]
|
||||
public Brush DebugBackground
|
||||
{
|
||||
get => (Brush) GetValue(DebugBackgroundProperty);
|
||||
set => SetValue(DebugBackgroundProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="DebugBackground"/> DependencyProperty.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty DebugBackgroundProperty =
|
||||
DependencyProperty.Register("DebugBackground", typeof(Brush), typeof(NLogViewer),
|
||||
new PropertyMetadata((Brush) (new BrushConverter().ConvertFrom("#90EE90"))));
|
||||
|
||||
/// <summary>
|
||||
/// The foreground for the debug output
|
||||
/// </summary>
|
||||
[Category("NLogViewerColors")]
|
||||
public Brush DebugForeground
|
||||
{
|
||||
get => (Brush) GetValue(DebugForegroundProperty);
|
||||
set => SetValue(DebugForegroundProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="DebugForeground"/> DependencyProperty.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty DebugForegroundProperty =
|
||||
DependencyProperty.Register("DebugForeground", typeof(Brush), typeof(NLogViewer),
|
||||
new PropertyMetadata((Brush) (new BrushConverter().ConvertFrom("#042271"))));
|
||||
|
||||
/// <summary>
|
||||
/// The background for the info output
|
||||
/// </summary>
|
||||
[Category("NLogViewerColors")]
|
||||
public Brush InfoBackground
|
||||
{
|
||||
get => (Brush) GetValue(InfoBackgroundProperty);
|
||||
set => SetValue(InfoBackgroundProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="InfoBackground"/> DependencyProperty.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty InfoBackgroundProperty = DependencyProperty.Register("InfoBackground",
|
||||
typeof(Brush), typeof(NLogViewer),
|
||||
new PropertyMetadata((Brush) (new BrushConverter().ConvertFrom("#0000FF"))));
|
||||
|
||||
/// <summary>
|
||||
/// The foreground for the info output
|
||||
/// </summary>
|
||||
[Category("NLogViewerColors")]
|
||||
public Brush InfoForeground
|
||||
{
|
||||
get => (Brush) GetValue(InfoForegroundProperty);
|
||||
set => SetValue(InfoForegroundProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="InfoForeground"/> DependencyProperty.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty InfoForegroundProperty = DependencyProperty.Register("InfoForeground",
|
||||
typeof(Brush), typeof(NLogViewer), new PropertyMetadata(Brushes.White));
|
||||
|
||||
/// <summary>
|
||||
/// The background for the warn output
|
||||
/// </summary>
|
||||
[Category("NLogViewerColors")]
|
||||
public Brush WarnBackground
|
||||
{
|
||||
get => (Brush) GetValue(WarnBackgroundProperty);
|
||||
set => SetValue(WarnBackgroundProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="WarnBackground"/> DependencyProperty.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty WarnBackgroundProperty = DependencyProperty.Register("WarnBackground",
|
||||
typeof(Brush), typeof(NLogViewer),
|
||||
new PropertyMetadata((Brush) (new BrushConverter().ConvertFrom("#FFFF00"))));
|
||||
|
||||
/// <summary>
|
||||
/// The foreground for the warn output
|
||||
/// </summary>
|
||||
[Category("NLogViewerColors")]
|
||||
public Brush WarnForeground
|
||||
{
|
||||
get => (Brush) GetValue(WarnForegroundProperty);
|
||||
set => SetValue(WarnForegroundProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="WarnForeground"/> DependencyProperty.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty WarnForegroundProperty = DependencyProperty.Register("WarnForeground",
|
||||
typeof(Brush), typeof(NLogViewer),
|
||||
new PropertyMetadata((Brush) (new BrushConverter().ConvertFrom("#324B5C"))));
|
||||
|
||||
/// <summary>
|
||||
/// The background for the error output
|
||||
/// </summary>
|
||||
[Category("NLogViewerColors")]
|
||||
public Brush ErrorBackground
|
||||
{
|
||||
get => (Brush) GetValue(ErrorBackgroundProperty);
|
||||
set => SetValue(ErrorBackgroundProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="ErrorBackground"/> DependencyProperty.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty ErrorBackgroundProperty =
|
||||
DependencyProperty.Register("ErrorBackground", typeof(Brush), typeof(NLogViewer),
|
||||
new PropertyMetadata(Brushes.Red));
|
||||
|
||||
/// <summary>
|
||||
/// The foreground for the error output
|
||||
/// </summary>
|
||||
[Category("NLogViewerColors")]
|
||||
public Brush ErrorForeground
|
||||
{
|
||||
get => (Brush) GetValue(ErrorForegroundProperty);
|
||||
set => SetValue(ErrorForegroundProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="ErrorForeground"/> DependencyProperty.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty ErrorForegroundProperty =
|
||||
DependencyProperty.Register("ErrorForeground", typeof(Brush), typeof(NLogViewer),
|
||||
new PropertyMetadata(Brushes.White));
|
||||
|
||||
/// <summary>
|
||||
/// The background for the fatal output
|
||||
/// </summary>
|
||||
[Category("NLogViewerColors")]
|
||||
public Brush FatalBackground
|
||||
{
|
||||
get => (Brush) GetValue(FatalBackgroundProperty);
|
||||
set => SetValue(FatalBackgroundProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="FatalBackground"/> DependencyProperty.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty FatalBackgroundProperty =
|
||||
DependencyProperty.Register("FatalBackground", typeof(Brush), typeof(NLogViewer),
|
||||
new PropertyMetadata(Brushes.Black));
|
||||
|
||||
/// <summary>
|
||||
/// The foreground for the fatal output
|
||||
/// </summary>
|
||||
[Category("NLogViewerColors")]
|
||||
public Brush FatalForeground
|
||||
{
|
||||
get => (Brush) GetValue(FatalForegroundProperty);
|
||||
set => SetValue(FatalForegroundProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="FatalForeground"/> DependencyProperty.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty FatalForegroundProperty =
|
||||
DependencyProperty.Register("FatalForeground", typeof(Brush), typeof(NLogViewer),
|
||||
new PropertyMetadata(Brushes.Yellow));
|
||||
|
||||
#endregion
|
||||
|
||||
// ##########################################################################################
|
||||
// NLogViewer
|
||||
// ##########################################################################################
|
||||
|
||||
#region NLogViewer
|
||||
|
||||
/// <summary>
|
||||
/// Is looking if any target with this name is configured and tries to link it
|
||||
/// </summary>
|
||||
[Category("NLogViewer")]
|
||||
public string TargetName
|
||||
{
|
||||
get => (string)GetValue(TargetNameProperty);
|
||||
set => SetValue(TargetNameProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="TargetName"/> DependencyProperty.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty TargetNameProperty = DependencyProperty.Register("TargetName", typeof(string), typeof(NLogViewer), new PropertyMetadata(null));
|
||||
|
||||
/// <summary>
|
||||
/// Private DP to bind to the gui
|
||||
/// </summary>
|
||||
[Category("NLogViewer")]
|
||||
public CollectionViewSource LogEvents
|
||||
{
|
||||
get => (CollectionViewSource) GetValue(LogEventsProperty);
|
||||
private set => SetValue(LogEventsProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="LogEvents"/> DependencyProperty.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty LogEventsProperty = DependencyProperty.Register("LogEvents",
|
||||
typeof(CollectionViewSource), typeof(NLogViewer), new PropertyMetadata(null));
|
||||
|
||||
/// <summary>
|
||||
/// Automatically scroll to the newest entry
|
||||
/// </summary>
|
||||
[Category("NLogViewer")]
|
||||
public bool AutoScroll
|
||||
{
|
||||
get => (bool)GetValue(AutoScrollProperty);
|
||||
set => SetValue(AutoScrollProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="AutoScroll"/> DependencyProperty.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty AutoScrollProperty = DependencyProperty.Register("AutoScroll", typeof(bool), typeof(NLogViewer), new PropertyMetadata(true, AutoScrollChangedCallback));
|
||||
|
||||
private static void AutoScrollChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs args)
|
||||
{
|
||||
if (d is NLogViewer instance)
|
||||
{
|
||||
instance.OnAutoScrollChanged();
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void OnAutoScrollChanged()
|
||||
{
|
||||
if (AutoScroll)
|
||||
ListView?.ScrollToEnd();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Delele all entries
|
||||
/// </summary>
|
||||
[Category("NLogViewer")]
|
||||
public ICommand ClearCommand
|
||||
{
|
||||
get => (ICommand) GetValue(ClearCommandProperty);
|
||||
set => SetValue(ClearCommandProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="ClearCommand"/> DependencyProperty.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty ClearCommandProperty = DependencyProperty.Register("ClearCommand",
|
||||
typeof(ICommand), typeof(NLogViewer), new PropertyMetadata(null));
|
||||
|
||||
/// <summary>
|
||||
/// Stop logging
|
||||
/// </summary>
|
||||
[Category("NLogViewer")]
|
||||
public bool Pause
|
||||
{
|
||||
get => (bool)GetValue(PauseProperty);
|
||||
set => SetValue(PauseProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="Pause"/> DependencyProperty.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty PauseProperty = DependencyProperty.Register("Pause", typeof(bool), typeof(NLogViewer), new PropertyMetadata(false));
|
||||
|
||||
/// <summary>
|
||||
/// The maximum number of entries before automatic cleaning is performed. There is a hysteresis of 100 entries which must be exceeded.
|
||||
/// Example: <see cref="MaxCount"/> is '1000'. Then after '1100' entries, everything until '1000' is deleted.
|
||||
/// If set to '0' or less, it is deactivated
|
||||
/// </summary>
|
||||
[Category("NLogViewer")]
|
||||
public int MaxCount
|
||||
{
|
||||
get => (int)GetValue(MaxCountProperty);
|
||||
set => SetValue(MaxCountProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="MaxCount"/> DependencyProperty.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty MaxCountProperty = DependencyProperty.Register("MaxCount", typeof(int), typeof(NLogViewer), new PropertyMetadata(5000));
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
// ##########################################################################################
|
||||
// Resolver
|
||||
// ##########################################################################################
|
||||
|
||||
#region Resolver
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="ILogEventInfoResolver"/> to format the id
|
||||
/// </summary>
|
||||
[Category("NLogViewerResolver")]
|
||||
public ILogEventInfoResolver IdResolver
|
||||
{
|
||||
get => (ILogEventInfoResolver)GetValue(IdResolverProperty);
|
||||
set => SetValue(IdResolverProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="IdResolver"/> DependencyProperty.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty IdResolverProperty = DependencyProperty.Register("IdResolver", typeof(ILogEventInfoResolver), typeof(NLogViewer), new PropertyMetadata(new IdResolver()));
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="ILogEventInfoResolver"/> to format the timestamp output
|
||||
/// </summary>
|
||||
[Category("NLogViewerResolver")]
|
||||
public ILogEventInfoResolver TimeStampResolver
|
||||
{
|
||||
get => (ILogEventInfoResolver)GetValue(TimeStampResolverProperty);
|
||||
set => SetValue(TimeStampResolverProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="TimeStampResolver"/> DependencyProperty.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty TimeStampResolverProperty = DependencyProperty.Register("TimeStampResolver", typeof(ILogEventInfoResolver), typeof(NLogViewer), new PropertyMetadata(new TimeStampResolver()));
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="ILogEventInfoResolver"/> to format the loggername
|
||||
/// </summary>
|
||||
[Category("NLogViewerResolver")]
|
||||
public ILogEventInfoResolver LoggerNameResolver
|
||||
{
|
||||
get => (ILogEventInfoResolver)GetValue(LoggerNameResolverProperty);
|
||||
set => SetValue(LoggerNameResolverProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="LoggerNameResolver"/> DependencyProperty.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty LoggerNameResolverProperty = DependencyProperty.Register("LoggerNameResolver", typeof(ILogEventInfoResolver), typeof(NLogViewer), new PropertyMetadata(new LoggerNameResolver()));
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="ILogEventInfoResolver"/> to format the message
|
||||
/// </summary>
|
||||
[Category("NLogViewerResolver")]
|
||||
public ILogEventInfoResolver MessageResolver
|
||||
{
|
||||
get => (ILogEventInfoResolver)GetValue(MessageResolverProperty);
|
||||
set => SetValue(MessageResolverProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="MessageResolver"/> DependencyProperty.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty MessageResolverProperty = DependencyProperty.Register("MessageResolver", typeof(ILogEventInfoResolver), typeof(NLogViewer), new PropertyMetadata(new MessageResolver()));
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
// ##############################################################################################################################
|
||||
// Properties
|
||||
// ##############################################################################################################################
|
||||
|
||||
#region Properties
|
||||
|
||||
// ##########################################################################################
|
||||
// Public Properties
|
||||
// ##########################################################################################
|
||||
|
||||
|
||||
|
||||
// ##########################################################################################
|
||||
// Private Properties
|
||||
// ##########################################################################################
|
||||
|
||||
private ObservableCollection<LogEventInfo> _LogEventInfos { get; } = new ObservableCollection<LogEventInfo>();
|
||||
private IDisposable _Subscription;
|
||||
private Window _ParentWindow;
|
||||
|
||||
#endregion
|
||||
|
||||
// ##############################################################################################################################
|
||||
// Constructor
|
||||
// ##############################################################################################################################
|
||||
|
||||
#region Constructor
|
||||
|
||||
public NLogViewer()
|
||||
{
|
||||
InitializeComponent();
|
||||
DataContext = this;
|
||||
|
||||
// save instance UID
|
||||
Uid = GetHashCode().ToString();
|
||||
|
||||
if (DesignerProperties.GetIsInDesignMode(this))
|
||||
return;
|
||||
|
||||
LogEvents = new CollectionViewSource {Source = _LogEventInfos};
|
||||
|
||||
Loaded += _OnLoaded;
|
||||
Unloaded += _OnUnloaded;
|
||||
ClearCommand = new ActionCommand(_LogEventInfos.Clear);
|
||||
}
|
||||
|
||||
private void _OnUnloaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
// look in logical and visual tree if the control has been removed
|
||||
// If there is no parent window found before, we have a special case (https://github.com/dojo90/NLogViewer/issues/30) and just dispose it anyway
|
||||
if (_ParentWindow.FindChildByUid<NLogViewer>(Uid) == null)
|
||||
{
|
||||
_Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private void _ParentWindowOnClosed(object sender, EventArgs e)
|
||||
{
|
||||
_Dispose();
|
||||
}
|
||||
|
||||
private void _Dispose()
|
||||
{
|
||||
_Subscription?.Dispose();
|
||||
}
|
||||
|
||||
private void _OnLoaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
// removed loaded handler to prevent duplicate subscribing
|
||||
Loaded -= _OnLoaded;
|
||||
|
||||
// add hook to parent window to dispose subscription
|
||||
// use case:
|
||||
// NLogViewer is used in a new window inside of a TabControl. If you switch the TabItems,
|
||||
// the unloaded event is called and would dispose the subscription, even if the control is still alive.
|
||||
if (Window.GetWindow(this) is { } window)
|
||||
{
|
||||
_ParentWindow = window;
|
||||
_ParentWindow.Closed += _ParentWindowOnClosed;
|
||||
}
|
||||
|
||||
ListView.ScrollToEnd();
|
||||
var target = CacheTarget.GetInstance(targetName: TargetName);
|
||||
|
||||
_Subscription = target.Cache.SubscribeOn(Scheduler.Default).Buffer(TimeSpan.FromMilliseconds(100)).Where (x => x.Any()).ObserveOn(new DispatcherSynchronizationContext(_ParentWindow.Dispatcher)).Subscribe(infos =>
|
||||
{
|
||||
if (Pause) return;
|
||||
using (LogEvents.DeferRefresh())
|
||||
{
|
||||
foreach (LogEventInfo info in infos)
|
||||
{
|
||||
_LogEventInfos.Add(info);
|
||||
}
|
||||
if (MaxCount >= 0 & _LogEventInfos.Count - 100 > MaxCount)
|
||||
{
|
||||
for (int i = 0; i < _LogEventInfos.Count - MaxCount; i++)
|
||||
{
|
||||
_LogEventInfos.RemoveAt(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (AutoScroll)
|
||||
{
|
||||
ListView?.ScrollToEnd();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
12
FSI.Lib/NLogViewer/Resolver/ILogEventInfoResolver.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using NLog;
|
||||
|
||||
namespace DJ.Resolver
|
||||
{
|
||||
/// <summary>
|
||||
/// Default interface to resolve a <see cref="LogEventInfo"/> for your personal needs
|
||||
/// </summary>
|
||||
public interface ILogEventInfoResolver
|
||||
{
|
||||
string Resolve(LogEventInfo logEventInfo);
|
||||
}
|
||||
}
|
||||
12
FSI.Lib/NLogViewer/Resolver/IdResolver.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using NLog;
|
||||
|
||||
namespace DJ.Resolver
|
||||
{
|
||||
public class IdResolver : ILogEventInfoResolver
|
||||
{
|
||||
public string Resolve(LogEventInfo logEventInfo)
|
||||
{
|
||||
return logEventInfo.SequenceID.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
12
FSI.Lib/NLogViewer/Resolver/LoggerNameResolver.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using NLog;
|
||||
|
||||
namespace DJ.Resolver
|
||||
{
|
||||
public class LoggerNameResolver : ILogEventInfoResolver
|
||||
{
|
||||
public string Resolve(LogEventInfo logEventInfo)
|
||||
{
|
||||
return logEventInfo.LoggerName;
|
||||
}
|
||||
}
|
||||
}
|
||||
21
FSI.Lib/NLogViewer/Resolver/MessageResolver.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
using System.Text;
|
||||
using NLog;
|
||||
|
||||
namespace DJ.Resolver
|
||||
{
|
||||
public class MessageResolver : ILogEventInfoResolver
|
||||
{
|
||||
public string Resolve(LogEventInfo logEventInfo)
|
||||
{
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.Append(logEventInfo.FormattedMessage);
|
||||
|
||||
if (logEventInfo.Exception != null)
|
||||
{
|
||||
builder.AppendLine().Append(logEventInfo.Exception);
|
||||
}
|
||||
|
||||
return builder.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
12
FSI.Lib/NLogViewer/Resolver/TimeStampResolver.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using NLog;
|
||||
|
||||
namespace DJ.Resolver
|
||||
{
|
||||
public class TimeStampResolver : ILogEventInfoResolver
|
||||
{
|
||||
public string Resolve(LogEventInfo logEventInfo)
|
||||
{
|
||||
return logEventInfo.TimeStamp.ToString("dd-MM-yyyy hh:mm:ss.fff");
|
||||
}
|
||||
}
|
||||
}
|
||||
44
FSI.Lib/NLogViewer/ScrollingHelper.cs
Normal file
@@ -0,0 +1,44 @@
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace DJ
|
||||
{
|
||||
public static class ScrollingHelper
|
||||
{
|
||||
public static void ScrollToEnd(this ListView listView)
|
||||
{
|
||||
var scrollViewer = GetDescendantByType(listView, typeof(ScrollViewer)) as ScrollViewer;
|
||||
scrollViewer?.ScrollToEnd();
|
||||
}
|
||||
|
||||
public static Visual GetDescendantByType(Visual element, Type type)
|
||||
{
|
||||
if (element != null)
|
||||
{
|
||||
if (element.GetType() != type)
|
||||
{
|
||||
Visual foundElement = null;
|
||||
(element as FrameworkElement)?.ApplyTemplate();
|
||||
|
||||
for (var i = 0; i < VisualTreeHelper.GetChildrenCount(element); i++)
|
||||
{
|
||||
var visual = VisualTreeHelper.GetChild(element, i) as Visual;
|
||||
foundElement = GetDescendantByType(visual, type);
|
||||
if (foundElement != null)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return foundElement;
|
||||
}
|
||||
|
||||
return element;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
93
FSI.Lib/NLogViewer/Targets/CacheTarget.cs
Normal file
@@ -0,0 +1,93 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Reactive.Linq;
|
||||
using System.Reactive.Subjects;
|
||||
using DJ.Helper;
|
||||
using NLog;
|
||||
using NLog.Config;
|
||||
using NLog.Targets;
|
||||
|
||||
namespace DJ.Targets
|
||||
{
|
||||
[Target(nameof(CacheTarget))]
|
||||
public class CacheTarget : Target
|
||||
{
|
||||
/// <summary>
|
||||
/// Look in the NLog.config if any target is already defined and returns it, otherwise a new one is registered
|
||||
/// </summary>
|
||||
/// <param name="defaultMaxCount">The maximum entries which should be buffered. Is only used if no target is defined</param>
|
||||
/// <param name="targetName">The name of the target you want to link with</param>
|
||||
/// <returns></returns>
|
||||
public static CacheTarget GetInstance(int defaultMaxCount = 0, string targetName = null)
|
||||
{
|
||||
if(LogManager.Configuration == null)
|
||||
LogManager.Configuration = new LoggingConfiguration();
|
||||
|
||||
var predicate = PredicateBuilder.True<Target>().And(t => t is CacheTarget);
|
||||
if (!string.IsNullOrEmpty(targetName))
|
||||
{
|
||||
predicate = predicate.And(t => t.Name.Equals(targetName, StringComparison.CurrentCultureIgnoreCase) ||t.Name.Equals($"{targetName}_wrapped", StringComparison.CurrentCultureIgnoreCase));
|
||||
}
|
||||
|
||||
var target = (CacheTarget)LogManager.Configuration.AllTargets.FirstOrDefault(predicate.Compile());
|
||||
if (target == null)
|
||||
{
|
||||
target = new CacheTarget { MaxCount = defaultMaxCount, Name = targetName ?? nameof(CacheTarget)};
|
||||
LogManager.Configuration.AddTarget(target.Name, target);
|
||||
LogManager.Configuration.LoggingRules.Insert(0, new LoggingRule("*", LogLevel.FromString("Trace"), target));
|
||||
LogManager.ReconfigExistingLoggers();
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
// ##############################################################################################################################
|
||||
// Properties
|
||||
// ##############################################################################################################################
|
||||
|
||||
#region Properties
|
||||
|
||||
// ##########################################################################################
|
||||
// Public Properties
|
||||
// ##########################################################################################
|
||||
|
||||
/// <summary>
|
||||
/// The maximum amount of entries held in buffer/cache
|
||||
/// </summary>
|
||||
public int MaxCount { get; set; } = 100;
|
||||
|
||||
public IObservable<LogEventInfo> Cache => _CacheSubject.AsObservable();
|
||||
private readonly ReplaySubject<LogEventInfo> _CacheSubject;
|
||||
|
||||
// ##########################################################################################
|
||||
// Private Properties
|
||||
// ##########################################################################################
|
||||
|
||||
#endregion
|
||||
|
||||
// ##############################################################################################################################
|
||||
// Constructor
|
||||
// ##############################################################################################################################
|
||||
|
||||
#region Constructor
|
||||
|
||||
public CacheTarget()
|
||||
{
|
||||
_CacheSubject = new ReplaySubject<LogEventInfo>(MaxCount);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
// ##############################################################################################################################
|
||||
// override
|
||||
// ##############################################################################################################################
|
||||
|
||||
#region override
|
||||
|
||||
protected override void Write(LogEventInfo logEvent)
|
||||
{
|
||||
_CacheSubject.OnNext(logEvent);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows.Data;
|
||||
using DJ.Resolver;
|
||||
using NLog;
|
||||
|
||||
namespace DJ.XamlMultiValueConverter
|
||||
{
|
||||
public class ILogEventResolverToStringConverter : IMultiValueConverter
|
||||
{
|
||||
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (values[0] is LogEventInfo logEventInfo && values[1] is ILogEventInfoResolver resolver)
|
||||
return resolver.Resolve(logEventInfo);
|
||||
return "####";
|
||||
}
|
||||
|
||||
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
6
FSI.Lib/NLogViewer/global.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"sdk": {
|
||||
"version": "6.0.101",
|
||||
"rollForward": "disable"
|
||||
}
|
||||
}
|
||||