Lifeupdate DataGrid von TextFile mit guter Leistung

Tatsächlicher Zustand

Ich habe einDataGrid mit 4 Spalten (Icon | DateTime | LogLevel | Message)

Ich benutze es als Viewer, um Einträge eines @ zu präsentiereLogFile. Beim Öffnen desWindow Die Verzögerungen der Benutzeroberfläche und viele Einträge werden einzeln zum @ hinzugefügDataGrid.

Hinweis Ich benutze bereits mehrere Threads. Mein UI-Thread friert nicht ein. Es dauert einfach viel zu lange, um das ganze @ zu fülleDataGrid.

Was ich möchte

Ich würde es vorziehen, das gesamte Fenster vorab zu rendern, bevor ich es dem Benutzer zeige.

Wenn ich das @ geöffnet haWindow einmal - jedes Mal, wenn ich es wieder öffne, ist es kein Problem mehr (kein neues Rendering ...?)

Was ich versucht habe:

Einstellen desVisibility zuHidden und warteThread.Sleep()) 10 Sekunden dann setVisibility = Visibility.Visible;Hinzufügen aller Daten in meinDataGrid in ViewModel-Constructor

aber das alles hat es nicht wirklich behoben. Ich bin mir nicht mal sicher, ob es sich um den C # -Code oder nur um die Bindungen handelt ...

Dies mag eine dumme Frage sein, aber gibt es eine Möglichkeit, das @ vorab zu renderDataGrid und seinContent bevor es angezeigt wird?

BEARBEITEN

Ich benutze auch einigeDataTriggers, um RowColor einzustellen, aber dies ist möglicherweise nicht das Problem.

Hier ist ein Code, den ich verwende:

Die Einstiegsklasse:

 public class LogEntry
{
    public string LogLevel { get; set; }
    public string LogLevelIcon
    {
        get
        {
            switch(LogLevel)
            {
                case "[D]":     //IF DEBUG ENTRY:
                    return "pack://application:,,,/Resources/Bug.png";
                case "[F]":     //IF FATAL ENTRY
                    return "pack://application:,,,/Resources/System-error-alt.png";
                case "[E]":     //IF ERROR ENTRY
                    return "pack://application:,,,/Resources/Error_32_WhiteBackground.png";
                case "[I]":     //IF INFO ENTRY
                    return "pack://application:,,,/Resources/Info_32.png";
                case "[W]":     //IF WARNING ENTRY
                    return "pack://application:,,,/Resources/Warning_32_WhiteBackground.png";
                case "[DB]":    //IF DB ENTRY
                    return "pack://application:,,,/Resources/Database.png";
                default:
                    return string.Empty;
            }                
        }
    }
    public string Message { get; set; }
    public DateTime DateTime { get; set; }

    public override string ToString()
    {
        return $"{LogLevel};{DateTime.ToString("dd.MM.yyyy HH:mm:ss")};{Message}";
    }
}

Holen Sie sich die Daten aus meinem LogFile:

public void ExtractDataFromLogFile(string logFilePath)
    {
        new Thread(() => {

            List<string> linesInFile = new List<string>();
            using (FileStream stream = File.Open(logFilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
            {
                using (StreamReader reader = new StreamReader(stream))
                {
                    while (true)
                    {
                        while (!reader.EndOfStream)
                        {
                            ProcessFileContent(reader.ReadLine());
                        }
                        while (reader.EndOfStream)
                        {
                            Thread.Sleep(50);
                        }
                    }
                }
            }

        }).Start();
    }

Adding to theObservableCollection<LogEntry>() _logEntries;:

private void ProcessFileContent(string line)
    {
        Match match = _regex.Match(line);
        if (match.Success)
        {
            LogEntry entry = new LogEntry()
            {
                LogLevel = match.Groups[1].ToString(),
                DateTime = DateTime.Parse(match.Groups[2].ToString(), new CultureInfo("de-DE")),
                Message = match.Groups[3].ToString()
            };                    
            _logEntries.Add(entry);                    
        }
    }

Endlich die XAML des DataGrid (Stile weggelassen!):

<DataGrid Grid.Row="1"
          x:Name="DataGrid"
          Grid.ColumnSpan="2"
          Margin="5"
          IsReadOnly="True"
          AutoGenerateColumns="False"
          CanUserReorderColumns="False"
          ItemsSource="{Binding Path=ItemsView, UpdateSourceTrigger=PropertyChanged}">
  <DataGrid.Columns>
            <DataGridTemplateColumn Width="Auto">
                <DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <Image Source="{Binding Path=LogLevelIcon, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"
                               Width="16" 
                               Height="16"></Image>
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>
            <DataGridTextColumn Width="Auto" Header="Datum"
                                Binding="{Binding Path=DateTime, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"/>               
            <DataGridTextColumn Width="*" Header="Meldung"
                                Binding="{Binding Path=Message, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"/>
        </DataGrid.Columns>
    </DataGrid>

Bitte beachten Sie, dass "ItemsView" vom Typ @ isICollectionView

Ich fülle es hier aus:

private void InitializeCollection()
    {
        ItemsView = CollectionViewSource.GetDefaultView(_logEntries);
        BindingOperations.EnableCollectionSynchronization(_logEntries, _lock);
    }

Antworten auf die Frage(2)

Ihre Antwort auf die Frage