Problem pasting HTML from selection in web browser - c#

I am putting together a WYSIWYG html editor using the .NET webbrowser control. I have managed to piece together the code for inserting a table at the cursor position. However I am now trying to do something a little different.
What I need to do is insert a and html comment around a table row. I've managed to write the code that, from the cursor position, looks to the parent elements to find the table row the curor is sat in. The problem is when I try to use the pastHtml method in the range, it throws an exception with no detail on why its failed!.
Code listed below.
private void OnTest(object sender, EventArgs e)
{
try
{
IHTMLDocument2 doc = wbDesign.Document.DomDocument as IHTMLDocument2;
IHTMLSelectionObject currentSelection = doc.selection;
if (currentSelection != null)
{
IHTMLTxtRange range = currentSelection.createRange() as IHTMLTxtRange;
bool foundRow = false;
IHTMLElement parentElement = null;
parentElement = range.parentElement();
if ("TR" == parentElement.tagName) foundRow = true;
while (!foundRow)
{
if (null == parentElement.parentElement) break;
parentElement = parentElement.parentElement;
if ("TR" == parentElement.tagName) foundRow = true;
}
if (foundRow)
{
currentSelection.clear();
range.moveToElementText(parentElement);
range.pasteHTML("test");
}
else
{
MessageBox.Show("Unable to find table row from selection point.");
}
}
}
catch (Exception error)
{
MessageBox.Show(error.Message);
}
}

Related

RowUniqueID in filtered row

could somebody help me in C# programing in an web application. Namely, how can we find out RecordUniqueId of the filtered row....in order to further edit (i.e., set values in some other columns in the same row), based on RecordUniqueId value? Or, is it possible to, upon clicking on enter button in order to search for certain row, to immediately have some actions performed on the values in some other columns of filtered row? Let me say in other words, to have some kind of automation of editing values in some other columns of the filtered row?
Thanks in advance
public class PartyVuk2010GENTableControlRow : BasePartyVuk2010GENTableControlRow
{
}
public class PartyVuk2010GENTableControl : BasePartyVuk2010GENTableControl
{
public override void MarkDiscontinued_Click(object sender, ImageClickEventArgs args)
{
try {
DbUtils.StartTransaction();
foreach (PartyVuk2010GENTableControlRow rc in this.GetSelectedRecordControls()) {
PartyVuk2010GENRecord rec;
rec = PartyVuk2010GENTable.GetRecord(rc.RecordUniqueId, true);
if (rec != null) {
rec.Discontinued = true;
rec.Test = "10";
rec.BallotOrder = PartyVuk2010GENTable.Instance.GetLargest()+1;
rec.Save();
}
}
DbUtils.CommitTransaction();
}
catch (Exception ex) {
BaseClasses.Utils.MiscUtils.RegisterJScriptAlert(this, "BUTTON_CLICK_MESSAGE", ex.Message);
}
finally {
DbUtils.EndTransaction();
}
this.DataChanged = true;
}

Extract a string from a webpage

i need to have a label where its text comes from a web page, but for somting it doesnt work out, it appearce to me that the webpae returned null, but the location is correct.
WebBrowser JOJO = new WebBrowser();
string Tesla = "";
JOJO.Url = new Uri("https://finance.yahoo.com/quote/TSLA?p=TSLA");
var sal = JOJO.Document.GetElementsByTagName("div");// this return null
foreach (HtmlElement link in sal)
{
if (link.GetAttribute("className") == "D(ib) Mend(20px)")/*this is the class of the element*/
{
Tesla = link.FirstChild.InnerHtml;
}
}
label11.Text = Tesla;
this is the code that i have done so far, can someone see why dosnt work?
Thanks.
It is null because it didn't load yet when you try to access it. You should be handling it asynchronously.
Handle the DocumentCompleted event and access the Document in the handler.
Replace the code you have with:
WebBrowser JOJO = new WebBrowser();
JOJO.DocumentCompleted += new System.Windows.Forms.WebBrowserDocumentCompletedEventHandler
(this.BrowserDocumentCompleted);
JOJO.Url = new Uri("https://finance.yahoo.com/quote/TSLA?p=TSLA");
And here is the handler:
void BrowserDocumentCompleted(object sender,
WebBrowserDocumentCompletedEventArgs e)
{
if (e.Url.AbsolutePath != (sender as WebBrowser).Url.AbsolutePath)
return;
string Tesla = "";
var sal = (sender as WebBrowser).Document.GetElementsByTagName("div");
foreach (HtmlElement link in sal)
{
if (link.GetAttribute("className") == "D(ib) Mend(20px)")
{
Tesla = link.FirstChild.InnerHtml;
}
}
label1.Text = Tesla;
}
Now you will maybe face other problems with redirections. But that is another discussion :)

Faster way of reading csv to grid

I have following in Windows Forms .NET 3.5
It works fine for csv with records less than 10,000 but is slower for records above 30,000.
Input csv file can can any records between 1 - 1,00,000 records
Code currently used :
/// <summary>
/// This will import file to the collection object
/// </summary>
private bool ImportFile()
{
try
{
String fName;
String textLine = string.Empty;
String[] splitLine;
// clear the grid view
accountsDataGridView.Rows.Clear();
fName = openFileDialog1.FileName;
if (System.IO.File.Exists(fName))
{
System.IO.StreamReader objReader = new System.IO.StreamReader(fName);
do
{
textLine = objReader.ReadLine();
if (textLine != "")
{
splitLine = textLine.Split(',');
if (splitLine[0] != "" || splitLine[1] != "")
{
accountsDataGridView.Rows.Add(splitLine);
}
}
} while (objReader.Peek() != -1);
}
return true;
}
catch (Exception ex)
{
if (ex.Message.Contains("The process cannot access the file"))
{
MessageBox.Show("The file you are importing is open.", "Import Account", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
else
{
MessageBox.Show(ex.Message);
}
return false;
}
}
Sample Input file :
18906,Y
18908,Y
18909,Y
18910,Y
18912,N
18913,N
Need some advice on optimizing this code for fast reads & view in grid.
List<string[]> rows = File.ReadAllLines("Path").Select(x => x.Split(',')).ToList();
DataTable dt = new DataTable();
dt.Columns.Add("1");
dt.Columns.Add("2");
rows.ForEach(x => {
dt.Rows.Add(x);
});
dgv.DataSource = dt;
Try that, I suspected that you have some form of column names in the datagrid for now I just made them 1 and 2.
To filter as per your original code use:
List<string[]> rows = File.ReadAllines("Path").Select(x => x.Split(',')).Where(x => x[0] != "" && x[1] != "").ToList();
To get your columns from the DataGridView
dt.Columns.AddRange(dgv.Columns.Cast<DataGridViewColumn>().Select(x => new DataColumn(x.Name)).ToArray());
There isn't much to optimize in regards to speed, but following is much more readable. If it is too slow, it probably isn't the method reading the file, but your WinForm that needs to display >30k records.
accountsDataGridView.Rows.Clear();
using (FileStream file = new FileStream(openFileDialog1.FileName, FileMode.Open, FileAccess.Read, FileShare.Read, 4096))
using (StreamReader reader = new StreamReader(file))
{
while (!reader.EndOfStream)
{
var fields = reader.ReadLine().Split(',');
if (fields.Length == 2 && (fields[0] != "" || fields[1] != ""))
{
accountsDataGridView.Rows.Add(fields);
}
}
}
You can try to use SuspendLayout() and ResumeLayout() Methods.
From MSDN Documentation
"The SuspendLayout and ResumeLayout methods are used in tandem to suppress multiple Layout events while you adjust multiple attributes of the control. For example, you would typically call the SuspendLayout method, then set the Size, Location, Anchor, or Dock properties of the control, and then call the ResumeLayout method to enable the changes to take effect."
accountsDataGridView.SuspendLayout();
accountsDataGridView.Rows.Clear();
// .....
// in the end after you finished populating your grid call
accountsDataGridView.ResumeLayout();
Instead of putting the data directly into the grid you should take a look at the VirtualMode of the DataGridView.
In your code you're doing two things at one time (read the file, fill the grid), which leads to your freezed gui. Instead you should put the grid into the virtual mode and read the file within a BackgroundWorker into a list which holds the data for the grid. The background worker can after each line read update the virtual size of the grid, which allows to already see the data while the grid is loading. By using this approach you'll getting a smooth working grid.
Below you'll find an example which just needs to be filled into a form that uses a DataGridView with two text columns, a BackgroundWorker and a Button:
public partial class FormDemo : Form
{
private List<Element> _Elements;
public FormDemo()
{
InitializeComponent();
_Elements = new List<Element>();
dataGridView.AllowUserToAddRows = false;
dataGridView.AllowUserToDeleteRows = false;
dataGridView.ReadOnly = true;
dataGridView.VirtualMode = true;
dataGridView.CellValueNeeded += OnDataGridViewCellValueNeeded;
backgroundWorker.WorkerReportsProgress = true;
backgroundWorker.DoWork += OnBackgroundWorkerDoWork;
backgroundWorker.ProgressChanged += OnBackgroundWorkerProgressChanged;
backgroundWorker.RunWorkerCompleted += OnBackgroundWorkerRunWorkerCompleted;
}
private void OnBackgroundWorkerDoWork(object sender, DoWorkEventArgs e)
{
var filename = (string)e.Argument;
using (var reader = new StreamReader(filename))
{
string line = null;
while ((line = reader.ReadLine()) != null)
{
var parts = line.Split(',');
if (parts.Length >= 2)
{
var element = new Element() { Number = parts[0], Available = parts[1] };
_Elements.Add(element);
}
if (_Elements.Count % 100 == 0)
{
backgroundWorker.ReportProgress(0);
}
}
}
}
private void OnBackgroundWorkerProgressChanged(object sender, ProgressChangedEventArgs e)
{
dataGridView.RowCount = _Elements.Count;
}
private void OnBackgroundWorkerRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
dataGridView.RowCount = _Elements.Count;
button.Enabled = true;
}
private void OnButtonLoadClick(object sender, System.EventArgs e)
{
if (!backgroundWorker.IsBusy
&& DialogResult.OK == openFileDialog.ShowDialog())
{
button.Enabled = false;
backgroundWorker.RunWorkerAsync(openFileDialog.FileName);
}
}
private void OnDataGridViewCellValueNeeded(object sender, DataGridViewCellValueEventArgs e)
{
var element = _Elements[e.RowIndex];
switch (e.ColumnIndex)
{
case 0:
e.Value = element.Number;
break;
case 1:
e.Value = element.Available;
break;
}
}
private class Element
{
public string Available { get; set; }
public string Number { get; set; }
}
}

collapse all elements for loaded xml in webbrowser control using c#

I am using the System.Windows.Forms.WebBrowser to display XML in a syntax highlighted and easy to traverse format. Whenever I load the XML into the Control, I would like to have all the elements collapsed, is this possible?
This is triggered by the DocumentCompleted event handler.
this was a useful link to help with java script injection:
How to execute custom JavaScript in WebBrowser control?
I used the following code.
private void CollapseExpandDocument(object sender, WebBrowserDocumentCompletedEventArgs e)
{
if (sender == null)
{
return;
}
try
{
WebBrowser me = (WebBrowser) sender;
HtmlElement head = me.Document.GetElementsByTagName("head")[0];
HtmlElement scriptEl = me.Document.CreateElement("script");
IHTMLScriptElement element = (IHTMLScriptElement)scriptEl.DomElement;
string func = #"
function collapseDoc()
{
var className = 'b';
var hasClassName = new RegExp('(?:^|\\s)' + className + '(?:$|\\s)');
var allElements = document.getElementsByTagName('a');
var element;
for (var i = 0; (element = allElements[i]) != null; i++)
{
var elementClass = element.className;
if (elementClass && elementClass.indexOf(className) != -1 && hasClassName.test(elementClass))
ch(element.parentElement.parentElement);
}
}";
element.text = func;
head.AppendChild(scriptEl);
me.Document.InvokeScript("collapseDoc");
}
catch
{
//not interested in knowing if the collapse/expand failed...
}
}

Problems submitting DataGridView changes with Linq-to-SQL

I'm trying to implement database value edition through a DataGridView control but honestly I'm having a hard time trying to accomplish that. I'm basically using LINQ-to-SQL classes and events, the following being the most significant snippets:
var data = from q in data.FOOBARS
select new
{
ID = q.FOOBAR_ID,
LOREM = q.FOOBAR_LOREM,
IPSUM = q.FOOBAR_IPSUM
};
DataGridView grid = new DataGridView();
grid.DataSource = data;
// grid EVENTS
private void grid_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
{
this.grid.CurrentCell.ReadOnly = false;
this.grid.BeginEdit(true);
}
private void grid_CellLeave(object sender, DataGridViewCellEventArgs e)
{
if (this.grid.CurrentCell.IsInEditMode)
{
// METHOD CALL
this.SetVariableValue(this.grid.CurrentRow.Cells["ID"].Value.ToString(), this.grid.CurrentCell.OwningColumn.Name, this.grid.CurrentCell.FormattedValue.ToString(), this.grid.CurrentCell.EditedFormattedValue.ToString());
}
this.grid.CommitEdit(DataGridViewDataErrorContexts.Commit);
this.grid.EndEdit();
}
// METHOD IMPL
private void SetVariableValue(string id, string type, string current, string edited)
{
try
{
if (current != edited)
{
using (FOOBARDataClassesDataContext data = new FOOBARDataClassesDataContext(this.BuildConnection()))
{
data.ExecuteCommand("SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED");
switch (type)
{
case "LOREM":
var currentLorem = data.FOOBARS.SingleOrDefault(v => v.FOOBAR_ID == Convert.ToInt32(id)).FOOBAR_LOREM;
currentLorem = edited;
data.SubmitChanges(ConflictMode.ContinueOnConflict);
break;
case "IPSUM":
var currentIpsum = data.FOOBARS.SingleOrDefault(v => v.FOOBAR_ID == Convert.ToInt32(id)).FOOBAR_IPSUM;
currentIpsum = edited;
data.SubmitChanges(ConflictMode.ContinueOnConflict);
break;
default:
break;
}
data.Refresh(RefreshMode.OverwriteCurrentValues);
}
}
}
catch (Exception error)
{
if (logger.IsErrorEnabled) logger.Error(error.Message);
}
}
Debugging looks good, objects are actually being updated but for some reason changes are neither being submitted nor updated.
Any help would be certainly appreciated. Thanks much you guys in advance!
For some reason this does NOT WORK:
var currentLorem = data.FOOBARS.SingleOrDefault(v => v.FOOBAR_ID == Convert.ToInt32(id)).FOOBAR_LOREM;
currentLorem = edited;
data.SubmitChanges(ConflictMode.ContinueOnConflict);
But this DOES (notice the changes in lines 1 and 2, FOOBAR_LOREM attribute):
var currentLorem = data.FOOBARS.SingleOrDefault(v => v.FOOBAR_ID == Convert.ToInt32(id));
currentLorem.FOOBAR_LOREM = edited;
data.SubmitChanges(ConflictMode.ContinueOnConflict);

Categories