Showing posts with label c#. Show all posts
Showing posts with label c#. Show all posts

Tuesday, January 24, 2023

C# NET How to remove ANSI Control Characters fast and reduce to ANSI set




Here's how to reduce a string to ANSI and remove control characters from a string fast in C-Sharp. But be careful since, remove é is not replaces with e. Todo that you need normalize the string, see UnicodetoAscii function. 

ASCII (American Standard Code for Information Interchange) is a 7-bit character set that contains characters from 0 to 127.

The generic term ANSI (American National Standards Institute) is used for 8-bit character sets. These character sets contain the unchanged ASCII character set. In addition, they contain further characters from 128 to 255.


Here's a list of control characters. https://unicode-table.com/en/blocks/general-punctuation/


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
using System; using System.Text; using System.Linq; using System.Diagnostics; 
					
public static class Program
{
	// Based on http://www.codeproject.com/Articles/13503/Stripping-Accents-from-Latin-Characters-A-Foray-in
	// Proper Normalization
	public static string UnicodeToANSI(this string inString)
	{
		var newStringBuilder = new StringBuilder();
		newStringBuilder.Append(inString.Normalize(NormalizationForm.FormKD)
								.Where(x => (x > 30 && x <= 255))
								.ToArray());
		return newStringBuilder.ToString();
	}
	
	//ANSI characters 32 to 127 correspond to those in the 7-bit ASCII character set,
	public static string ReducetoASCII(this string s)
    {
        StringBuilder sb = new StringBuilder(s.Length);
        foreach (char c in s)
        {
            if ((int)c > 255) // remove chars > 127
                continue;
            if ((int)c < 32)  // remove  control characters 
                continue;
            sb.Append(c);
        }
        return sb.ToString();
    }
	
	public static void Main()
	{
		Stopwatch sw = new Stopwatch(); 
		string french = "A Paris, le cortège parisien s’était élancé à 14 heures.\r\n\tFace à l’affluence, un «itinéraire bis» a été mis en place. D’importants rassemblements ont lieu à Bordeaux, Marseille, Rennes ou Lyon. Suivez la journée avec nos journalistes dans toute la France.";
		string ftemp = string.Empty; 
		string german = "ޘ Trump\t\r\nverwechselt Klägerin Carroll auf Foto mit Ex-Frau – das könnte Folgen haben"; 
		string gtemp = string.Empty; 
		Console.WriteLine(french); 
		
		sw.Start();
		ftemp = french.ReducetoASCII(); 
		sw.Stop(); 
		
		Console.WriteLine("Ansi reduced\r\n" + ftemp + " in " + sw.ElapsedTicks); 
		
		sw.Reset(); 
		sw.Start();
		ftemp = french.UnicodeToANSI(); 
		sw.Stop(); 
		
		Console.WriteLine("Proper Normalization\r\n" + ftemp + " in " + sw.ElapsedTicks); 
				
		Console.WriteLine();
		Console.WriteLine();
		Console.WriteLine(german); 
		
		sw.Reset();
		sw.Start();
		gtemp = german.ReducetoASCII(); 
		sw.Stop(); 
		
		Console.WriteLine("Ansi reduced\r\n" + gtemp + " in " + sw.ElapsedTicks); 
		
		sw.Reset(); 
		sw.Start();
		gtemp = german.UnicodeToANSI(); 
		sw.Stop(); 
		
		Console.WriteLine("Proper Normalization\r\n" + gtemp + " in " + sw.ElapsedTicks); 
		
	}
}

Monday, November 16, 2020

C# .NET How to remove blank lines from a string faster, dealing with null '\0' character confusion

Typically, in C# code you would use a 

str.Split(TrimNewLineChars, StringSplitOptions.RemoveEmptyEntries);

to remove empty white-space lines and is effective. But a faster way is to use StringReader and process each line. 

But there are gotcha's introduced when processing null character ('\0') which you might deduce from the above to be a white-space character. But in fact, in C# '\u0000' is a null character, but has no special meaning in C#. It just a null character in a string. It is considered
not white-space but a control character. It's not considered a null either or string terminator as it is in C. To view control characters in VS Code, see my blog post and in Notepad++ see post.

In fact, you can look a the .NET internal storage of a string using, see my next post on this.

using (var writer = new StringWriter())
{
    using (var provider = CodeDomProvider.CreateProvider("CSharp"))
    {
        provider.GenerateCodeFromExpression(new CodePrimitiveExpression(input), writer, null);

        return writer.ToString();
    }
}

TLDR / Lesson Learning :

Counter-intuitively 
StringSplitOptions.RemoveEmptyEntries considers null character ('\0') whitespace, not a control character.




Source Code

using System;
using System.Text; 
using System.IO;
using System.Diagnostics;
using System.Text.RegularExpressions;
					
    public static class Program
    {

        public static string RemoveAllWhitespace(this string str)
        {
            var len = str.Length;
            var src = str.ToCharArray();
            var dstIdx = 0;
            for (var i = 0; i < len; i++)
            {
                char ch = src[i];
                if (!char.IsWhiteSpace(ch) && ch != '\0')
                    //ch!='\0')
                    src[dstIdx++] = ch;
                     
            }
            return new string(src, 0, dstIdx);
        }


        public static string TrimStartUnicode(this string str)
        {
            var len = str.Length;
            var src = str.ToCharArray();
            var dstIdx = 0;
            for (var i = 0; i < len; i++)
            {
                char ch = src[i];
                if (!char.IsWhiteSpace(ch) && !char.IsControl(ch) ) 
                {
                    src[dstIdx++] = ch;
                    break;
                }
            }
            return new string(src, 0, dstIdx);
        }

        private static readonly char[] TrimNewLineChars = Environment.NewLine.ToCharArray();
        public static string RemoveEmptyLines(this string str)
        {
            if (str == null)
            {
                return null;
            }
            var lines = str.Split(TrimNewLineChars, StringSplitOptions.RemoveEmptyEntries);

            var sb = new StringBuilder(str.Length);
            foreach (var line in lines)
            {
                if (!String.IsNullOrWhiteSpace(line))
                    sb.AppendLine(line);
            }

            return sb.ToString();
        }

        //Tue 12-May-20 2:08am  - 
        public static String RemoveAllBlankLinesIssue(this string value)
        {

            StringBuilder output = new StringBuilder(value.Length);
            using (StringReader sr = new StringReader(value))
            {
                string line;
                while ((line = sr.ReadLine()) != null)
                {
					//\0 has no special meaning in c# it's just a null character contained in a string.
                    if (line == '\0'.ToString()) //is line length of 1
                    {

                        Console.WriteLine("is char '\\0' empty or null = " + string.IsNullOrEmpty('\0'.ToString()));
                        Console.WriteLine("is char '\\0' whitespace or null = " + String.IsNullOrWhiteSpace('\0'.ToString()));
						Console.WriteLine("is char '\\0' char.IsWhiteSpace = " + char.IsWhiteSpace('\0')); 
						Console.WriteLine("is char '\\0' char.IsControl = " + char.IsControl('\0')); 
						
                    }
                    if (line.Contains('\u0080'.ToString()))
                    {
                        Console.WriteLine("is char '\\0080' empty or null = " + string.IsNullOrEmpty("\u0080").ToString());
                        Console.WriteLine("is char '\\0080' whitespace or null = " + String.IsNullOrWhiteSpace("\u0080").ToString());

                    }

                    if (!String.IsNullOrWhiteSpace(line) && !string.IsNullOrEmpty(line))
                        output.AppendLine(line);
                }

            }
            return output.ToString();
        }

        //Tue 12-May-20 2:08am  - 
        public static String RemoveAllBlankLinesFinal(this string value)
        {
                         
            StringBuilder output = new StringBuilder(value.Length);
            using (StringReader sr = new StringReader(value))
            {
                string line;
                string temp; 
                while ((line = sr.ReadLine()) != null)
                {
                    temp = line.TrimStartUnicode();  
                    
                    if (!string.IsNullOrWhiteSpace(temp) && !string.IsNullOrEmpty(temp))
                        output.AppendLine(line);
                }

            }
            return output.ToString();
        }



        public static String RemoveAllBlankLinesRegex(this string s)
        {
            return Regex.Replace(s, @"^\s+$[\r\n]*", string.Empty, RegexOptions.Multiline);
            //return Regex.Replace(s, @"^(?:[\t ]*(?:\r?\n|\r))+", string.Empty, RegexOptions.Multiline); 
            //return Regex.Replace(s, @"(?<=(?:\r?\n){2}|\A)(?:\r?\n)+", string.Empty, RegexOptions.Multiline); 
            //return Regex.Replace(s, @"(?<=(?:\r?\n){2}$\w)(?:\r?\n)+", string.Empty, RegexOptions.Multiline); 
            //return Regex.Replace(s, @"^\s*(\r\n|\V)", string.Empty, RegexOptions.Multiline); //does not work

        }

        public static void Main()
        {
            string output = string.Empty;

            Stopwatch sw = new Stopwatch();

            string emptytest = "Tell me and I forget.\n \n     \nTeach me and I remember.     \r\n \r\n\r\nInvolve me and I learn.  \r     \r\r\0\r\r   Pad Unicode \\u0080 next line\n\n\u0080\r\rby Benjamin Franklin.\r\n";

            sw.Start();
            output = emptytest.RemoveEmptyLines();
            sw.Stop();
            Console.WriteLine(output + " in " + sw.ElapsedTicks + " ticks");

            Console.WriteLine();
            Console.WriteLine("-------- StringReader Issue ----------------");
            sw.Reset();
            sw.Start();
            output = emptytest.RemoveAllBlankLinesIssue();
            sw.Stop();
            Console.WriteLine(output + " in " + sw.ElapsedTicks + " ticks");


            Console.WriteLine();
            Console.WriteLine("-------- StringReader Final ----------------");
            sw.Reset();
            sw.Start();
            output = emptytest.RemoveAllBlankLinesFinal();
            sw.Stop();
            Console.WriteLine(output + " in " + sw.ElapsedTicks + " ticks");








            Console.WriteLine();
            Console.WriteLine("-------- Regex ----------------");

            sw.Reset();
            sw.Start();
            output = emptytest.RemoveAllBlankLinesRegex();
            sw.Stop();

            Console.WriteLine(output + "\n in " + sw.ElapsedTicks + " ticks");

            

        }
    }

Wednesday, September 9, 2020

C# .NET - How to get a string between two strings, minimal spanning, fast

Here's an implementation to get a string between two strings fast, which meets most  expectations what this function should return. It finds the sub-string found "after" the 1st string "before" the next 2nd string. The sticky question is where does before 2nd string exactly start?


Technically, this minimal spanning meaning the string returned is the minimal length found string between the 1st string end and the beginning of the 2nd string. 

See my post on maximally spanning 
https://metadataconsulting.blogspot.com/2020/09/CSharp-dotNET-How-to-get-a-string-between-two-strings.html




Below we compare the 2nd string starting immediately after leaving no space after 1st, versus, 2nd string starting immediately after 1st but starting +1 character or next character after. We want at least one character to return, not empty string. Right.

Immediate after is how most examples are commonly implemented, but it may not be what you want, see comparison image below. Quick note, r stands for rule, see code.








With index immediately after "Exact in charts", getting string between strings "a" to "a" for input "aaaa" is empty! Technically correct. 

With index immediately after "+1 in charts", getting string between strings "a" to "a" for input "aaaa" is "a". Intuitively you would want this. 

Whilst the "+1" seems good, there are repercussions, in some cases might not be want you expect. Best to see it for you own eyes, in 
comparison chart image below.





















To see full effects, run code below for "Exact" or Edit in .NET Fiddle
to try "+1" version. 



using System;using System.Diagnostics; 

public static class Extensions 
{
	/// <summary>
	/// Get a substring between two anchor strings, minimal span
	/// </summary>
	/// <param name="s">source string</param>
	/// <param name="from">search from end of this string</param>
	/// <param name="to">to beginning of this string, searching backwards, from end to start of s</param>
	/// <returns>a substring between from and to, maximal span</returns>
	public static string GetFirstStringBetweenStringsMinSpanCleanup(this string s, string from, string to)
	{
		if (string.IsNullOrEmpty(s) || string.IsNullOrEmpty(from) || string.IsNullOrEmpty(to)) return string.Empty;

		int idxFrom = s.IndexOf(from);
		int idxStart = idxFrom + from.Length; //we filter "not found" -1, never race condtn

		if (idxFrom == -1 || idxStart >= s.Length - 1)
			return string.Empty;

		int idxEnd = s.IndexOf(to, idxStart); //Exact definition, but intuitively next line meets likely expectations -> YOU CHOOSE
        //int idxEnd = s.IndexOf(to, idxStart + 1); //Start next position after, leaving a space for 1 character to be returned

           
		if (idxEnd == -1 || idxEnd <= idxStart)
			return string.Empty;

		return s.Substring(idxStart, idxEnd - idxStart);

	}
	/// <summary>
	/// Get a substring between two anchor strings, MINIMAL SPAN
	/// </summary>
	/// <param name="s">source string</param>
	/// <param name="from">search from end of this string</param>
	/// <param name="to">to beginning of this string, searching backwards, from end to start of s</param>
	/// <returns>a substring between from and to, maximal span</returns>
	public static string GetFirstStringBetweenStringsMinSpan(this string s, string from, string to)
	{
		Console.Write("args from {0} to {1} = ", from, to); //debug

		//edge cases
		if (string.IsNullOrEmpty(s) || string.IsNullOrEmpty(from) || string.IsNullOrEmpty(to)) return string.Empty;
		//if (from.Length >= s.Length || to.Length >= s.Length) return string.Empty; //redundant, this Rule take care of below

		int idxFrom = s.IndexOf(from);
		int idxStart = idxFrom + from.Length; //we filter "not found" -1, never race condtn

		if (idxFrom == -1)       
			return string.Empty;
		else if (idxStart >= s.Length - 1) //for testing combine to 1 line, we combining a idx with a length, and w/ lengths we normally subtract 1 
		{
			Console.WriteLine("r1. idxStart={0} >= (s.Length - 1)={1}", idxStart, s.Length - 1);
			return string.Empty; 
		}

		int idxEnd = s.IndexOf(to, idxStart); //Exact definition, but intuitively next line meets likely expectations -> YOU CHOOSE
        //int idxEnd = s.IndexOf(to, idxStart + 1); //Start next position after, leaving a space for 1 character to be returned

		if (idxEnd == -1 )
			return string.Empty;
		else if (idxEnd > s.Length - 1) //Rule 2 never gets used
		{
			Console.WriteLine("r2. idxEnd={0} > (s.Length - 1)={1}", idxEnd, s.Length - 1);
			return string.Empty;
		}
		else if (idxEnd <= idxStart)
		{
			Console.WriteLine("r3. idxEnd={0} <= idxStart={1}", idxEnd, idxStart);
			return string.Empty;
		}

		return s.Substring(idxStart, idxEnd - idxStart);

	}
 }

public class Program
{
	public static void Main()
	{
		  string test = "abcd";
            Console.WriteLine(test);
            Console.WriteLine("=================");

            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan(null, null));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("", ""));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan(test, test));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("", test));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan(test,""));
            
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("a", "a"));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("a", "b"));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("a", "c"));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("a", "d"));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("a", "e"));
            
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("e", "e"));
            
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("ab", "a"));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("ab", "b"));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("ab", "c"));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("ab", "d"));

            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("ab", "a"));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("ab", "b"));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("ab", "c"));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("ab", "d"));

            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("abc", "a"));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("abc", "b"));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("abc", "c"));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("abc", "d"));
            
            

            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan(test, "a"));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan(test, "b"));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan(test, "c"));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan(test, "d"));

            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("a","abc"));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("b", "abc"));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("c", "abc"));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("d", "abc"));

            Console.WriteLine(); 
            test = "abcdabcd";
            Console.WriteLine(test);
            Console.WriteLine("=================");

            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan(null, null));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("", ""));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan(test, test));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("", test));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan(test, ""));

            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("a", "a"));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("a", "b"));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("a", "c"));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("a", "d"));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("a", "e"));

            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("e", "e"));

            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("ab", "a"));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("ab", "b"));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("ab", "c"));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("ab", "d"));

            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("ab", "a"));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("ab", "b"));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("ab", "c"));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("ab", "d"));

            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("abc", "a"));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("abc", "b"));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("abc", "c"));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("abc", "d"));

            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan(test, "a"));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan(test, "b"));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan(test, "c"));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan(test, "d"));

            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("a", "abc"));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("b", "abc"));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("c", "abc"));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("d", "abc"));

            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("abc", "d")); //pass


            Console.WriteLine();
            test = "aaaa";
            Console.WriteLine(test);
            Console.WriteLine("=================");

            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("a", "a"));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("aa", "a"));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("aaa", "a"));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("aaaa", "a"));

            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("a", "a"));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("a", "aa"));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("a", "aaa"));
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("a", "aaaa"));

            Console.WriteLine();
            test = "aaaaaaaaaaaaaaaaaaaaaaaaaaaabbbb";
            Console.WriteLine(test);
            Console.WriteLine("=================");
            Console.WriteLine(test.GetFirstStringBetweenStringsMinSpan("bbbb", "aaaa"));

            string result = string.Empty; 
            Stopwatch sw = new Stopwatch();
            sw.Start();
            result = test.GetFirstStringBetweenStringsMinSpan("aaaaaaa", "bb");
            sw.Stop();
            Console.WriteLine(result);
            Console.WriteLine(" in " + sw.ElapsedTicks + " ticks."); 
	}
}

Wednesday, August 12, 2020

C# .NET How to overload clipboard to handle multiple formats simultaneously




















Tip! Get ClipSpy - CodeProject to examine the clipboard overloads.  


The following console application is fully functional working code to demonstrate how to overload Windows system clipboard with multiple
formats

In below example source code specifically, we are overloading a image copy to append a caption.

Result: 

When you copy an image from a browser, and paste into MSPaint, you'll get the expected image.
When you paste into Notepad, you'll get a text message.

This is the overload in action, an additional text format has been added. 

Aside : See it in action with my tool - https://clipboardplaintextpowertool.blogspot.com/  which overloads images with following text metadata; 

Clip iss063e070805.jpg [1041w✕585h] "NASA Image of the Day | NASA - Microsoft​ Edge", img src="https://www.nasa.gov/sites/default/files/styles/full_width_feature/public/thumbnails/image/iss063e070805.jpg"

Update - Simplified further Aug 13, 2020.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Imaging;
using System.Drawing;

namespace ClipboardOverloadExample
{
    class Program
    {
        [STAThread] //TIP! Set this to get clipboard handle from a console app
        public static void Main(string[] args)
        {
            Console.WriteLine("Right-click COPY a image from your open brower. Press any key to start...");
            Console.ReadKey();

            //Let's grab clipboard, do we have access and does it contain data?
            System.Windows.Forms.IDataObject iData = Clipboard.GetDataObject();

            if (iData == null)
                return;
            
            //check if we have a standard Bitmap format on the clipboard
            //images are saved on the clipboard as raw bitmap "Memory Bitmap",but transparency maybe lost.
            if (!iData.GetDataPresent(DataFormats.Bitmap))
                return;

            //we have Bitmap format and thus we can perform cast safely
            Bitmap clipBMP = iData.GetData(DataFormats.Bitmap) as Bitmap;

            if (clipBMP == null)
                return;

            string imgInfo = "This image is a Bitmap " + clipBMP.PixelFormat.ToString();

            //Create an object that will contain multiple formats to paste - overload
            System.Windows.Forms.IDataObject objFormatstoPaste = new DataObject();

            //add formats to put on clipboard
            objFormatstoPaste.SetData(DataFormats.Text, imgInfo);
            objFormatstoPaste.SetData(DataFormats.Bitmap, clipBMP);

            //Copy to the clipboard, and the 2nd parameter indicates that the clipboard is not cleared when the program exits
            Clipboard.SetDataObject(objFormatstoPaste, true);
            
            Console.WriteLine("Success. You can exit program, but to test overload of clipboard, do the following:");
            Console.WriteLine("Open Notepad and paste (CTRL-V), you'll get text. Open MSPaint and you'll paste the image!");
            Console.ReadKey();

        }
    }
}

Tuesday, February 14, 2017

Copy WPF DataGrid selected rows to clipboard using CopyingRowClipboardContent

Searched high-and-low for this code that properly used of a DataGrid event method signature associated with the DataGridRowClipboardEventArgs. Clipboard.SetText can be flaky, not grabbing/setting the clipboard all the time. 

Set "FullRow" at the SelectionUnit mode for dataGrid called myDataGrid

1
<DataGrid x:Name="myDataGrid" SelectionUnit="FullRow"></DataGrid>

We have a method myDataGrid_CopyingRowClipboardContent that gets called for each row in the dataGrid to copy its contents to the clipboard. For example,for a datagrid with 10 rows this is called 10 times.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public int clipboardcalledcnt { get; set; } //CopyingRowClipboardContent invoked count
private void myDataGrid_CopyingRowClipboardContent(object sender, DataGridRowClipboardEventArgs e)
    {
        PathInfo cellpath = new PathInfo(); //a custom class to hold path info
        string path = string.Empty;
    
    DataGrid dgdataPaths = (DataGrid)sender;
    int rowcnt = dgdataPaths.SelectedItems.Count;

    cellpath = (PathInfo)e.Item;
    
    path = "Row #"+ clipboardcalledcnt +" Len="+ cellpath.Length.ToString() + ", path=" + cellpath.Path;

    e.ClipboardRowContent.Clear();

    if (clipboardcalledcnt == 0) //add header to clipboard paste
        e.ClipboardRowContent.Add(new DataGridClipboardCellContent("", null, "--- Clipboard Paste ---\t\t\n")); // \t cell divider, repeat (number of cells - 1)
    
    clipboardcalledcnt++;
    e.ClipboardRowContent.Add(new DataGridClipboardCellContent(path, null, path));
    
    if (clipboardcalledcnt == rowcnt)
        clipboardcalledcnt = 0;

}