Learning WPF, CSharp(C#) with me | Part #1

December 4, 2017

Part #1

Subject: A Simple File Listing Utility using WPF & CSharp (C#)

Okay guys

Here I am once again! This time trying to learn WPF with C# to build my own small utilities to make my “Admin work” a lot easier. Further, I use my own blog as a reference guide most of them time! So, you are most welcome to use my “notes”

A WPF project always has two parts, XAML and the code behind. While XAML maintains the GUI part of it, Code part is where you write supporting code.

<Window x:Class="WpflisttoGrid.MainWindow"         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"         Title="MainWindow" Height="513" Width="877" Loaded="Window_Loaded">
    <DockPanel>
<Menu DockPanel.Dock="Top" Height="24"></Menu>

        <StatusBar DockPanel.Dock="Bottom" Height="24">
            <StatusBarItem x:Name="StatusItem" Content="Ready" Width="Auto" HorizontalAlignment="Left" VerticalAlignment="top"></StatusBarItem>
        </StatusBar>

        <Grid>
            <GroupBox x:Name="MyParameters">
                <Grid x:Name="MyParameters_Grid">
                    <Label x:Name="lblPath" Content="Folder" HorizontalAlignment="Left" Margin="6,19,0,0" VerticalAlignment="Top"/>
                    <Label x:Name="lblFileType" Content="File Type" HorizontalAlignment="Left" Margin="6,47,0,0" VerticalAlignment="Top"/>
                    <TextBox x:Name="txtPath" HorizontalAlignment="Left" Height="23" Margin="83,22,0,0" TextWrapping="NoWrap" VerticalAlignment="Top" Width="258"/>
                    <TextBox x:Name="txtType" HorizontalAlignment="Left" Height="23" Margin="83,49,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120"/>
                    <Button x:Name="buttonFldrOpen" HorizontalAlignment="Left" Margin="346,22,0,0" VerticalAlignment="Top" Height="23" Click="buttonFldrOpen_Click" >
                        <StackPanel Orientation="Horizontal">
                            <Image Source="/Resources/folder_Open_32xMD.png" Stretch="Uniform" Height="18" Width="22"/>
                        </StackPanel>
                    </Button>
                    <Button Content="Process" HorizontalAlignment="Left" Margin="83,84,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click"/>
                </Grid>
            </GroupBox>

            <DataGrid x:Name="Grid1" Margin="68,159,89,40" IsReadOnly="True" SelectionChanged="Grid1_SelectionChanged" MouseDoubleClick="Grid1_MouseDoubleClick" SelectionUnit="Cell"/>

        </Grid>

    </DockPanel>

</Window>

and the CSharp code portion as below

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.IO;
using System.Data;
//Required for folder browswer & so
using System.Windows.Forms;

namespace WpflisttoGrid
{
    ///
<summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>

    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
        private void Button_Click(object sender, RoutedEventArgs e)
        {
            //Setup the gridview to generate columns automatically against the file lists
            this.Grid1.AutoGenerateColumns = true;
            //We will store the text box values into local variables for easy understanding
            //You may refer them straight away as defined columns
            string filepath = this.txtPath.Text;
            string filetype = this.txtType.Text;
            //We will build a LIST of class myFiles
            //Which will have chosen columns from the directory info file info results
            List<myFiles> newList = new List<myFiles>();
            try
            {
                foreach (FileInfo myfile in (new DirectoryInfo(@filepath).GetFiles(filetype, SearchOption.AllDirectories)))
                //SearchOption.TopDirectoryOnly lists files from the top folder, ie, if a folder has sub-folders within
                //SearchOption.TopDirectoryOnly will isolate the top folder & list all files from it
                //SearchOption.AllDirectories will recursively pick all files from all folders those match type of files PDF
                //As a developer who is learning
                //I will leave enhancements to your logic
                //This application could have
                //Files those matching certain "contents"
                //You can change the SearchOption.AllDirectories to SearchOption.TopDirectoryOnly programmatically...etc
                {
                   //Calculate the time difference between the file creation and as on this moment
                    double _fileAge = Math.Round((DateTime.Now - myfile.CreationTime).TotalDays, 0);
                    //Add rows to the new list using new instance of the "Constructor" myFiles by passing the file details
                   newList.Add(new myFiles(myfile.FullName.ToString(), myfile.CreationTime, _fileAge));
                }
                //The following you could use for showing additional details
                //this.StatusItem.Content = myfileList.Count().ToString();
                //this.Grid1.ItemsSource = myfileList;
                //System.Diagnostics.Debug.WriteLine(myfileList.Count());
                this.Grid1.ItemsSource = newList;
                this.Grid1.Columns[0].Header = "File Name";
                this.Grid1.Columns[1].Header = "Creation Time";
                this.Grid1.Columns[2].Header = "File Age(Days)";
            }
            catch (Exception ex)
            {
                System.Windows.MessageBox.Show(ex.Message + ex.Source);
            }
        }

        private void Grid1_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {

        }
        private void Grid1_MouseDoubleClick(object sender, MouseButtonEventArgs e)
        {
            // System.Windows.MessageBox.Show()
            //https://stackoverflow.com/questions/47309073/c-sharp-wpf-gridview-will-not-show-data-unless-clicked
            try
            {
                var cellInfo = Grid1.SelectedCells[0];
                var content = (cellInfo.Column.GetCellContent(cellInfo.Item) as TextBlock).Text;
                //System.Windows.MessageBox.Show(content);
                System.Diagnostics.Process.Start(@content);
            }
            catch (Exception ex)
            {
                System.Windows.MessageBox.Show(ex.Message + ex.Source);
            }
        }

        private void buttonFldrOpen_Click(object sender, RoutedEventArgs e)
        {
            FolderBrowserDialog folderDlg = new FolderBrowserDialog();
            folderDlg.ShowNewFolderButton = false; //Don't allow users to create new folders from this dialogue
            folderDlg.RootFolder = Environment.SpecialFolder.MyComputer;
            // Show the FolderBrowserDialog.
            DialogResult result = folderDlg.ShowDialog();
            if (result == System.Windows.Forms.DialogResult.OK)
            {
                this.txtPath.Text = folderDlg.SelectedPath;
                Environment.SpecialFolder root = folderDlg.RootFolder;
            }
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            this.txtType.Text = "*.*";
        }
    }

    public class myFiles
    {
        public string fName { get; set; }
        public DateTime fCreationDate { get; set; }
        public double fAge { get; set; }

        public myFiles(string fname, DateTime fcdate, double fage)
        {
            fName = fname;
            fCreationDate = fcdate;
            fAge = fage;

        }

    }
}

This project should be used as a pilot to learn both WPF & CSharp (C#) rather than a commercial product as I am not using threading or channeling the background works. So once the Process button clicked, the GUI become irresponsive until the file lists populated, and could make a user feel the system is stuck.

Once the file list is populated in the GridView, one can double click the file name to start a fresh instance of associated program. So be careful, you may be running an executable that could cause unexpected problems.

Optionally you may download the Visual Studio Solution from here

regards,

rajesh

Advertisements

C# (CSharp, C-Sharp) Windows Active Directory last logon

January 7, 2017

Hi guys

Please note, many threads were referred in order to compile the script attached below & all I did was re-arranging in order for better reading/formatting

(And I insure that the script works under following scenarios:

  1. You are a domain administrator
  2. You are administrating Windows 2003 onwards Windows domain
  3. Your puter is connected to the domain network ;)

)

Referenced websites/threads

  1. http://stackoverflow.com/questions/15775264/searching-for-lastlogon-attribute-of-user-in-multiple-domain-servers
  2. https://www.codeproject.com/kb/security/lastlogonacrossallwindows.aspx#_comments
  3. http://codebeautify.org/csharpviewer (for formatting the C# code)

How to test the code

Start Visual Studio (I am using 2013 Professional edition, you can use any of the community editions to test the scripts)

Create a new C# Console Application and name it llogon (else you need to change the namespace name “llogon” according to the name you have chosen for your new project.

Add the following references to your project

  1. “Framework -> System.DirectoryServices”
  2. “Browse and add -> C:\Windows\System32\activeds.tlb”

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

//Added by Rajesh

//using System.Management;
//using System.Data;
using System.DirectoryServices;
using System.DirectoryServices.ActiveDirectory;
//http://stackoverflow.com/questions/33274162/the-namespace-of-iadslargeinteger
//ActiveDS namespace
using ActiveDs; // Namespace added via ref to C:\Windows\System32\activeds.tlb
//https://www.codeproject.com/kb/security/lastlogonacrossallwindows.aspx

namespace llogon
{
    class Program
    {
        static void Main(string[] args)
        {
            // Get the root entry
            DirectoryEntry rootDSE = new DirectoryEntry("LDAP://RootDSE");
            string configurationNamingContext =
             (string)rootDSE.Properties["configurationNamingContext"].Value;
            string defaultNamingContext =
             (string)rootDSE.Properties["defaultNamingContext"].Value;
            Dictionary<string, Int64> lastLogons = new Dictionary<string, Int64>();
            // Get all the domain controllers
            DirectoryEntry deConfig = new DirectoryEntry("LDAP://" + configurationNamingContext);
            DirectorySearcher dsConfig = new DirectorySearcher(deConfig);
            dsConfig.Filter = "(objectClass=nTDSDSA)";
            foreach (SearchResult srDomains in dsConfig.FindAll())
            {
                DirectoryEntry deDomain = srDomains.GetDirectoryEntry();
                if (deDomain != null)
                {
                    string dnsHostName =
                     deDomain.Parent.Properties["DNSHostName"].Value.ToString();
                    // Get all the users for that domain
                                   DirectoryEntry deUsers =
                     new DirectoryEntry("LDAP://" + dnsHostName + "/" + defaultNamingContext);
                    DirectorySearcher dsUsers = new DirectorySearcher(deUsers);
                    dsUsers.Filter = "(&(objectCategory=person)(objectClass=user))";
                    foreach (SearchResult srUsers in dsUsers.FindAll())
                    {
                        DirectoryEntry deUser = srUsers.GetDirectoryEntry();
                        if (deUser != null)
                        {
                            // Get the distinguishedName and lastLogon for each user
                            // Save the most recent logon for each user in a Dictionary object
                            string distinguishedName = deUser.Properties["distinguishedName"].Value.ToString();
                            Int64 lastLogonThisServer = new Int64();
                            if (deUser.Properties["lastLogon"].Value != null)
                            {
                                IADsLargeInteger lgInt =
                                 (IADsLargeInteger)deUser.Properties["lastLogon"].Value;
                                lastLogonThisServer = ((long)lgInt.HighPart << 32) + lgInt.LowPart;
                            }

                            // Save the most recent logon for each user in a Dictionary object
                            if (lastLogons.ContainsKey(distinguishedName))
                            {
                                if (lastLogons[distinguishedName] < lastLogonThisServer)
                                {
                                    lastLogons[distinguishedName] = lastLogonThisServer;
                                }
                            }
                            else
                            {
                                lastLogons.Add(distinguishedName, lastLogonThisServer);
                            }
                            string readableLastLogon = DateTime.FromFileTime(lastLogonThisServer).ToString();
                            Console.WriteLine("User: " + distinguishedName + "Last logon: " +readableLastLogon);
                        }
                    }
                    Console.ReadLine();
                }
            }

        }
    }
}

Try the code & if you are stuck somewhere, do let me through the comments. I am working on a WPF C# project for a simple Active Directory Reporter / Asset Management System using WMI. Stay tuned & I will soon post the entire solution here :)

regards,

rajesh

 


It’s been long time!

April 19, 2016

Hello guys!

I know, there were NOT much to post throughout last few months about Oracle as I am nose down into one of the development platforms that I hardly desired for developing business applications.

For me, it was always Oracle forms and reports. The easiest, the most robust development tools for BUSINESS applications which is supported by the ease of SQL, PL/SQL

I am doing loads of research with C# & SQL database, which will be the main technologies behind our next proposed ERP suite. After spending almost 15 years with Forms and reports, I don’t see Oracle is too keen about modernizing their most loved development tools & the latest release lacks loads of features those would have helped to reclaim the desktop based business applications.

Wondering whether there is still room for desktop applications, especially for businesses? dude! there is, and there will be!

 

So stay tuned, I will start posting my “findings” about C#, who knows may be some sample applications using Windows forms or WPF & Oracle database in near future!

regards,

rajesh

 


VB.Net | Appending an existing XML file

February 23, 2015

VB.Net | Appending an existing XML file

XML is widely used by .net oriented programming. It is vast and learning XML could be requiring loads of dedication. I needed to add a XML file to hold certain configuration details that could be read with one of the VB.Net projects currently I am busy with. This project deals with running Oracle VirtualBox VM(Virtual Machines) headless using a Windows Service as Local System so that multiple administrators could log in and log off from the Windows Server that hosts Virtual machines without closing down the machines abrupt (This project is ongoing, half cooked)

Without wasting more time, let us see how to append an “existing” XML file using VB.Net

Create a Windows Form Project
Create a XML file (MyVMS.xml) using your favorite text editing tool and copy the below

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<VM>
<MACHINE>
    <MACHINE_ID>1</MACHINE_ID>
    <VM_NAME>MyVM</VM_NAME>
    <VM_SHUTDOWNMODE>poweroff</VM_SHUTDOWNMODE>
  </MACHINE>
</VM>

and copy the XML file to the project root folder

Add the namespaces to your new project

Imports System.Xml
Imports System.Data

As I said in the beginning, we will be adding data to an “existing” XML file, hence the XML files must have a root element, for example

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<VM>
</VM>

Drag a button to your forms1.vb design view
Drag another button to your forms1.vb design view
Drag a DataGridView to your forms1.vb design view

Now we will try to add one more “MACHINE” node into the existing XML file using VB.Net code block

Public Class Form1
 
    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Dim xmldoc As New XMLDocument()
        Try
            xmldoc.Load("MyVMS.xml")
            Dim e1 As XmlElement = xmldoc.CreateElement("MACHINE")
            Dim e2 As XmlElement = xmldoc.CreateElement("MACHINE_ID")
            e2.InnerText = "2"
            Dim e3 As XmlElement = xmldoc.CreateElement("VM_NAME")
            e3.InnerText = "Linux"
            Dim e4 As XmlElement = xmldoc.CreateElement("VM_SHUTDOWNMODE")
            e4.InnerText = "savestate"
 
            e1.AppendChild(e2)
            e1.AppendChild(e3)
            e1.AppendChild(e4)
 
            xmldoc.DocumentElement.AppendChild(e1)
            xmldoc.Save("MyVMS.xml")
 
        Catch ex As Exception
            MsgBox(ex.Message)
        End Try
    End Sub
 
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
        Dim xmlFile As XmlReader
        xmlFile = XmlReader.Create("MyVMS.xml", New XmlReaderSettings())
        Dim ds As New DataSet
        ds.ReadXml(xmlFile)
        DataGridView1.DataSource = ds.Tables(0)
        DataGridView1.Columns(0).HeaderText = "Id"
        DataGridView1.Columns(1).HeaderText = "VM Name"
        DataGridView1.Columns(2).HeaderText = "Shutoff Mode"
 
    End Sub
End Class

Now, as you click on the first button, a new node for “MACHINE” will be inserted using the static information attached & by activating the second button, your data grid view should populate the MACHINE information already stored within the XML file.

Pretty simple & easy, right? You may rush ahead and say thanks to my dearest friend and ONE of the best .Net programmers Aziz Marafi / @azizane , who had coded majority of the block above for the “FileMyster” project.

Please post your comments and queries and I may learn few more things with you!

regards,

rajesh