Ich sollte anfangen, diese WPF-Proben zu verkaufen, anstatt sie kostenlos zu verteilen. = P
- Virtualized UI (mit
VirtualizingStackPanel
), die unglaublich gute Leistung (auch mit 200000+ Artikel)
- Fully MVVM freundlich zur Verfügung stellt.
DataTemplate
s für jede Art von LogEntry
Typ. Diese geben Ihnen die Möglichkeit, wie viel wie Sie möchten anpassen. Ich habe nur zwei Arten von LogEntries implementiert (Basic und Nested), aber Sie bekommen die Idee. Sie können die LogEntry
so oft unterteilen, wie Sie benötigen. Sie können sogar Rich Text oder Bilder unterstützen.
- Erweiterbare (verschachtelte) Elemente.
- Wortumbruch.
- Sie können die Filterung usw. mithilfe einer
CollectionView
implementieren.
WPF Rocks, kopieren Sie einfach und fügen Sie meinen Code in einem File -> New -> WPF Application
und sehen Sie die Ergebnisse für sich.
<Window x:Class="MiscSamples.LogViewer"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:MiscSamples"
Title="LogViewer" Height="500" Width="800">
<Window.Resources>
<Style TargetType="ItemsControl" x:Key="LogViewerStyle">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<ScrollViewer CanContentScroll="True">
<ItemsPresenter/>
</ScrollViewer>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<VirtualizingStackPanel IsItemsHost="True"/>
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
</Style>
<DataTemplate DataType="{x:Type local:LogEntry}">
<Grid IsSharedSizeScope="True">
<Grid.ColumnDefinitions>
<ColumnDefinition SharedSizeGroup="Index" Width="Auto"/>
<ColumnDefinition SharedSizeGroup="Date" Width="Auto"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding DateTime}" Grid.Column="0"
FontWeight="Bold" Margin="5,0,5,0"/>
<TextBlock Text="{Binding Index}" Grid.Column="1"
FontWeight="Bold" Margin="0,0,2,0" />
<TextBlock Text="{Binding Message}" Grid.Column="2"
TextWrapping="Wrap"/>
</Grid>
</DataTemplate>
<DataTemplate DataType="{x:Type local:CollapsibleLogEntry}">
<Grid IsSharedSizeScope="True">
<Grid.ColumnDefinitions>
<ColumnDefinition SharedSizeGroup="Index" Width="Auto"/>
<ColumnDefinition SharedSizeGroup="Date" Width="Auto"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBlock Text="{Binding DateTime}" Grid.Column="0"
FontWeight="Bold" Margin="5,0,5,0"/>
<TextBlock Text="{Binding Index}" Grid.Column="1"
FontWeight="Bold" Margin="0,0,2,0" />
<TextBlock Text="{Binding Message}" Grid.Column="2"
TextWrapping="Wrap"/>
<ToggleButton x:Name="Expander" Grid.Row="1" Grid.Column="0"
VerticalAlignment="Top" Content="+" HorizontalAlignment="Right"/>
<ItemsControl ItemsSource="{Binding Contents}" Style="{StaticResource LogViewerStyle}"
Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="2"
x:Name="Contents" Visibility="Collapsed"/>
</Grid>
<DataTemplate.Triggers>
<Trigger SourceName="Expander" Property="IsChecked" Value="True">
<Setter TargetName="Contents" Property="Visibility" Value="Visible"/>
<Setter TargetName="Expander" Property="Content" Value="-"/>
</Trigger>
</DataTemplate.Triggers>
</DataTemplate>
</Window.Resources>
<DockPanel>
<TextBlock Text="{Binding Count, StringFormat='{}{0} Items'}"
DockPanel.Dock="Top"/>
<ItemsControl ItemsSource="{Binding}" Style="{StaticResource LogViewerStyle}">
<ItemsControl.Template>
<ControlTemplate>
<ScrollViewer CanContentScroll="True">
<ItemsPresenter/>
</ScrollViewer>
</ControlTemplate>
</ItemsControl.Template>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel IsItemsHost="True"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</DockPanel>
</Window>
-Code Behind: (Beachten Sie, dass die meisten davon nur das Beispiel zu unterstützen ist boileplate (erzeugen zufällige Einträge)
public partial class LogViewer : Window
{
private string TestData = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum";
private List<string> words;
private int maxword;
private int index;
public ObservableCollection<LogEntry> LogEntries { get; set; }
public LogViewer()
{
InitializeComponent();
random = new Random();
words = TestData.Split(' ').ToList();
maxword = words.Count - 1;
DataContext = LogEntries = new ObservableCollection<LogEntry>();
Enumerable.Range(0, 200000)
.ToList()
.ForEach(x => LogEntries.Add(GetRandomEntry()));
Timer = new Timer(x => AddRandomEntry(), null, 1000, 10);
}
private System.Threading.Timer Timer;
private System.Random random;
private void AddRandomEntry()
{
Dispatcher.BeginInvoke((Action) (() => LogEntries.Add(GetRandomEntry())));
}
private LogEntry GetRandomEntry()
{
if (random.Next(1,10) > 1)
{
return new LogEntry()
{
Index = index++,
DateTime = DateTime.Now,
Message = string.Join(" ", Enumerable.Range(5, random.Next(10, 50))
.Select(x => words[random.Next(0, maxword)])),
};
}
return new CollapsibleLogEntry()
{
Index = index++,
DateTime = DateTime.Now,
Message = string.Join(" ", Enumerable.Range(5, random.Next(10, 50))
.Select(x => words[random.Next(0, maxword)])),
Contents = Enumerable.Range(5, random.Next(5, 10))
.Select(i => GetRandomEntry())
.ToList()
};
}
}
Daten Artikel:
public class LogEntry: PropertyChangedBase
{
public DateTime DateTime { get; set; }
public int Index { get; set; }
public string Message { get; set; }
}
public class CollapsibleLogEntry: LogEntry
{
public List<LogEntry> Contents { get; set; }
}
PropertyChangedBase:
public class PropertyChangedBase:INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
Application.Current.Dispatcher.BeginInvoke((Action) (() =>
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}));
}
}
Sind Sie sicher, dass Sie Ihren eigenen Log Viewer implementieren müssen? Dadurch wird das Rad neu erfunden ... Können Sie Tools von Drittanbietern verwenden, um Ihre Protokolle anzuzeigen? Sie können beispielsweise [DbgView] (http://technet.microsoft.com/en-us/sysinternals/bb896647.aspx) öffnen und Protokolle erfassen, die über die Windows-API gesendet werden. Sie können dann Protokolle senden, die in dem Tool erfasst werden, zum einfachen Durchsuchen und Filtern – Liel
Ausgezeichnete Frage. Ich benötige diese Komponente als Teil einer bestehenden WPF-Anwendung. Wir haben bereits eine "Konsole", die als frustrierend langsame TextBox implementiert ist. Aber jetzt brauchen wir die zusätzlichen Funktionen, die ich beschrieben habe. Ich bin sehr froh, bestehende kommerzielle oder freie Nicht-GPL-Komponenten wiederzuverwenden. – pixtur