Erbsenzähler

Zur Übung, um C# und .NET zu lernen, schreibe ich mir einen Erbsen… äh Zeilenzähler. In XAML schreibe ich mir mal eben eine Oberfläche mit einem Button ‘Load File’, auf dessen Betätigung hin eine Visual Studio C++-Projektdatei auf ihre Filter (Ordner) hin untersucht wird und eine Auswahl an diesen Filtern angeboten wird. Mit dem Button ‘Count’ werden dann alle Zeilen der in diesen virtuellen Ordnern befindlichen Dateien gezählt.

<Window x:Class="TestFileDialog2343.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="350">

    <StackPanel Margin="10" HorizontalAlignment="Left">
        <StackPanel Name="ChooseFilters" HorizontalAlignment="Left" Height="28" Width="91">
            <Button Content="Load File"
                Click="Button_LoadFile_Click"
                Margin="0 0 0 10"/>
        </StackPanel>
        <ListBox ItemsSource="{Binding FilterSelections}" IsSynchronizedWithCurrentItem="True"
        Height="87" HorizontalAlignment="Left" Margin="12,69,0,0" Name="listBox1" VerticalAlignment="Top" Width="276" >
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal">
                        <CheckBox IsChecked="{Binding Check}" />
                        <TextBlock Text="{Binding Name}" />

                    </StackPanel>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>

        <StackPanel>
            <Button Content="Count"
                Click="Button_Count_Click"
                Margin="0 0 0 10"/>
        </StackPanel>
    </StackPanel>
</Window>

Was ich hier außer handwerklichen Dingen wie mit XML-Dokumenten umgehen oder das eigentliche Zeilen zählen gelernt habe, ist die Datenbindung. Hier der Quellcode:

using System;
using System.Windows;
using Microsoft.Win32;
using System.IO;
using System.Xml;
using System.Collections.ObjectModel;

namespace TestFileDialog2343
{
    public class FilterSelection
    {
        public string Name { get; set; }
        public bool Check { get; set; }
    }

    public partial class Window1 : Window
    {
        public ObservableCollection<FilterSelection> FilterSelections { get; internal set; }
        public XmlNodeList FiltersNode;

        public Window1()
        {
            FilterSelections = new ObservableCollection<FilterSelection>();
            InitializeComponent();

            this.DataContext = this;
        }

        private void Button_LoadFile_Click(object sender, RoutedEventArgs e)
        {
            OpenFileDialog dlg = new OpenFileDialog();
            dlg.DefaultExt = ".vcproj";
            dlg.InitialDirectory = @"C:\Quellen\nova\Sources\XElektro";
            dlg.Filter = "Projektdateien (.vcproj)|*.vcproj";

            bool? result = dlg.ShowDialog();

            if (result == true)
            {
                XmlDocument doc = new XmlDocument();
                doc.Load(dlg.FileName);

                XmlElement oNode = doc.DocumentElement;

                //XmlNodeList oNodeList = oNode.SelectNodes("/VisualStudioProject/Files/Filter");
                FiltersNode = oNode.SelectNodes("//Filter");

                foreach (XmlNode i in FiltersNode)
                {
                    FilterSelection fs = new FilterSelection();
                    FilterSelections.Add(fs);
                    fs.Name = i.Attributes["Name"].Value;
                }

            }
        }

        private XmlNode GetNode(string name)
        {
            foreach (XmlNode i in FiltersNode)
                if (name == i.Attributes["Name"].Value)
                    return i;

            return null;
        }

        public void Button_Count_Click(object sender, RoutedEventArgs e)
        {
            int count = 0;
            foreach (FilterSelection fs in FilterSelections)
            {
                if (!fs.Check)
                    continue;

                XmlNode i = GetNode(fs.Name);

                System.Diagnostics.Debug.WriteLine(fs.Name);

                if (i == null)
                    continue;

                int r = CountLines(i);

                System.Diagnostics.Debug.WriteLine(r);
                count += r;
            }
        }

        private string GetFilename(XmlNode node)
        {
            Uri uri = new Uri(node.BaseURI);
            string dir = uri.AbsolutePath;
            int lastslash = dir.LastIndexOf("/");
            dir = dir.Remove(lastslash + 1);

            string file = node.Attributes["RelativePath"].Value;
            lastslash = file.LastIndexOf("\\");
            file = file.Substring(lastslash + 1);

            return dir + file;
        }

        private int CountLines(XmlNode filenode)
        {
            int count = 0;

            XmlNodeList list = filenode.SelectNodes("File");
            foreach (XmlNode fnode in list)
            {
                string filename = GetFilename(fnode);

                if (!File.Exists(filename))
                    continue;

                System.Diagnostics.Debug.WriteLine(filename);
                using (FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.Read))
                {
                    using (StreamReader sr = new StreamReader(fs))
                    {
                        while (!sr.EndOfStream)
                        {
                            string line = sr.ReadLine();
                            if (line.Length > 0)
                                count++;
                        }
                    }
                }
            }
            return count;
        }
    }
}

Das schöne an WPF ist die mögliche Trennung zwischen Daten und Ansicht. Ich binde meine Listbox an eine ObservableCollection von Objekten der Klasse FilterSelection und den Inhalt der Klasse binde ich an eine benamte Checkbox. So kann ich für jeden Filter entscheiden, ob er mitgezählt werden soll. Unkomplizierter Weise fülle ich eben nicht den Dialog, sondern die Collection mit Daten und die Oberfläche ändert sich wie von Geisterhand. Anders herum ändern sich auch die Daten automatisch mit der Änderung des Benutzers der Obefläche. So brauche ich auch nur die Daten auszulesen und herauszufinden, welche Filter der Benutzer gezählt bekommen möchte.

 

Hinterlassen Sie eine Antwort