Screenshot of particular columns&rows of a grid - c#

Imagine that I have a grid with 3 columns and 2 rows. I want to take a picture of what is inside the column 2-3 and row 1. Is this possible?
Right now I am able to take a screenshot to my plot graph with this method
private void Capture()
{
SaveFileDialog dlg = new SaveFileDialog();
dlg.FileName = "hello";
dlg.Filter = "JPEG (*.jpg)|*.jpg|PNG (*.png)";
dlg.FilterIndex = 1;
if (dlg.ShowDialog().GetValueOrDefault(false))
{
string filePath = dlg.FileName;
plotter.SaveScreenshot(filePath);
e.Handled = true;
}
}
Where plotter is a ChartPlotter (a class in DynamicDataDisplay), it has a method called "SaveScreenshot".
But it only takes the screenshot of that particular plotter. My idea is to have several plotters and be able to make a screenshot to all of them. For that I can put them into a StackPanel or a grid and take a picture of that element as whole (that contains all my plotters).

yes it is. I don't know in what case exactly you would like to use it. but if you just want to save it in a nother array for example you could do this with for loops. for your example only one loop is needed:
int[,] array = new int[2,3];
static int[,] ScreenShot(int row, int colum1, int colum2)
{
int[,] temp = new int[colum2-colum1, 1];
for (int i = 0; i < colum2-colum1; i++)
{
temp[i,1] = array[i+colum1,row];
}
}
if you want it to have more rows, you could extend it.

This woudn't be the fastest or nicest solution, but you could make an array of plotters, then create a temporary array of small pictures (would use something more lossless then jpg) and combine them at the end. Would this work for you?

Related

How to retrieve efficiently all strings from a large Excel documents

The Excel spreadsheet should be read by .NET. It is very efficient to read all values from the active range by using the property Value. This transfers all values in a two dimensional array, by one single call to Excel.
However reading strings is not possible for a range which contains more than one single cell. Therefor we have to iterate over all cells and use the Text property. This shows very poor performance for larger document.
The reason of using strings rather than values is to obtains the correct format (for instance for dates or the number of digits).
Here is a sample code written in C# to demonstrate the approach.
static void Main(string[] args)
{
Excel.Application xlApp = (Excel.Application)System.Runtime.InteropServices.Marshal.GetActiveObject("Excel.Application");
var worksheet = xlApp.ActiveSheet;
var cells = worksheet.UsedRange();
// read all values in array -> fast
object[,] arrayValues = cells.Value;
// create array for text of the same extension
object[,] arrayText = (object[,])Array.CreateInstance(typeof(object),
new int[] { arrayValues.GetUpperBound(0), arrayValues.GetUpperBound(1) },
new int[] { arrayValues.GetLowerBound(0), arrayValues.GetLowerBound(1) });
// read text for each cell -> slow
for (int row = arrayValues.GetUpperBound(0); row <= arrayValues.GetUpperBound(0); ++row)
{
for (int col = arrayValues.GetUpperBound(0); col <= arrayValues.GetUpperBound(1); ++col)
{
object obj = cells[row, col].Text;
arrayText[row, col] = obj;
}
}
}
The question is, if there is a more efficient way to read the complete string content from an Excel document. One idea was to use cells.Copy to copy the content to the clipboard to get it from there. However this has some restrictions and could of course interfere with users which are working with the clipboard at the same time. So I wonder if there are better approaches to solve this performance issue.
You can use code below:
using (MSExcel.Application app = MSExcel.Application.CreateApplication())
{
MSExcel.Workbook book1 = app.Workbooks.Open( this.txtOpen_FilePath.Text);
MSExcel.Worksheet sheet = (MSExcel.Worksheet)book1.Worksheets[1];
MSExcel.Range range = sheet.GetRange("A1", "F13");
object value = range.Value; //the value is boxed two-dimensional array
}
The code is provided from this post. It should be much more efficient than your code, but may not be the best.

Randomizing images in picture boxes without repeating

I am pretty new in the programming scene and I want to be able to use a button to show random photos in multiple picture boxes. The thing is that I don't want one photo to show in multiple boxes. So every pictureBox should contain different images. I have searched Google for the past few hours but I haven't been able to get any useful information. What I have now, when pressing the button, every pictureBox goes blank. Though here is my code in the button1_Click :
{
List<string> name = new List<string>();
name.Add("0.jpg");
name.Add("1.jpg");
name.Add("2.jpg");
name.Add("3.png");
List<PictureBox> box = new List<PictureBox>();
box.Add(pictureBox1);
box.Add(pictureBox2);
box.Add(pictureBox3);
box.Add(pictureBox4);
a = 4;
ResourceManager rm = MatchGame.Properties.Resources.ResourceManager;
for (int i = 0; i < box.Count; i++)
{
int randomPic = new Random().Next(0, name.Count);
string randomName = name[randomPic];
name.Remove(randomName);
Image img = rm.GetObject(randomName) as Image;
box[i].Image = img;`
}
}
An easy way would be to simply shuffle in random order your name list
List<string> name = new List<string>();
name.Add("0.jpg");
name.Add("1.jpg");
name.Add("2.jpg");
name.Add("3.png");
List<PictureBox> box = new List<PictureBox>();
box.Add(pictureBox1);
box.Add(pictureBox2);
box.Add(pictureBox3);
box.Add(pictureBox4);
// 2 lines code for shuffle every kind of IEnumerable
Random r = new Random();
name = name.OrderBy(x => r.Next()).ToList();
ResourceManager rm = MatchGame.Properties.Resources.ResourceManager;
for (int i = 0; i < box.Count; i++)
{
// no need to remove elements from name list
string randomName = name[i];
Image img = rm.GetObject(randomName) as Image;
box[i].Image = img;`
}
this will assure that every picture picked once and only once (as long, of course, number of pictureboxes is the same of images stored in resource).
Be sure that every rm.GetObject returns a different image.
As a side note, never create a new Random() within a loop: instantiate a single Random and keep calling .Next on it (see this question). The above code would be wrong in this way:
name = name.OrderBy(x => new Random.Next()).ToList();
What you could do is store the picture references in a Dictionary.
Associating the picture names with the PictureBox indexes - then all you need to do is check the dictionary values and see if the picturename is in the dictionary. If it is in the dictionary - then just let the while loop do another loop - to pick another image. To Recycle that all you would need to do is clear the dictionary and the process could start over again.
Dictionary<int, string> MyActivePictures = new Dictionary<int, string>();
Use a concurrentDictionary if you are multithreading.
// Where MyActivePictures < PictureBoxControl , picturename > is the Dictionary
Dictionary<int, string> MyActivePictures = new Dictionary<int, string>();
// i is your PictureBoxes index as you loop through them
int i = 0;
if(box.Count < name.Length){
do
{
int randomPic = new Random().Next(0, name.Count);
string randomName = name[randomPic];
if(!MyActivePictures.Values.Contains[randomName])
{
name.Remove(randomName);
Image img = rm.GetObject(randomName) as Image;
box[i].Image = img;
MyActivePictures[i]=randomName;
i++;
}
if (i > name.Length) // exits the loop in case there are more
{
i = box.Count + 1;
}
}while (i < box.Count);
}
I should add that if it is not possible for the above code to get a unique picture - for example picture boxes > number of images. Then this code will hang in an endless loop. You will need to factor in for that scenario in the while loop - if(the iterator I of pictureboxes value > total images - exit the loop. so if(i > totalimages) exit loop.
I added the additional code to handle this: however
You could just simply include that test in the while condition as well - it is easier ( (i names.Length))

Large file CSV transpose takes forever in C#

I'm trying to transpose a large data file that may have many rows and columns, for subsequent analysis in Excel. Currently rows might contain either 2 or 125,000 points, but I'm trying to be generic. (I need to transpose because Excel can't handle that many columns, but is fine if the large sets span many rows.)
Initially, I implemented this is Python, using the built-in zip function. I process the source file to separate long rows from short, then transpose the long rows with zip:
tempdata = zip(*csv.reader(open(tempdatafile,'r')))
csv.writer(open(outfile, 'a', newline='')).writerows(tempdata)
os.remove(tempdatafile)
This works great and takes a few seconds for a 15MB csv file, but since the program that generated the data in the first place is in C#, I thought it would be best to do it all in one program.
My initial approach in C# is a little different, since from what I've read, the zip function might not work quite the same. Here's my approach:
public partial class Form1 : Form
{
StreamReader source;
int Rows = 0;
int Columns = 0;
string filePath = "input.csv";
string outpath = "output.csv";
List<string[]> test_csv = new List<string[]>();
public Form1()
{
InitializeComponent();
}
private void button_Load_Click(object sender, EventArgs e)
{
source = new StreamReader(filePath);
while(!source.EndOfStream)
{
string[] Line = source.ReadLine().Split(',');
test_csv.Add(Line);
if (test_csv[Rows].Length > Columns) Columns = test_csv[Rows].Length;
Rows++;
}
}
private void button_Write_Click(object sender, EventArgs e)
{
StreamWriter outfile = new StreamWriter(outpath);
for (int i = 0; i < Columns; i++)
{
string line = "";
for (int j = 0; j < Rows; j++)
{
try
{
if (j != 0) line += ",";
line += test_csv[j][i];
}
catch { }
}
outfile.WriteLine(line);
}
outfile.Close();
MessageBox.Show("Outfile written");
}
}
I used the List because the rows might be of variable length, and I have the load function set to give me total number of columns and rows so I can know how big the outfile has to be.
I used a try/catch when writing to deal with variable length rows. If the indices are out of range for the row, this catches the exception and just skips it (the next loop writes a comma before an exception occurs).
Loading takes very little time, but actually saving the outfile is an insanely long process. After 2 hours, I was only 1/3 of the way through the file. When I stopped the program and looked at the outfile, everything is done correctly, though.
What might be causing this program to take so long? Is it all the exception handling? I could implement a second List that stores row lengths for each row so I can avoid exceptions. Would that fix this issue?
Try using StringBuilder. Concatenation (+) of long strings is very inefficient.
Create a List<string> of lines and then make a single call System.IO.File.WriteAllLines(filename, lines). This will reduce disk IO.
If you don't care about the order of the points try changing your outside for loop to System.Threading.Tasks.Parallel.For. This will run multiple threads. Since these run parallel it won't preserve the order when writing it out.
In regards to your exception handling: Since this is an error that you can determine ahead of time, you should not use a try/catch to take care of it. Change it to this:
if (j < test_csv.Length && i < test_csv[j].Length)
{
line += test_csv[j][i];
}

Optimized way of adding multiple hyperlinks in excel file with C#

I wanted to ask if there is some practical way of adding multiple hyperlinks in excel worksheet with C# ..? I want to generate a list of websites and anchor hyperlinks to them, so the user could click such hyperlink and get to that website.
So far I have come with simple nested for statement, which loops through every cell in a given excel range and adds hyperlink to that cell:
for (int i = 0; i < _range.Rows.Count; i++)
{
Microsoft.Office.Interop.Excel.Range row = _range.Rows[i];
for (int j = 0; j < row.Cells.Count; j++)
{
Microsoft.Office.Interop.Excel.Range cell = row.Cells[j];
cell.Hyperlinks.Add(cell, adresses[i, j], _optionalValue, _optionalValue, _optionalValue);
}
}
The code is working as intended, but it is Extremely slow due to thousands of calls of the Hyperlinks.Add method.
One thing that intrigues me is that the method set_Value from Office.Interop.Excel can add thousands of strings with one simple call, but there is no similar method for adding hyperlinks (Hyperlinks.Add can add just one hyperlink).
So my question is, is there some way to optimize adding hyperlinks to excel file in C# when you need to add a large number of hyperlinks...?
Any help would be apreciated.
I am using VS2010 and MS Excel 2010.
I have the very same problems (adding 300 hyperlinks via Range.Hyperlinks.Add takes approx. 2 min).
The runtime issue is because of the many Range-Instances.
Solution:
Use a single range instance and add Hyperlinks with the "=HYPERLINK(target, [friendlyName])" Excel-Formula.
Example:
List<string> urlsList = new List<string>();
urlsList.Add("http://www.gin.de");
// ^^ n times ...
// create shaped array with content
object[,] content = new object [urlsList.Count, 1];
foreach(string url in urlsList)
{
content[i, 1] = string.Format("=HYPERLINK(\"{0}\")", url);
}
// get Range
string rangeDescription = string.Format("A1:A{0}", urlsList.Count+1) // excel indexes start by 1
Xl.Range xlRange = worksheet.Range[rangeDescription, XlTools.missing];
// set value finally
xlRange.Value2 = content;
... takes just 1 sec ...

How do you have a bulletted list in migradoc / pdfsharp

even after reading this forum post, its still quite confusing how to create a bulletted list using migradoc / pdfsharp. I basically want to display a list of items like this:
Dodge
Nissan
Ford
Chevy
Here's a sample (a few lines added to the HelloWorld sample):
// Add some text to the paragraph
paragraph.AddFormattedText("Hello, World!", TextFormat.Italic);
// Add Bulletlist begin
Style style = document.AddStyle("MyBulletList", "Normal");
style.ParagraphFormat.LeftIndent = "0.5cm";
string[] items = "Dodge|Nissan|Ford|Chevy".Split('|');
for (int idx = 0; idx < items.Length; ++idx)
{
ListInfo listinfo = new ListInfo();
listinfo.ContinuePreviousList = idx > 0;
listinfo.ListType = ListType.BulletList1;
paragraph = section.AddParagraph(items[idx]);
paragraph.Style = "MyBulletList";
paragraph.Format.ListInfo = listinfo;
}
// Add Bulletlist end
return document;
I didn't use the AddToList method to have it all in one place. In a real application I'd use that method (it's a user-defined method, code given in this thread).
A little bit more concise than the above answer:
var document = new Document();
var style = document.AddStyle("BulletList", "Normal");
style.ParagraphFormat.LeftIndent = "0.5cm";
style.ParagraphFormat.ListInfo = new ListInfo
{
ContinuePreviousList = true,
ListType = ListType.BulletList1
};
var section = document.AddSection();
section.AddParagraph("Bullet 1", "BulletList");
section.AddParagraph("Bullet 2", "BulletList");
Style is only created once, including listinfo, and can be re-used everywhere.
With PDFsharp you must draw the bullets yourself.
With MigraDoc you add a paragraph and set paragraph.Format.ListInfo for this paragraph to create a bullet list.
The linked thread shows two helper routines:
DefineList() only sets a member variable so next time a new list will be created.
AddToList() is called for each entry.
Simply call DefineList() to start a new bullet list, then call AddToList() for every entry.
DefineList() makes a big difference for numbered lists.
Adapt the helper routines for your needs.

Categories

Resources