Lightswitch export all rows to CSV - c#

I am using c# and VS2012 on a lightswitch web-application,
I wish to export my data to CSV (on a search screen!), but can't reach any POC,
As i understand there are 2 main problems - a savefiledialog must be caused directly from a user button and in it must happened in the main dispatcher,
I used this code :
partial void mySearchScreen_Created()
{
var CSVButton = this.FindControl("ExportToCSV");
CSVButton.ControlAvailable += ExportCSV_ControlAvailable;
}
private void ExportCSV_ControlAvailable(object sender, ControlAvailableEventArgs e)
{
this.FindControl("ExportToCSV").ControlAvailable -= ExportCSV_ControlAvailable;
Button Button = (Button)e.Control;
Button.Click += ExportCSV_Click;
}
private void ExportCSV_Click(object sender, System.Windows.RoutedEventArgs e)
{
Microsoft.LightSwitch.Details.Client.IScreenCollectionProperty collectionProperty = this.Details.Properties.mySearch;
var intPageSize = collectionProperty.PageSize;
//Get the Current PageSize and store to variable
collectionProperty.PageSize = 0;
var dialog = new SaveFileDialog();
dialog.Filter = "CSV (*.csv)|*.csv";
if (dialog.ShowDialog() == true) {
using (StreamWriter stream = new StreamWriter(dialog.OpenFile())) {
string csv = GetCSV();
stream.Write(csv);
stream.Close();
this.ShowMessageBox("Excel File Created Successfully. NOTE: When you open excel file and if you receive prompt about invalid format then just click yes to continue.", "Excel Export", MessageBoxOption.Ok);
}
}
collectionProperty.PageSize = intPageSize;
//Reset the Current PageSize
}
private string GetCSV()
{
StringBuilder csv = new StringBuilder();
int i = 0;
foreach (var orderRow_loopVariable in mySearch) {
var orderRow = orderRow_loopVariable;
////HEADER
if (i == 0) {
int c = 0;
foreach (var prop_loopVariable in orderRow.Details.Properties.All().OfType<Microsoft.LightSwitch.Details.IEntityStorageProperty>()) {
var prop = prop_loopVariable;
if (c > 0) {
csv.Append(",");//Constants.vbTab
}
c = c + 1;
csv.Append(prop.DisplayName);
}
}
csv.AppendLine("");
////DATA ROWS
int c1 = 0;
foreach (var prop_loopVariable in orderRow.Details.Properties.All().OfType<Microsoft.LightSwitch.Details.IEntityStorageProperty>()) {
var prop = prop_loopVariable;
if (c1 > 0) {
csv.Append(",");//Constants.vbTab
}
c1 = c1 + 1;
csv.Append(prop.Value);
}
i = i + 1;
}
if (csv.Length > 0) {
return csv.ToString(0, csv.Length - 1);
} else {
return "";
}
}
This works, but it only get's me the first page items,
On another thing i had to do i solved that problem by using this code :
this.DataWorkspace.myDataContextData.MySearch(...).Execute();
Yet trying that instead of just using 'MySearch' gives me the following error :
t is not valid to call Execute() on a different Dispatcher than the ExecutableObject's Logic Dispatcher.
Why is it so difficult to do such a basic thing related to data (export to csv/excel) on a system build for handling data ?
Any ideas ?

The simplest workaround if this is the only use of the search screen would be to turn off paging. To do this go to the screen designer, highlight the query on the left, and in properties uncheck 'support paging.'
I'm not sure what the limitations are, but you can run some code in a different dispatcher using:
this.Details.Dispatcher.BeginInvoke(() =>
{
//This runs on main dispatcher
});

I don't think there's anything wrong with your code, but I've noticed that it takes a while to reset the page size on a large collection, in which time the rest of your code continues to execute. I think that's why you only get the first page. The only solution I've found is to wait.
When the "File Download - Security Warning" dialog pops up, keep an eye on the 'busy' indicator on the screen's tab and also the 'Page x of y' status at the bottom of the grid if you can see it. Only when the busy indicator has gone and the status just says 'Page' should you click OK to continue.
I haven't figured out a way of doing this programmatically so it's not a very helpful feature unless you have a very tightly controlled user population. But if it's just you and a couple of power users, it is workable. I'm also not sure if this has been improved on in versions after VS2012.
There can be a downside to the other answer of taking the paging off the query entirely. I've tried that workaround when the grid collection was being displayed in a modal window and the window became uncloseable if there were too many rows in the grid.
Phil

Related

C# - Button Placement inside a RichtextBox

I'm currently struggling with a button I want to add dynamically inside a RichTextBox.
The main issue is that I can't seem to get the location down properly (Location X & Y) also that the Text adjusts with Form Changes but the location of the Buttons won't.
The concept behind this is that I want to be able to write RTF Documents and include Button Clicks for certain Functions (Copy for now) without having to adjust the program every time.
My idea was to have a very specific Pattern -> [Copy|WHAT-TO-COPY] and replace every occurrence of this with a [C] Button in the application.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
LoadRTF();
AddButtons();
}
private void LoadRTF()
{
richTextBox1.LoadFile("RTF Path");
richTextBox1.ReadOnly = true;
}
private void AddButtons()
{
String Text = richTextBox1.Rtf;
richTextBox1.ReadOnly = false;
foreach (Match CopyMatch in Regex.Matches(Text, #"\[Copy\|.*\]", RegexOptions.IgnoreCase))
{
string CopyString = CopyMatch.Value;
var CopyPosition = richTextBox1.GetPositionFromCharIndex(richTextBox1.Find(CopyString));
Button Copy = new Button
{
Text = "Copy",
Size = new Size(20, 23),
Location = new Point(CopyPosition.X, CopyPosition.Y)
};
Copy.Click += (_, args) =>
{
Clipboard.SetText(CopyString.Substring(6, CopyString.Length - 7));
};
richTextBox1.SelectionStart = richTextBox1.Find(CopyString);
richTextBox1.SelectionLength = CopyString.Length;
richTextBox1.SelectedText = "";
richTextBox1.Controls.Add(Copy);
}
richTextBox1.ReadOnly = true;
}
}
The first issue is that this method apparently doesn't work to get the proper X,Y values for the Button Creation. It seems the values don't align with the found PositionFromChar(Index).
Am I headed in the entirely wrong direction is this a proper start? What am I missing?
Also, I'm still completely new to programming so sorry if this is a total mess.

How to open a textfile in XNA/monogame(beginner here)?

Okay, so i am working in xna and i want to open this textfile which should open in a textfile. Here is the code:
if (Keyboard.GetState().IsKeyDown(Keys.G) == true)
{
var fileToOpen = "Name.txt";
var process = new Process();
process.StartInfo = new ProcessStartInfo()
{
UseShellExecute = true,
FileName = fileToOpen
};
process.Start();
process.WaitForExit();
}
However an error occurs and cant find the textfile to open. I did this in a normal consol application and just added a new item textfile to the project and it worked fine in the console application, however in XNA it does not seem to work at all.
Also im really not well educated in file directory things and need a quick fix. The text files are placed in this area:
I hope this is of somehelp im trying to give as much information as possible. Just to note streamwriting to textfiles in the directory location shown in the image link works perfectly fine and i just give the name of the file as shown below:
if (player.GetRec.Intersects(map.sharkRec))
{
using (StreamWriter writer = new StreamWriter("CurrentScore.txt"))
{
writer.Write(time);
}
player.Position = new Vector2(64,100);
mCurrentScreen = ScreenState.leaderboard;
}
However it just didt seem to work when i want to open the textfile in notepad and allow for typing to be done in the textfile in notepad. The reason why i want to open a text file for typing is the user entering there name and i dont have knowledge or the time to do XNA textbox input creation which seems complicated from the tutorials i have seen, which is why i want to open the textfile in notepad for editing. Furthermore this is going to be used on other people's computers so if directorys have to be used i need a directory that will work on other computers as well as my own, just to note directory entering seems to confuse me.
Hope i have given enough information and i really hope someone can help this beginner out here :)
For this to work, your code should be something like this:
using(StreamWriter ...)
{
show textbox so the user can see what he's typing
for each keypress add the letter
exit on ESC button (for example)
delete char on Backspace
etc...
}
Now, I personaly don't recommend this type of code. Open the file, do what you have to do with it and close it. The code below is how I programmed textbox for my game. I hope it helps (you could say this is more a little tutoial for better approach to the problem instead an answer to the exact problem you put up for yourself).
namespace Acircalipse.MenuClasses
{
public class TextBox:MenuItem
{
private string originTitle;
public string Text
{
get
{
return title.Replace(originTitle, "").Replace(Menu.separator, "");
}
}
public int index, max;
public TextBox (string Title, string text = "", int MaxCharacters = 14)
{
originTitle = Title;
index = 0;
max = MaxCharacters;
SetText(text);
}
public void SetText (string text)
{
if (text.Length > max) text = text.Substring(0, max);
title = originTitle + Menu.separator + text;
}
public void ChangeIndex (int howMuch)
{
index += howMuch;
ChangeCar(index);
}
public void AddChar (int index = 0)
{
SetText(Text + Menu.Wheel(index));
}
public void ChangeCar (int index)
{
if(Text.Length > 0)
SetText(Text.Substring(0, Text.Length - 1) + Menu.Wheel(index));
}
public void DeleteChar ()
{
if (Text.Length > 0)
SetText(Text.Substring(0, Text.Length - 1));
}
}
}
Where the Menu.Wheel(int index) is simply an array of available character for user to type in
public static char Wheel(int index)
{
string charWheel = " ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
int max = charWheel.Length;
while (index > max) index -= max;
while (index ("less than" sign here) 0) index += max;
return charWheel[index];
}
Where Menu.separator is a string ": ".
The code is pretty self explanatory.
Now, when using this class, you'll have to have one bool to see if the user has activated this textbox, and if he has, add text on keypress. If the textbox is inactive, just continue your normal update
What you have to understand is that textbox is a simple string witch is updated when textbox is active, and just showed when not active.
Using this simple and on point definition of TextBox, you can simply create your own class that will work the way you want to.
If this answer helped you resolve your problem, please mark it as the solution.

WebBrowser isn't working

I have this code:
This is a button press:
int part = 0;
web.Navigate(loginURL.Text + "/auth/login");
wait.Enabled = true;
This is a timer "wait", with interval set to 6000:
if (part == 0)
{
part = 2;
web.Document.GetElementById("idLoginUserName").SetAttribute("value", user);
web.Document.GetElementById("idLoginPassword").SetAttribute("value", pass);
web.Document.GetElementById("idLoginBtn").InvokeMember("click");
}
if (part == 2)
{
web.Navigate(fullURL.Text);
part = 3;
}
if (part == 3)
{
web.Document.GetElementById("title").SetAttribute("value", title.Text);
}
if (part == 4)
{
web.Navigate("www.vbulletin.com/forum/auth/logout");
part = 5;
}
if (part == 5)
{
part = 0;
web.Navigate(loginURL.Text + "/auth/login");
}
The button press works fine, however:
web.Document.GetElementById("idLoginUserName").SetAttribute("value", user);
web.Document.GetElementById("idLoginPassword").SetAttribute("value", pass);
web.Document.GetElementById("idLoginBtn").InvokeMember("click");
does nothing. The text isn't changed, the button isn't clicked, etc. I've checked and double checked the IDs and it's right.
The loginURL.Text is this
My guess you try to access the document before navigation is completed, this works for me...
web.DocumentCompleted += (s, e) =>
{
web.Document.GetElementById("idLoginUserName").SetAttribute("value", user);
web.Document.GetElementById("idLoginPassword").SetAttribute("value", pass);
web.Document.GetElementById("idLoginBtn").InvokeMember("click");
};
web.Navigate("http://www.vbulletin.com/forum/auth/login");
You are not obliged to do everything using C#. If you treat the embedded web page as a black box fro the point of view of your app, you can give it internal behaviours using scripts, and jQuery makes this sort of thing short, sweet and very legible for those who come after, with the added benefit of not polluting application logic with functionally trivial but frequently complex UI behaviour code.
$(function(){
$("#idLoginUserName").val(user);
$("#idLoginPassword").val(password);
$("#idLoginBtn").click();
});

Adding a wizard to a blank project: "The operation could not be completed. No such interface supported"

I've created a custom wizard that generates a windows form through code that lists out some SQL queries for the user. For almost all of the testing of the form and the wizard itself, adding it to a blank project would bring up the form and I could test the button click events and other general form stuff. Most recently I fleshed out the listbox's event listeners and ever since then I get this error:
Googling has lead me to a lot of posts about Ruby, which I'm not using. Other suggestions were reboot and re installation, and those proved unsuccessful. I attempted to comment out the listbox events but that did not keep the error from occuring, however, if it helps here are the events in question:
//-----------Event fired when a listbox object is double-clicked; populate the listbox with the new databases---------
public void dataList_MouseDoubleClick(object sender, EventArgs e)
{
//temp string used to hold the name of the clicked object
string selectedNAME = dataList.SelectedItem.ToString();
firstSEL.TableVar = selectedNAME;
foreach (tempDataVar t in dataVars)
{
if (t.TableVar == firstSEL.TableVar)
{
firstSEL = t;
}
}
string newQ = "SELECT COLUMN_NAME,* FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = '" + firstSEL.TableVar + "' AND TABLE_SCHEMA= '" + firstSEL.SchemaVar + "'";//order by TABLE_NAME'";
results = GetDataSet(bldr.ToString(), newQ);
//listBox1.Items.Clear();
foreach (DataRow row in results.Tables[0].Rows)
{
//foreach (object x in row.ItemArray)
//{
// listBox1.Items.Add(x.ToString());
//}
for (int x = 0; x < row.ItemArray.Length; x++)
{
if (x == 0)
{
colList.Items.Add(row.ItemArray[x]);
}
}
}
dataList.Enabled = false;
}
//-----------------------------Event that fires when the index of the second listbox changes--------------------------
private void colList_SelectedIndexChanged(object sender, EventArgs e)
{
btnYes.Enabled = true;
}
Noobie mistake fixed by a co-worker! I blindly copied and pasted the following code from a "How to make a wizard tutorial":
[ComVisible(true)]
[Guid("20184B81-7C38-4E02-A1E3-8D564EEC2D25"),
ProgId("MyNewWizard.Class1")]
This code needed to be directly above the MyNewWizard class and I accidentally pasted in my custom TempDataVar class in the white space between these lines and the start of the MyNewWizard class. If you're receiving a similar error then I'd suggest testing around the order of some of your attributes/classes!

Multi-line textbox shows mult-line string as One-Line

I am making a program where you enter an item's name and it's description. Then you add it to a listbox and after you are done you can save all the items to a 'txt' file. (Using StreamWriter). This program also has an edit button that allows you to edit the description in the listbox by removing it first from the listbox and then showing it back in the textbox (, so you can edit it)
If the description is multi-line, it will successfuly show it multi-line when I select it in the listbox and click the edit button that will show it back in the textbox. BUT if I save all the items in the listbox to a file first. And then open up the file again so it load the items back into the listbox. And then clicking the edit button...
The multi-line description will show as a one-line description in the textbox.
I am not sure why - but I've also made a label that will show the exact string that the textbox is suppose to show and the label is showing it multi-lined while textbox isn't!
The string is definitely multi-line but the multi-line textbox is showing it one-line after loading the items back into the listbox using StreamReader.
Example of the multi-line string: (named "theString1")
This is line 1
This is line 2
Using the following code: TextBox1.Text = theString1; this appears in the text box:
This is line1This is line2
But if I use the same code with a label. It will show it correctly.
If someone can explain to me why this is happening I will be more than happy. I just need an explanation.
Thanks in advance.
---[More info]---
Just so you know. I came up with this code myself so it is probably set-up all wrong.
I will be happy if you tell me a better way to do this.
I am using a list to store the description text + the item name. I seperated these two using '`' .And splited the string (see code).
This is the code that happens when you click the edit button. It removes the item from
the listbox and shows it in the textbox so you can edit it and add to listbox again:
int index = listBox.SelectedIndex;
itemName.Text = listBox.SelectedItem.ToString();
var descVar = descList.ElementAt(index).Split('`');
string theString1 = descVar[1];
TextBox1.Text = theString1;
This is how it saves it to a file:
FileDialog save = new SaveFileDialog();
save.Title = "Save information...";
save.DefaultExt = "Text File|*.txt";
save.Filter = "Text File|*.txt";
if (save.ShowDialog() == DialogResult.OK)
{
StreamWriter sw = new StreamWriter(save.FileName);
foreach (string s in listBox.Items) //This writes the names of item names.
{
sw.WriteLine(s);
}
sw.WriteLine("`1`"); //I use this to seperate the item names from description.
foreach (string s in descList) //This writes the descriptions that are stored in a list named "descList".
{
sw.WriteLine(s);
sw.WriteLine("``"); //I use this to seperate descriptions from each other because they are multi-line.
}
sw.WriteLine("`2`"); //Just something so I know where it ends. :D
sw.Close();
}
else
{
}
And this is how it loads: (This can definitely be better!)
FileDialog load = new OpenFileDialog();
load.Title = "Load information...";
load.DefaultExt = "Text File|*.txt";
load.Filter = "Text File|*.txt";
if (load.ShowDialog() == DialogResult.OK)
{
List<string> loadDesc = new List<string>(); //Don't ask you will see why
descList.Clear();
while (listBox.Items.Count > 0) //This removes all items in the listbox to load new ones.
{
int index = 0;
listBox.Items.RemoveAt(index);
descList.Clear();
itemName.Text = "";
}
StreamReader rw = new StreamReader(load.FileName);
for (; true; )
{
string read = rw.ReadLine();
if (read == "`1`") //When it reaches the separator I made it stops reading.
{
break;
}
else
{
listBox.Items.Add(read);
}
}
for (; true; )
{
string read = rw.ReadLine();
if (read == "`2`")
{
break;
}
else
{
loadDesc.Clear();
loadDesc.Add(read);
for (; true; ) //Please tell me if this can be done differently.
{
string read2 = rw.ReadLine();
if (read2 != "``") //This will keep reading the whole description until it reaches the separator.
{
loadDesc.Add(read2); //Adds each line into the list I created.
}
else
{
break;
}
}
string oneBigString = string.Join("\n", loadDesc); //This basically converts all strings in a list into one string.
descList.Add(oneBigString); //And this finally add the string to the main list from where it then loads.
}
}
}
else
{
}
I believe that is it.
If there is anything else you need - tell me.
string oneBigString = string.Join("\n", loadDesc); is where the issue is.
Use Environment.NewLine instead of \n
I'm also just going to go over a couple of things that could be improved with your code (there are a lot, but I just want to cover a couple).
while (listBox.Items.Count > 0) //This removes all items in the listbox to load new ones.
You don't need to iterate over every element in the listbox to remove it. You can just do listBox.clear()
Also, using break to get out of loops is generally bad practice. This should be written as...
for (; true; )
{
string read = rw.ReadLine();
if (read == "`1`") //When it reaches the separator I made it stops reading.
{
break;
}
else
{
listBox.Items.Add(read);
}
}
this
string read = rw.ReadLine()
while(read != "`1`")
{
listBox.Items.Add(read);
read = rw.ReadLine()
}
but theres more, what if 1 is never found in the file? It would crash your program, so you also need to check if there is more data to be read...
string read = rw.ReadLine()
while(read != "`1`" && !sw.EndOfStream) // Make sure you're not at the end of the file
{
listBox.Items.Add(read);
read = rw.ReadLine()
}

Categories