Get current URL from active tab chrome vb net? - vb.net

I have search on google with keyword same as this question title.
Some code not work or complicated explanation, even in stackoverflow link.
I found one link work here.
But that code result is page title, not url.
How to make this code below to retrieve current url active tab on chrome?
here the code,
'//Grab all the Chrome processes
Dim chrome() As Process = Process.GetProcessesByName("chrome")
'//Exit if chrome isn't running
If chrome.Length <= 0 Then Exit Sub
For Each chromeProcess As Process In chrome
'//If the chrome process doesn't have a window handle then ignore it
If chromeProcess.MainWindowHandle <> IntPtr.Zero Then
'//To find the tabs we first need to locate something reliable - the 'New Tab' button
Dim rootElement As AutomationElement = AutomationElement.FromHandle(chromeProcess.MainWindowHandle)
Dim condNewTab As Condition = New PropertyCondition(AutomationElement.NameProperty, "New Tab")
Dim elemNewTab As AutomationElement = rootElement.FindFirst(TreeScope.Descendants, condNewTab)
'//Get the tabstrip by getting the parent of the 'new tab' button
Dim tWalker As TreeWalker = TreeWalker.ControlViewWalker
Dim elemTabStrip As AutomationElement = tWalker.GetParent(elemNewTab)
'//Loop through all the tabs and get the names which is the page title
Dim tabItemCondition As Condition = New PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.TabItem)
For Each tabItem As AutomationElement In elemTabStrip.FindAll(TreeScope.Children, tabItemCondition)
Debug.WriteLine(tabItem.Current.Name)
Next
End If
Next

Solved, From another forum,
Imports System.Windows.Automation
Module GoogleChrome
Private Const ChromeProcess As [String] = "chrome"
Private Const AddressCtl As [String] = "Address and search bar"
Public Function GetChromeActiveWindowUrl() As [String]
Dim procs = Process.GetProcessesByName(ChromeProcess)
If (procs.Length = 0) Then
Return [String].Empty
End If
Return procs _
.Where(Function(p) p.MainWindowHandle <> IntPtr.Zero) _
.Select(Function(s) GetUrlControl(s)) _
.Where(Function(p) p IsNot Nothing) _
.Select(Function(s) GetValuePattern(s)) _
.Where(Function(p) p.Item2.Length > 0) _
.Select(Function(s) GetValuePatternUrl(s)) _
.FirstOrDefault
End Function
Private Function GetUrlControl( _
proses As Process) _
As AutomationElement
Dim propCondition = _
New PropertyCondition( _
AutomationElement.NameProperty, _
AddressCtl)
Return AutomationElement _
.FromHandle(proses.MainWindowHandle) _
.FindFirst( _
TreeScope.Descendants, _
propCondition)
End Function
Private Function GetValuePatternUrl( _
element As Tuple(Of _
AutomationElement, AutomationPattern())) As [String]
Dim ap = element.Item2(0)
Dim ovp = element.Item1.GetCurrentPattern(ap)
Dim vp = CType(ovp, ValuePattern)
Return vp.Current.Value
End Function
Private Function GetValuePattern( _
element As AutomationElement) _
As Tuple(Of _
AutomationElement, _
AutomationPattern())
Return New Tuple(Of _
AutomationElement, _
AutomationPattern())( _
element, _
element.GetSupportedPatterns())
End Function
End Module

If you are using .Net framework 2.0 it works for Google Chrome 55 And Firefox. Send the process name to the method ("CHROME" or "FIREFOX"). Also, you must import UIAutomationClient.dll. I hope it helps someone.
private string GetBrowserUrlActivaChromeFirefox(string process)
{
Process[] procsChrome = Process.GetProcessesByName(process);
foreach (Process chrome in procsChrome)
{
if (chrome.MainWindowHandle == IntPtr.Zero)
continue;
UIAutomationClient.CUIAutomation element = new UIAutomationClient.CUIAutomation();
UIAutomationClient.IUIAutomationElement root = element.ElementFromHandle(chrome.MainWindowHandle);
if (element == null)
return "";
UIAutomationClient.IUIAutomationCondition condition1 = element.CreatePropertyCondition(UIAutomationClient.UIA_PropertyIds.UIA_ProcessIdPropertyId, chrome.Id);
UIAutomationClient.IUIAutomationCondition condition2 = element.CreatePropertyCondition(UIAutomationClient.UIA_PropertyIds.UIA_IsControlElementPropertyId, true);
UIAutomationClient.IUIAutomationCondition condition3 = element.CreatePropertyCondition(UIAutomationClient.UIA_PropertyIds.UIA_IsContentElementPropertyId, true);
UIAutomationClient.IUIAutomationCondition condition4 = element.CreatePropertyCondition(UIAutomationClient.UIA_PropertyIds.UIA_ControlTypePropertyId, UIAutomationClient.UIA_ControlTypeIds.UIA_EditControlTypeId);
UIAutomationClient.IUIAutomationCondition[] conditions = new UIAutomationClient.IUIAutomationCondition[4];
conditions[0] = condition1;
conditions[1] = condition2;
conditions[2] = condition3;
conditions[3] = condition4;
UIAutomationClient.IUIAutomationCondition andCondition = element.CreateAndConditionFromArray(conditions);
UIAutomationClient.IUIAutomationElement elementx = root.FindFirst(UIAutomationClient.TreeScope.TreeScope_Descendants, andCondition);
return ((UIAutomationClient.IUIAutomationValuePattern)elementx.GetCurrentPattern(UIAutomationClient.UIA_PatternIds.UIA_ValuePatternId)).CurrentValue.ToString();
}
return string.Empty;
}

This C# code works for me on non-English browsers:
// Check for Chrome
if (processName.Equals("chrome"))
{
Process[] procsChrome = Process.GetProcessesByName("chrome");
foreach (Process chrome in procsChrome)
{
// the chrome process must have a window
if (chrome.MainWindowHandle == IntPtr.Zero)
continue;
try
{
CUIAutomation _automation = new CUIAutomation();
var appElement = _automation.ElementFromHandle(chrome.MainWindowHandle);
IUIAutomationCondition[] conditionArray = new IUIAutomationCondition[3];
conditionArray[0] = _automation.CreatePropertyCondition(UIA_PropertyIds.UIA_ProcessIdPropertyId, chrome.Id);
conditionArray[1] = _automation.CreatePropertyCondition(UIA_PropertyIds.UIA_NamePropertyId, "Google Chrome");
conditionArray[2] = _automation.CreatePropertyCondition(UIA_PropertyIds.UIA_ControlTypePropertyId, UIA_ControlTypeIds.UIA_PaneControlTypeId);
IUIAutomationCondition conditions = _automation.CreateAndConditionFromArray(conditionArray);
IUIAutomationElement frameElement = appElement.FindFirst(TreeScope.TreeScope_Subtree, conditions);
if (frameElement != null)
{
conditionArray = new IUIAutomationCondition[2];
conditionArray[0] = _automation.CreatePropertyCondition(UIA_PropertyIds.UIA_ProcessIdPropertyId, chrome.Id);
conditionArray[1] = _automation.CreatePropertyCondition(UIA_PropertyIds.UIA_ControlTypePropertyId, UIA_ControlTypeIds.UIA_EditControlTypeId);
conditions = _automation.CreateAndConditionFromArray(conditionArray);
frameElement = frameElement.FindFirst(TreeScope.TreeScope_Descendants, conditions);
if (frameElement != null)
return ((IUIAutomationValuePattern)frameElement.GetCurrentPattern(10002)).CurrentValue;
}
}
catch (Exception e)
{
continue;
}
}
}
The COM interface is much more efficient then the old one from System.Windows.Automation.

Related

Placing a collection of values into a For...each loop

I have this code written to return a collection of an object with properties as follows:
Public Shared Function Create() As Collection(Of Element)
Return New Collection(Of Element)() From { _
New Element() With { _
.Group = 1, _
.Period = 1, _
.Name = "Hydrogen" _
}, _
New Element() With { _
.Group = 18, _
.Period = 1, _
.Name = "Helium" _
}, _
New Element() With { _
.Group = 1, _
.Period = 2, _
.Name = "Lithium" _
}
}
End Function
I would now like to get these values from a database, but I can't figure out how to reformat the code. My returning procedure should be something like this:
Public Shared Function CreateDB() As Collection(Of Element)
Using db As New DataClassesDataContext(ACCCon)
Dim rows = (From row In db.PeriodicTableQs
Order By row.ID
Select row).ToList()
For Each s In rows
<<collect the elements here as result>>
<<eg, New Element() With {.Group = s.Group}>>
Next
End Using
Return Result
End Function
Thanks!
Try this:
Public Shared Function CreateDB() As Collection(Of Element)
Dim ACCCon As String = "ConnectionString"
Using db As New DataClassesDataContext(ACCCon)
Dim List = db.PeriodicTableQs.
OrderBy(Function(Q) Q.ID).ToList.
Select(Function(row)
Return New Element With {
.Group = row.Group,
.Name = row.Name,
.Period = row.Period
}
End Function)
End Using
Return New Collection(Of Element)(List)
End Function

Exchange Web service (EWS) chain FindItemType for itemItemclas & messageIsRead

High fellow coders.
I'm using the raw exchange web service, referenced in my SSIS script task.
My issue is that when I enumerate items in a mailbox or folder, Not only am I interested in only those items that have not been read, but I want to ignore all the system type messages. so I only want items, specifically messages, who's "itemclass" is "IPM.Note" nothing else.
Here is a definitive list of Item Types and Message classes
https://msdn.microsoft.com/en-us/library/office/ff861573.aspx
my code which works successfully for unread items in the inbox
'declare my find criteria, return only the IDs, from the inbox, for unread items
Dim reqFindUnreadMailInInbox As FindItemType = New FindItemType With _
{.Traversal = ItemQueryTraversalType.Shallow _
, .ItemShape = New ItemResponseShapeType With {.BaseShape = DefaultShapeNamesType.IdOnly} _
, .ParentFolderIds = New DistinguishedFolderIdType(0) {New DistinguishedFolderIdType With {.Id = DistinguishedFolderIdNameType.inbox}} _
, .Restriction = New RestrictionType With _
{.Item = New IsEqualToType With _
{.Item = New PathToUnindexedFieldType With {.FieldURI = UnindexedFieldURIType.messageIsRead} _
, .FieldURIOrConstant = New FieldURIOrConstantType With {.Item = New ConstantValueType With {.Value = "0"}} _
} _
} _
}
'go fetch the response from exchange
Dim resFindItemResponse As FindItemResponseType = esb.FindItem(reqFindUnreadMailInInbox)
Dim resFindFolderMessages As FindItemResponseMessageType = resFindItemResponse.ResponseMessages.Items(0)
Dim resFolderItems As ArrayOfRealItemsType = Nothing '= New ArrayOfRealItemsType
The problem I have is I want to add a restriction on the itemClass that is returned. But cannot figure out how to add a second Restriction to the request. This is what the restriction would look like if I changed my search to pull all items from the inbox regardless of read state but restricting only to itemClass IPM.Note (note the addition of the paged result)
Dim reqFindUnreadMailInInbox As FindItemType = New FindItemType With _
{.Item = New IndexedPageViewType With {.MaxEntriesReturnedSpecified = True, .MaxEntriesReturned = "100", .BasePoint = IndexBasePointType.Beginning, .Offset = 0} _
, .Traversal = ItemQueryTraversalType.Shallow _
, .ItemShape = New ItemResponseShapeType With {.BaseShape = DefaultShapeNamesType.IdOnly} _
, .ParentFolderIds = New DistinguishedFolderIdType(0) {New DistinguishedFolderIdType With {.Id = DistinguishedFolderIdNameType.inbox}} _
, .Restriction = New RestrictionType With _
{.Item = New IsEqualToType With _
{.Item = New PathToUnindexedFieldType With {.FieldURI = UnindexedFieldURIType.itemItemClass} _
, .FieldURIOrConstant = New FieldURIOrConstantType With {.Item = New ConstantValueType With {.Value = "IPM.Note"}} _
} _
} _
}
The next chunk of code checks for an error, and proceeds to enumerate the IDs and fetch the items in one call. If I debug the resGetitem after the response has returned, I can drill down and look at each items class by looking in the immediate window with this query
?directcast(directcast(resGetItem.ResponseMessages.Items(0),ItemInfoResponseMessageType).Items.Items(0),MessageType)
and I can see "REPORTS.IPM.Note.NDR". The question is how can I filter the initial call to restrict to only "IPM.Note"
'if there was an error bur out and report
If resFindFolderMessages.ResponseClass = ResponseClassType.[Error] Then
Throw New Exception(resFindFolderMessages.MessageText)
Else
TraceLog.AppendLine("Inbox found, ID pulled back")
If Not IsNothing(DirectCast(resFindFolderMessages.RootFolder.Item, ArrayOfRealItemsType).Items) Then
resFolderItems = resFindFolderMessages.RootFolder.Item
TraceLog.AppendLine(String.Format("found {0} unread mail - start processing", resFolderItems.Items.Count))
'So we have the array of ids for the emails, now fetch the emails themselves
Dim resItemIDs As ItemIdType() = Nothing
'collect the ids up
For x As Integer = 0 To resFolderItems.Items.Count - 1
If IsNothing(resItemIDs) Then ReDim resItemIDs(0) Else ReDim Preserve resItemIDs(resItemIDs.Length)
resItemIDs(x) = resFolderItems.Items(x).ItemId
Next
'go get the email messages
Dim resGetItem As GetItemResponseType = esb.GetItem(New GetItemType With { _
.ItemShape = New ItemResponseShapeType With {.BaseShape = DefaultShapeNamesType.AllProperties _
, .BodyType = BodyTypeResponseType.Text _
, .BodyTypeSpecified = True} _
, .ItemIds = resItemIDs})
'declare and fill up the message array that we are going to return
Dim resItemMessage As ItemType() = Nothing
For x As Integer = 0 To resGetItem.ResponseMessages.Items.Length - 1
If IsNothing(resItemMessage) Then ReDim resItemMessage(0) Else ReDim Preserve resItemMessage(resItemMessage.Length)
resItemMessage(x) = DirectCast(resGetItem.ResponseMessages.Items(x), ItemInfoResponseMessageType).Items.Items(0)
Next
'pass back the emails
Return resItemMessage
Else
TraceLog.AppendLine("no unread mail found closing out")
Return Nothing
End If
End If
========== UPDATE ============
With a nudge in the right direction from Glen Scales we have Success! EWS is a mine field of types and derived types.
'create the finditemtype and load the restrictions
'first only the unread messages
'secondly, only of type "IPM.Note" ie just emails
Dim reqFindUnreadMailInInbox As FindItemType = New FindItemType With _
{.Traversal = ItemQueryTraversalType.Shallow _
, .ItemShape = New ItemResponseShapeType With {.BaseShape = DefaultShapeNamesType.IdOnly} _
, .ParentFolderIds = New DistinguishedFolderIdType(0) {New DistinguishedFolderIdType With {.Id = DistinguishedFolderIdNameType.inbox}} _
, .Restriction = New RestrictionType With {.Item = New AndType With { _
.Items = New IsEqualToType() { _
New IsEqualToType With {.Item = New PathToUnindexedFieldType With { _
.FieldURI = UnindexedFieldURIType.messageIsRead} _
, .FieldURIOrConstant = New FieldURIOrConstantType With {.Item = New ConstantValueType With {.Value = "0"}} _
} _
, New IsEqualToType With {.Item = New PathToUnindexedFieldType With { _
.FieldURI = UnindexedFieldURIType.itemItemClass} _
, .FieldURIOrConstant = New FieldURIOrConstantType With {.Item = New ConstantValueType With {.Value = "IPM.Note"}} _
} _
}}}}
Thanks goes to Glen Scales!
You need to use the AndType https://msdn.microsoft.com/en-us/library/office/exchangewebservices.andtype(v=exchg.150).aspx
Then define and add two isEqual Restrictions to that eg
RestrictionType restriction = new RestrictionType();
AndType andType = new AndType();
andType.Items = new SearchExpressionType[] { IsEqual1,IsEqual2 };
restriction.Item = andType;
Cheers
Glen

Listbox in dynamic web user controls lost data after postback

I create dynamic web user control which has a list box and a textbox. However, data in the list box is lost after postback but the data in the textbox isn't.
I've read a lot of forums and pages about web user controls and I understands that web user controls recreate after such post-back.
Could you please show me the way to get data of list box before post back ?
Thank alot
'--------------------------------------
Note that: my web user control has a list and text boxes, user can add value to the list box by entering values in the text box ( I wrote functions in javascripts to add data from text box to list box) .
However, in the main page, when I click a button to save data of the list, all of my page and my web user control are reloaded, so data in the list box is also disappear :-(
Code VB for adding web user control:
Private Sub WebFormTestValidation_Init(sender As Object, e As EventArgs) Handles Me.Init
Dim ctrList As wucListPerson
ctrList = LoadControl("wucListPerson.ascx")
Me.Panel1.Controls.Add(ctrList)
ctrList.ID = "wucDynamic"
ctrList.wucName = "DYNAMIC TEST"
ctrList.wucInfo = "DYNAMIC TEST"
End Sub
'----------------------
Code VB of web user control
Public Class wucListPerson
Inherits System.Web.UI.UserControl
Public Property lstPersons As List(Of String)
Get
Dim lst As New List(Of String)
If lstFullName.Items.Count > 0 Then
For i = 0 To lstFullName.Items.Count - 1
lst.Add(CStr(lstFullName.Items(i).Value))
Next
End If
Return lst
End Get
Set(ByVal lstValues As List(Of String))
If lstValues.Count > 0 Then
For i = 0 To lstValues.Count - 1
Dim strArr As String() = Split(CStr(lstValues.Item(i)), "*")
Ordre.Text = CStr(strArr(0))
Nom.Text = strArr(1)
Prenom.Text = strArr(2)
hdfIdPersonne.Value = strArr(3)
Dim item As New System.Web.UI.WebControls.ListItem
item.Text = strArr(0) + "." + strArr(1) + " " + strArr(2)
item.Value = CStr(lstValues.Item(i))
lstFullName.Items.Add(item)
Next
End If
End Set
End Property
Public Property wucName As String
Get
Return lblName.Text
End Get
Set(ByVal value As String)
lblName.Text = value
End Set
End Property
Public Property wucInfo As String
Get
Return Info.Text
End Get
Set(ByVal value As String)
Info.Text = value
End Set
End Property
Public Sub addPersonne(ByVal ordre As Integer, ByVal nom As String, ByVal prenom As String, idpersonne As Integer)
'lstName.Items.Add(CStr(ordre) + "." + nom + " " + prenom, CStr(ordre) + "*" + nom + "*" + prenom + "*" + CStr(idpersonne))
Dim item As New System.Web.UI.WebControls.ListItem
item.Text = CStr(ordre) + "." + nom + " " + prenom
item.Value = CStr(ordre) + "*" + nom + "*" + prenom + "*" + CStr(idpersonne)
lstFullName.Items.Add(item)
End Sub
Public Function getList() As List(Of String)
Dim lst As New List(Of String)
If lstFullName.Items.Count > 0 Then
For i = 0 To lstFullName.Items.Count - 1
lst.Add(CStr(lstFullName.Items(i).Value))
Next
End If
Return lst
End Function
Public Sub SetList(ByVal lst As List(Of String))
If lst.Count > 0 Then
For i = 0 To lst.Count - 1
Dim strArr As String() = Split(CStr(lst.Item(i)), "*")
Ordre.Text = CStr(strArr(0))
Nom.Text = strArr(1)
Prenom.Text = strArr(2)
hdfIdPersonne.Value = strArr(3)
Dim item As New ListItem
item.Text = strArr(0) + "." + strArr(1) + " " + strArr(2)
item.Value = CStr(lst.Item(i))
lstFullName.Items.Add(item)
Next
End If
End Sub
Protected uniqueKey As String
Private Sub Page_Load(sender As Object, e As EventArgs) Handles Me.Load
'If Not Page.IsPostBack Then
' lblName.Text = wucName
'End If
Me.uniqueKey = Guid.NewGuid.ToString("N")
Me.cmdRight.Attributes("onclick") = ("RemoveItem_" + (uniqueKey + "(); return false;"))
Me.cmdLeft.Attributes("onclick") = ("AddItem_" + (uniqueKey + "(); return false;"))
Me.cmdInfor.Attributes("onclick") = ("showHideInfor_" + (uniqueKey + "(); return false;"))
If Trim(lblName.Text) = "" Then cmdInfor.Visible = False
End Sub
End Class
'----------------------
Code Javascript to get/ remove data from text boxes to the list
//===================
function getMaxOrdre_<%=uniqueKey%>() {
var listName = document.getElementById("<%=lstFullName.ClientID()%>");
var lst = listName.options;
var count = lst.length;
if (lst.length == 0) {
return 0;
}
var max = 0;
for (var i = 0; i < count; i++) {
var item = lst[i].value;
var FName = getFullName_<%=uniqueKey%>(item);
if (parseInt(FName.Ordre) > max) {
max = FName.Ordre;
}
}
return max;
}
//===================
function getFullName_<%=uniqueKey%>(FullName) {
if (FullName.length != "0") {
var temp = new Array();
temp = FullName.split('*');
return { Ordre: temp[0], Nom: temp[1], PreNom: temp[2], IdPersonne: temp[3] };
}
return { Ordre: 0, Nom: '', PreNom: '', IdPersonne: '0' };
}
//===================
function AddItem_<%=uniqueKey %>() {
//lstName.BeginUpdate();
var txtOrdre = document.getElementById("<%=Ordre.ClientID()%>");
var txtNom = document.getElementById("<%=Nom.ClientID()%>");
var txtPrenom = document.getElementById("<%=Prenom.ClientID()%>");
var hdfIdPerson = document.getElementById("<%=hdfIdPersonne.ClientID%>");
var listName = document.getElementById("<%=lstFullName.ClientID()%>");
var index = listName.selectedIndex;
var lst = listName.options;
var ordre = txtOrdre.value;
var nom = txtNom.value;
var prenom = txtPrenom.value;
var idPerson = hdfIdPerson.value;
if ((nom.length > 0) || (prenom.length > 0)) {
var selectBoxOption = document.createElement("option");//create new option
selectBoxOption.value = ordre + '*' + nom + '*' + prenom + '*' + idPerson;//set option value
selectBoxOption.text = ordre + '.' + nom + ' ' + prenom;//set option display text
listName.add(selectBoxOption, null);//add created option to select box.
};
// lstName.EndUpdate();
//get deafault data
var ordreMax = getMaxOrdre_<%=uniqueKey%>();
txtOrdre.value = parseInt(ordreMax) + 1;
txtNom.value = '';
txtPrenom.value = '';
hdfIdPerson.value = '0';
}
//===================
function RemoveItem_<%=uniqueKey %>() {
//lstName.BeginUpdate();
var txtOrdre = document.getElementById("<%=Ordre.ClientID()%>");
var txtNom = document.getElementById("<%=Nom.ClientID()%>");
var txtPrenom = document.getElementById("<%=Prenom.ClientID()%>");
var hdfIdPerson = document.getElementById("<%=hdfIdPersonne.ClientID%>");
var listName = document.getElementById("<%=lstFullName.ClientID()%>");
var index = listName.selectedIndex;
var lst = listName.options;
if (index >= 0) {
var FName = getFullName_<%=uniqueKey %>(lst[index].value);
txtOrdre.value = FName.Ordre;
txtNom.value = FName.Nom;
txtPrenom.value = FName.PreNom;
hdfIdPerson.value = FName.IdPersonne;
listName.remove(index);
}
}
Your problem is that you are adding the new items in the DOM, but these changes will not necessarily be reflected in your ListBox after a page refresh or PostBack. I could suggest two solutions:
1) Add the elements in the ListBox through .net instead of using Javascript.
but if you need a client side solution so that your page won't refresh everytime you add an item:
2) Add a .net HiddenField control. These controls have the advantage of being accessible easily from both Client Side and Server Side. You can add each item in both, the ListItem and the HiddenField (maybe comma separated) and on the server side you will use this HiddenField instead of your ListBox.

XElement.ReplaceWith throwing System.AccessViolationException

I'm working on an WindowsPhone 8 app that stores and reads it's data from its IsolatedStorage.
I'm using Visual Basic.NET and LINQ to XML.
There's no problem with loading/saving the data, but I've got a serious issue with replacing an XElement with [***XElementListName*].FirstOrDefault().ReplaceWith([NewXElementName])**.
It throws an System.AccessViolationException, but only if it's supposed to find and replace the data bound to the FIRST item in a LongListSelector, also the first of that element in the XML file. Editing any other item works fine thou.
Here's the code from the routine that is supposed to replace the data.
Dim Accounts = From el In XMLData.<accounts>.<account> Where _
el.Attribute("title").Value = oiTitle And _
el.Attribute("uname").Value = oiName And _
el.Attribute("pass").Value = oiPass And _
el.Attribute("site").Value = oiSite And _
el.Attribute("description").Value = oiDesc _
Select el
Dim acc As XElement = Accounts.FirstOrDefault()
If acc.Equals(Nothing) Then
MessageBox.Show("Error while saving edited account. Account not found.", "Account not found", MessageBoxButton.OK)
Exit Sub
End If
Dim tmpstr As String = acc.Attribute("title").Value + _
acc.Attribute("uname").Value + _
acc.Attribute("pass").Value + _
acc.Attribute("site").Value + _
acc.Attribute("description").Value
'Does this during debug to confirm that the replace is performed on the correct item.
MessageBox.Show(tmpstr, "Info about first item", MessageBoxButton.OK)
acc.Attribute("title").SetValue(NewInfo.Title)
acc.Attribute("uname").SetValue(NewInfo.Username)
acc.Attribute("pass").SetValue(NewInfo.Password)
acc.Attribute("site").SetValue(NewInfo.Site)
acc.Attribute("description").SetValue(NewInfo.Description)
' This code throws the exception when performing on the first item from the LongListSelector
Accounts.FirstOrDefault().ReplaceWith(acc)
I've searched and tried to figure it out by looking at the LINQ to XML documentation, but it lacks usable examples. Also checked this: How can I update/replace an element of an XElement from a string?
So, does anyone sit on any knowledge I could use to solve this?
If there's some code you'd like to see, just tell me, it's pretty ugly though.
EDIT: Omitted the Accounts.FirstOrDefault().ReplaceWith(acc) line, and it works just fine. Saves everything as it should. Also rewrote some code, here's the new one, and all the related code in that sub.
Public Sub EditAccount(ByVal OldInfo As AccountViewModel, ByVal NewInfo As AccountViewModel)
Dim IsStore As IsolatedStorageFile = IsolatedStorageFile.GetUserStoreForApplication()
Dim File As New IsolatedStorageFileStream("Data.xml", FileMode.Open, IsStore)
Dim XMLData As XElement = XElement.Load(File)
Dim oiTitle As String = OldInfo.Title
Dim oiName As String = OldInfo.Username
Dim oiPass As String = OldInfo.Password
Dim oiSite As String = OldInfo.Site
Dim oiDesc As String = OldInfo.Description
Try
Dim Accounts = From e In XMLData.<accounts>.<account> Where ( _
e.Attribute("title").Value = oiTitle And _
e.Attribute("uname").Value = oiName And _
e.Attribute("pass").Value = oiPass And _
e.Attribute("site").Value = oiSite And _
e.Attribute("description").Value = oiDesc)
Select e Take 1
Dim Account As XElement = Accounts.FirstOrDefault()
If Account.Equals(Nothing) Then
MessageBox.Show("Error while saving edited account. Account not found.", "Account not found", MessageBoxButton.OK)
Exit Sub
End If
Dim tmpstr As String = Account.Attribute("title").Value + _
Account.Attribute("uname").Value + _
Account.Attribute("pass").Value + _
Account.Attribute("site").Value + _
Account.Attribute("description").Value
'MessageBox.Show(tmpstr, "Info about first item", MessageBoxButton.OK)
Account.Attribute("title").SetValue(NewInfo.Title)
Account.Attribute("uname").SetValue(NewInfo.Username)
Account.Attribute("pass").SetValue(NewInfo.Password)
Account.Attribute("site").SetValue(NewInfo.Site)
Account.Attribute("description").SetValue(NewInfo.Description)
File.Close()
IsStore.DeleteFile("Data.xml")
File = New IsolatedStorageFileStream("Data.xml", FileMode.Create, IsStore)
XMLData.Save(File)
File.Close()
Catch ex As Exception
MessageBox.Show(ex.ToString)
End Try
Me.LoadData()
End Sub
Omitted the Accounts.FirstOrDefault().ReplaceWith(acc) line, and it works just fine. Saves everything as it should. Also rewrote some code, here's the new one, and all the related code in that sub.
Public Sub EditAccount(ByVal OldInfo As AccountViewModel, ByVal NewInfo As AccountViewModel)
Dim IsStore As IsolatedStorageFile = IsolatedStorageFile.GetUserStoreForApplication()
Dim File As New IsolatedStorageFileStream("Data.xml", FileMode.Open, IsStore)
Dim XMLData As XElement = XElement.Load(File)
Dim oiTitle As String = OldInfo.Title
Dim oiName As String = OldInfo.Username
Dim oiPass As String = OldInfo.Password
Dim oiSite As String = OldInfo.Site
Dim oiDesc As String = OldInfo.Description
Try
Dim Accounts = From e In XMLData.<accounts>.<account> Where ( _
e.Attribute("title").Value = oiTitle And _
e.Attribute("uname").Value = oiName And _
e.Attribute("pass").Value = oiPass And _
e.Attribute("site").Value = oiSite And _
e.Attribute("description").Value = oiDesc)
Select e Take 1
Dim Account As XElement = Accounts.FirstOrDefault()
If Account.Equals(Nothing) Then
MessageBox.Show("Error while saving edited account. Account not found.", "Account not found", MessageBoxButton.OK)
Exit Sub
End If
Dim tmpstr As String = Account.Attribute("title").Value + _
Account.Attribute("uname").Value + _
Account.Attribute("pass").Value + _
Account.Attribute("site").Value + _
Account.Attribute("description").Value
'MessageBox.Show(tmpstr, "Info about first item", MessageBoxButton.OK)
Account.Attribute("title").SetValue(NewInfo.Title)
Account.Attribute("uname").SetValue(NewInfo.Username)
Account.Attribute("pass").SetValue(NewInfo.Password)
Account.Attribute("site").SetValue(NewInfo.Site)
Account.Attribute("description").SetValue(NewInfo.Description)
File.Close()
IsStore.DeleteFile("Data.xml")
File = New IsolatedStorageFileStream("Data.xml", FileMode.Create, IsStore)
XMLData.Save(File)
File.Close()
Catch ex As Exception
MessageBox.Show(ex.ToString)
End Try
Me.LoadData()
End Sub

Need C# code converted to VB.NET for Silverlight "Export to CSV" [closed]

Closed. This question is off-topic. It is not currently accepting answers.
Want to improve this question? Update the question so it's on-topic for Stack Overflow.
Closed 12 years ago.
Improve this question
I'm looking to get the following code converted to working VB.NET code. I need to export data from a datagrid into the CSV format that the user can save off, and the code below from David in Dakota would work great, but it's in C#. Any help would be appreciated! This is for a Silverlight 4 site we're working on.
private void exportHistoryButton_Click(object sender, RoutedEventArgs e)
{
string data = ExportDataGrid(true, historyDataGrid);
SaveFileDialog sfd = new SaveFileDialog()
{
DefaultExt = "csv",
Filter = "CSV Files (*.csv)|*.csv|All files (*.*)|*.*",
FilterIndex = 1
};
if (sfd.ShowDialog() == true)
{
using (Stream stream = sfd.OpenFile())
{
using (StreamWriter writer = new StreamWriter(stream))
{
writer.Write(data);
writer.Close();
}
stream.Close();
}
}
}
private string FormatCSVField(string data)
{
return String.Format(
"\"{0}\"",
data.Replace("\"", "\"\"\"")
.Replace("\n", "")
.Replace("\r", "")
);
}
public string ExportDataGrid(bool withHeaders, DataGrid grid)
{
string colPath;
System.Reflection.PropertyInfo propInfo;
System.Windows.Data.Binding binding;
System.Text.StringBuilder strBuilder = new System.Text.StringBuilder();
System.Collections.IList source = (grid.ItemsSource as System.Collections.IList);
if (source == null)
return "";
List<string> headers = new List<string>();
grid.Columns.ToList().ForEach(col =>
{
if (col is DataGridBoundColumn)
{
headers.Add(FormatCSVField(col.Header.ToString()));
}
});
strBuilder
.Append(String.Join(",", headers.ToArray()))
.Append("\r\n");
foreach (Object data in source)
{
List<string> csvRow = new List<string>();
foreach (DataGridColumn col in grid.Columns)
{
if (col is DataGridBoundColumn)
{
binding = (col as DataGridBoundColumn).Binding;
colPath = binding.Path.Path;
propInfo = data.GetType().GetProperty(colPath);
if (propInfo != null)
{
csvRow.Add(FormatCSVField(propInfo.GetValue(data, null).ToString()));
}
}
}
strBuilder.Append(String.Join(",", csvRow.ToArray())).Append("\r\n");
}
return strBuilder.ToString();
}
You may try a free online conversion tool.
Here's a mostly-direct translation. I made a few improvements but left if close enough to original that you should still recognize it. But we can do a lot better, so keep reading after this initial attempt for something better:
Private Sub exportHistoryButton_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
Dim sfd As New SaveFileDialog()
sfd.DefaultExt = "csv"
sfd.Filter = "CSV Files (*.csv)|*.csv|All files (*.*)|*.*"
sfd.FilterIndex = 1
If sfd.ShowDialog() Then
Using writer As New StreamWriter(sfd.OpenFile())
writer.Write(ExportDataGrid(True, historyDataGrid))
End Using
End If
End Sub
Private Function FormatCSVField(ByVal data As String) As String
Return String.Format("""{0}""", _
data.Replace("""", """""").Replace(vbLf, "").Replace(vbCr, ""))
End Function
Public Function ExportDataGrid(ByVal withHeaders As Bool, ByVal grid As DataGrid) As String
Dim source As System.Collections.IList = TryCast(grid.ItemsSource, System.Collections.IList)
If source Is Nothing Then Return ""
Dim builder As New System.Text.StringBuilder()
If withHeaders Then
Dim headers As new List(Of String)()
For Each col As DataColumn In grid.Columns.Where(Function(c) TypeOf c is DataGridBoundColumn)
headers.Add(FormatCSVField(col.Header.ToString()))
Next col
builder.Append(String.Join(",", headers.ToArray())).Append(vbCrLf)
End If
For Each row in source
Dim csvRow As New List(Of String)()
For Each col As DataGridBoundColumn in grid.Columns.Where(Function(c) TypeOf col Is DataGridBoundColumn)
Dim propInfo As System.Reflection.PropertyInfo = _
row.GetType().GetProperty(col.Binding.Path.Path)
If propInfo IsNot Nothing Then
csvRow.Add(FormatCSVField(propInfo.GetValue(row, Nothing).ToString()))
End If
Next col
builder.Append(String.Join(",", csvRow.ToArray())).Append(vbCrLf)
Next row
Return builder.ToString()
End Function
The big problem with this code is that when you put your entire grid into a single string variable, you create an object that will very likely end up on the Large Object Heap. This is a "Bad Thing"™. One of the things that makes it so bad is that it often doesn't look bad in your performance testing. It's the kind of problem that won't show up until production. But trust me when I say we can do better.
If this were still going to be C# I'd refactor it to use an iterator block to yield return the string for one row at a time, and then write that out. Since it's VB, we'll refactor it to accept a TextWriter and write directly to that:
Private Sub exportHistoryButton_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
Dim sfd As New SaveFileDialog()
sfd.DefaultExt = "csv"
sfd.Filter = "CSV Files (*.csv)|*.csv|All files (*.*)|*.*"
sfd.FilterIndex = 1
If sfd.ShowDialog() Then
Using writer As New StreamWriter(sfd.OpenFile())
ExportDataGrid(historyDataGrid, writer) ' Notice the change here
End Using
End If
End Sub
Private Function WriteCSVField(ByVal data As String, ByVal writer As TextWriter) As String
' This would likely do a _lot_ better with a state machine to iterate over
' each character rather than create 3 new strings for every field,
' but we'll let it slide for now
writer.Write(""""c)
writer.Write(data.Replace("""", """""").Replace(vbLf, "").Replace(vbCr, ""))
writer.Write(""""c)
End Function
' Notice the new function signature
Public Sub ExportDataGrid(ByVal grid As DataGrid, ByVal writer As TextWriter, Optional ByVal WithHeaders As Boolean = True)
Dim source As System.Collections.IList = TryCast(grid.ItemsSource, System.Collections.IList)
If source Is Nothing Then Return ""
Dim delimiter As String
If WithHeaders Then
delimiter = ""
For Each col As DataColumn In grid.Columns.Where(Function(c) TypeOf c is DataGridBoundColumn)
writer.Write(delimiter)
WriteCSVField(col.Header.ToString(), writer)
delimiter = ","
Next col
writer.Write(vbCrLf)
End If
For Each row In source
delimiter = ""
For Each col As DataGridBoundColumn in grid.Columns.Where(Function(c) TypeOf col Is DataGridBoundColumn)
writer.Write(delimiter)
delimiter = ","
' I'm pretty sure this could be refactored to avoid the reflection,
' But I also think there's a bug in your code here, so I'll
' leave the direct translation for now
Dim propInfo As System.Reflection.PropertyInfo = _
row.GetType().GetProperty(col.Binding.Path.Path)
If propInfo IsNot Nothing Then
WriteCSVField(propInfo.GetValue(row, Nothing).ToString(), writer)
End If
Next col
writer.Write(vbCrLf)
Next row
End Sub
Of course, the best option of all here is to write no new code at all for a problem that's already been solved by thousands of other programmers. You can just go get an existing library that turn this whole mess into two or lines calling into that API.
This isn't a question, it's a request. But try this:
http://www.developerfusion.com/tools/convert/csharp-to-vb/
Private Sub exportHistoryButton_Click(sender As Object, e As RoutedEventArgs)
Dim data As String = ExportDataGrid(True, historyDataGrid)
Dim sfd As New SaveFileDialog() With { _
.DefaultExt = "csv", _
.Filter = "CSV Files (.csv)|.csv|All files (.)|.", _
.FilterIndex = 1 _
}
If sfd.ShowDialog() = True Then
Using stream As Stream = sfd.OpenFile()
Using writer As New StreamWriter(stream)
writer.Write(data)
writer.Close()
End Using
stream.Close()
End Using
End If
End Sub
Private Function FormatCSVField(data As String) As String
Return [String].Format("""{0}""", data.Replace("""", """""""").Replace(vbLf, "").Replace(vbCr, ""))
End Function
Public Function ExportDataGrid(withHeaders As Boolean, grid As DataGrid) As String
Dim colPath As String
Dim propInfo As System.Reflection.PropertyInfo
Dim binding As System.Windows.Data.Binding
Dim strBuilder As New System.Text.StringBuilder()
Dim source As System.Collections.IList = TryCast(grid.ItemsSource, System.Collections.IList)
If source Is Nothing Then
Return ""
End If
Dim headers As New List(Of String)()
grid.Columns.ToList().ForEach(Function(col) Do
If TypeOf col Is DataGridBoundColumn Then
headers.Add(FormatCSVField(col.Header.ToString()))
End If
End Function)
strBuilder.Append([String].Join(",", headers.ToArray())).Append(vbCr & vbLf)
For Each data As [Object] In source
Dim csvRow As New List(Of String)()
For Each col As DataGridColumn In grid.Columns
If TypeOf col Is DataGridBoundColumn Then
binding = TryCast(col, DataGridBoundColumn).Binding
colPath = binding.Path.Path
propInfo = data.[GetType]().GetProperty(colPath)
If propInfo IsNot Nothing Then
csvRow.Add(FormatCSVField(propInfo.GetValue(data, Nothing).ToString()))
End If
End If
Next
strBuilder.Append([String].Join(",", csvRow.ToArray())).Append(vbCr & vbLf)
Next
Return strBuilder.ToString()
End Function