So, I am developing an application which is able to drag and drop files into the form and display the information of it into a datagridview. Basically I already got something developed in VB.Net and now I want to upgrade it to C# and make somethings better adding features.
I am stuck at the moment because in VB.Net I have this peace of code
Private MeuFicheiro As FileInfo
Private Sub frmMenu_DragDrop(sender As Object, e As DragEventArgs) Handles cmdEntrar.DragDrop
Dim file As String = e.Data.GetData(DataFormats.FileDrop)(0)
MyFile = New FileInfo(ficheiro)
If String.IsNullOrWhiteSpace(MyFile.Extension) Then
Exit Sub
End If
End Sub
And I trying to use the Dim file As String = e.Data.GetData(DataFormats.FileDrop)(0) C#, but making some changes of course like this:
string file = e.Data.GetData(DataFormats.FileDrop)(0); in the form method:
private void frmMenu_DragDrop(object sender, DragEventArgs e)
{
string ficheiro = e.Data.GetData(DataFormats.FileDrop)(0);
MeuFicheiro = new FileInfo(ficheiro);
if (string.IsNullOrWhiteSpace(MeuFicheiro.Extension))
{
return;
}
}
But it gives me an error in the e.Data.GetData(DataFormats.FileDrop)(0) called Method name
Method name expected
So do you guys have something to help me solving this error?
change from parenthesis to square brackets. In C# square brackets are used for indexing arrays.
Do this:
string file = e.Data.GetData(DataFormats.FileDrop)[0]; // see square brackets
If GetData returns IList then change e.Data.GetData(DataFormats.FileDrop)(0) to e.Data.GetData(DataFormats.FileDrop)[0]
There are actually two errors on your code:
First, DataObject.GetData returns an Object instance. You will first need to cast that object to the type you are expecting to be stored on that Drag event.
Then, assuming that the returing type was indeed a collection of Strings, you need to use square brackets ([]) to access the first item.
var collection = e.Data.GetData(DataFormats.FileDrop) as IList<string>;
string ficheiro = collection[0];
Note that I casted to IList<string>, as that will cover most of C#'s indexable generic collections (array, list, hashSet...).
In the other hand, if that object GetData returns is a string, you should do:
string ficheiro = e.Data.GetData(DataFormats.FileDrop).ToString();
Related
at line 161,I want to insert my text in parameter t,but it won't change when i debug it.although the parameter tmp had alredy changed.
I want to change this Text in UI,when my parameter t changes.
With respect to your specific issue, Insert is defined as:
public string Insert (int startIndex, string value);
and returns a new string. In C#, strings aren't modified, new strings are created. In this way, they act like a value type, even though they're a reference type. In other words, once a string is created, it is never modified - it's 'immutable'. So, you need to store your newly created string.
In cases like this, I like to use the string interpolation, as it allows me to get a slightly clearer representation of what the final string will look like.
var tmp = System.Text.Encoding.UTF8.GetString ( e.Message );
t.text = $"{tmp}\n{t.text}"; // Note that a newline is represented as \n
Or, if you add the System.Text namespace; you could reduce it down to:
using System.Text;
...
t.text = $"{Encoding.UTF8.GetString ( e.Message )}\n{t.text}";
The string type in c# is immutable, therefore Insert returns a new string instead of modifying the current one.
Do:
t = t.text.Insert(0, tmp + "//n");
See also
How to modify string contents in C#
Similarly to passing a list through a function and adding elements to it, I want to pass a string and add characters to it. However, I do not want to change the reference.
Func(List myList) {
myList.Append("hello");
}
Func(List myList) {
myList = new List();
}
It's like the distinction between the two functions above. In one case you're adding an element to an existing reference to an object, in the other case you are changing the object that is referenced to.
With strings, I have noticed you always(?) change the object that is referenced to. Every solution i've found takes two or more strings, adds them together and returns a new string.
Is there a way to use the same string instance and add one or more characters to this specific instance?
With strings, I have noticed you always(?) change the object that is referenced to.
Because strings are immutable. You can't change a string in .NET. That opens the door to many optimizations (such as string interning), but also has performance issues when you want to build a long string by parts - many allocations and copyings of memory (to concatenate two strings, you have to allocate a third in the length of the two together, then copy them).
So Microsoft created System.Text.StringBuilder. The idea is to create mutable string. The basic methods are Append() (which appends some data, often primitive types) and AppendFormat() (similar to string.Format()). Then you get a normal string by calling to ToString():
void Func(StringBuilder s)
{
s.Append("Hi everyone!");
}
var s = new StringBuilder();
s.Append("a StringBuilder.");
Func(s);
s.ToString(); // "a StringBuilder.Hi everyone!"
Is there a way to use the same string instance and add one or more
characters to this specific instance?
No, but you can do it by using StringBuilder. Pass instance of StringBuilder to a function and append any string to it, it will add string but will refer to same instance of StringBuilder class
public void AppendString(StringBuilder sb) {
sb.Append("hello");
}
This is because string type is mutable, whenever you assign new value to string it creates new string object in memory, but StringBuilder is immutable, it is reference type. StringBuilder modifies without creating new object.
You can try below code,
public static void Main()
{
StringBuilder sb = new StringBuilder("Default Text");
Console.WriteLine($"Before function call: {sb.ToString()}");
AppendString(sb); //Function call
Console.WriteLine($"After function call: {sb.ToString()}");
}
public static void AppendString(StringBuilder sb)
{
sb.Append(" Hello world");
Console.WriteLine($"Inside function: {sb.ToString()}");
}
Output:
Before function call: Default Text
Inside function: Default Text Hello world
After function call: Default Text Hello world
.Net fiddle
I would suggest you to read string vs StringBuilder
You can achieve this by passing string parameter as reference. Please refer to the following code snippet.
static void Main(string[] args)
{
string input = "input";
AddString(ref input);
System.Console.WriteLine(input);
}
private static void AddString(ref string input)
{
input += "_edited";
}
You will need to use ref keyword in both the cases while defining and passing method parameter. Hope it helps.
I am trying to read a string into an array and I get the error "Cannot implecitly convert type 'string' to 'string[]'.
The error occurs here:
string[] sepText = result.Tables[0].Rows[0].Field<string>("WebHTML").UrlDecode();
My full if else statement is below:
if (!string.IsNullOrEmpty(result.Tables[0].Rows[0].Field<string>("WebHTML")))
{
string[] sepText = result.Tables[0].Rows[0].Field<string>("WebHTML").UrlDecode();
NewsContent.Text = sepText[1];
if (!string.IsNullOrEmpty(sepText[0]))
Image1.ImageUrl = sepText[0];
else
Image1.Visible = false;
NewsTitle.Text = String.Format("{3}", Extensions.GetServerName(true), result.Tables[0].Rows[0].Field<int>("News_Item_ID"), result.Tables[0].Rows[0].Field<string>("Title").UrlFormat(), result.Tables[0].Rows[0].Field<string>("Title"));
Hyperlink1.NavigateUrl = String.Format("{0}/news/{1}/{2}.aspx", Extensions.GetServerName(true), result.Tables[0].Rows[0].Field<int>("News_Item_ID"), result.Tables[0].Rows[0].Field<string>("Title").UrlFormat());
}
else
{
Hyperlink1.Visible = false;
Image1.Visible = false;
}
Thank you for your help!
EDIT Code for URL Decode:
public static string UrlDecode(this string str)
{
return System.Web.HttpUtility.UrlDecode(str);
}
result.Tables[0].Rows[0].Field<string>("WebHTML") is going to give you the value of the WebHTML field in the first row in the first table which is a single string rather than a string[].
You may want to show your code for UrlDecode() since it looks like a custom implementation rather than one of the built-in framework versions.
You also declare the UrlDecode method to take a string as a parameter and return a string. Remember, a string is not the same thing as a string array.
It seems that you are trying to put:
result.Tables[0].Rows[0].Field<string>("WebHTML").UrlDecode();
which returns a string, into an array of strings.
Simply delare your sepText variable as a string rather than a string array and you should be good to go, e.g.:
string sepText = result.Tables[0].Rows[0].Field<string>("WebHTML").UrlDecode();
Later in your code you will clearly need to read the contents of the string like this:
Image1.ImageUrl =sepText;
Assuming the UrlDecode you are using is the one from here then the result is a string and not a string[] !
UrlDecode returns a string and you are assigning it to an array.
If you want the parts you will have to use the string to create an Url object.
Url url = new Url(result.Tables[0].Rows[0].Field<string>("WebHTML"));
and then get the parts.
See: Get url parts without host
I don't think URLDecode works the way you think it works. All URLDecode does is remove URL encoding from a string. It does not return an array of strings - only the decoded value of the string you gave it.
http://msdn.microsoft.com/en-us/library/system.web.httputility.urldecode.aspx
Example: Your web browser replaces a space with %20. This changes the %20 back to a space.
That's because the result of this line is "string" and you're trying to assign it to an array since UrlDecode do not produce an array. What you probably wanted is to use a method split() to create an array of separators?
I have the code below.
The line string content = twitterMsg.text; is creating the error 'Use of unassigned local variable' for twitterMsg. I don't seem able to access my TwitterSearchResponse.results.text fields in my DataContractJsonSerializer<TwitterMain> collection.
TwitterSearchResponse.results is an array (set of object properties) with several string fields attached with names like text and user_info.
Can anyone help with this??
Updated code below. I am still highly confused about why I am not able to iterate over my TwitterSearchResponse.results properly and assign content = twitterMsg.text
For what it's worth, here is my DataContractJsonSerializer method:
String url = String.Format("http://search.twitter.com/search.json?q={0}&rpp=20", Server.UrlEncode(txtSearchFor.Text));
// parse the JSON data
using (MemoryStream ms = new MemoryStream(wc.DownloadData(url)))
{
DataContractJsonSerializer jsonSerializer =
new DataContractJsonSerializer(typeof(TwitterMain));
TwitterSearchResponse = jsonSerializer.ReadObject(ms) as TwitterMain; // read as JSON and map as TwitterOut
}
And here is the original posted code where the issue lies.
public List<MatchCollection> returnMatches(DataContractJsonSerializer<TwitterMain> TwitterSearchResponse)
{
List<MatchCollection> messageLinks = new List<MatchCollection>();
foreach (TwitterResult twitterMsg in TwitterSearchResponse.results)
{
string content = twitterMsg.text;
// capture internet protocol pre-fixed words from message
string pattern = #"...";
messageLinks.Add(Regex.Matches(content, pattern, RegexOptions.IgnoreCase));
// capture #username twitter users from message
string atUsernamePattern = #"#([a-zA-Z0-9-_]+)";
MatchCollection PeopleMatches = Regex.Matches(content, atUsernamePattern, RegexOptions.IgnoreCase);
}
return messageLinks;
}
I suspect it's actually reporting the use of the unassigned local variable MessageLinks. Your use of twitterMsg looks fine.
So, the big question is: what do you want to return if there aren't any results? If you're happy returning null, just assign the value when you declare MessageLinks.
Next question: do you really only want to return the last MatchCollection you find? That's what the current behaviour is: you're looping over all the variables, setting the same local variable each time (i.e. replacing the previous value) and then returning that last value.
Final question: any reason why you've got a camel-cased method name (returnMatches), a Pascal-cased local variable (MessageLinks), a Pascal-cased parameter name (TwitterSearchResponse) and a camel-cased property (text)? I would assume that text is due to it coming from JSON that way - but it's a good idea to follow normal .NET naming conventions otherwise.
So, let's say I have this code (VB.Net):
Sub Main()
dim xxx as string = "HELLO WORLD"
DetectName(xxx)
End Sub
Public Sub (theVariable as string)
dim output as string = "The Value: {0} was stored in the variable named: {1}."
debug.writeline(string.format(output, theVariable, What Goes Here????))
End Sub
Te output I want to see is:
The Value: HELLO WORLD was stored in the variable named: xxx.
Is this somehow possible, through reflection possibly?? (And if you definitively know it isn't possible, thats useful to know also).
In case you are wondering why I want to do this...I am trying to find some decent way to write a custom binding class (for forms, not grids) for asp.net because I can't seem to find anything that works well enough to be worth the trouble of using it. (NOTE: I am working with webforms and cannot use MVC to solve this problem).
I'm thinking my convention for supplying the binding information will be something like:
asp:TextBox id="myClassInstanceName.myPropertyName" ...
So, then I can have a function like so:
Public Sub Bind(webForm as System.Web.UI.Page, bindingObjects as HashTable)
For each ctl in webForm.flattenedControls that contains "." within ID
' Here, which property is set would actually depends on control type
' magicGetValue() would find the property class instance within bindingObjects, which is indexed by variable *NAME* (not type), and then return the proper property value via reflection
ctl.Text = magicGetValue(ctl.ID, bindingObjects)
End Sub
End Sub
Personally, I think this is a much easier syntax and much more powerful than the recommended asp:FormView, Bind("") approach. For example:
- if I want to implement the ability to render as read only, its quite a simple change in my underlying Bind function.
- if I want to have more than one class used to populate the UI, I can
- if I want to traverse a rich domain model, I can, ie:
asp:TextBox id="_Customer.Address.State"
What I don't like is:
- relies upon reflection
- loosely typed (no compile time checking)
- I'd rather store the binding information somewhere other than ID, but don't know where else it could go within the aspx definition. Moving the binding declaration to the code behind would be better in some ways, but worse in others.
If anyone has any insight or advice, I'd be very grateful!
It will definitely not work the way you want it, as local variable names are not even included in the assembly after it is compiled.
It might be possible if the variable is a field of a class (by passing a FieldInfo instead of the actual value or when the variable is passed ByRef).
You can't detect a variable's name directly, but you can workaround this by wrapping it in an anonymous type when passing it to the function.
You can then interrogate the anonymous type using reflection. The names of the type's properties will match the names of the original variables, thanks to name inferencing.
Sub Main()
Dim xxx As String = "HELLO WORLD"
Dim yyy As Integer = 42
Dim zzz As DateTime = DateTime.Now
DetectName(New With { xxx })
DetectName(New With { yyy })
DetectName(New With { zzz })
' or...
' DetectName(New With { xxx, yyy, zzz })
End Sub
Public Sub DetectName(Of T As Class)(test As T)
Dim piArray As PropertyInfo() = GetType(T).GetProperties()
Dim pi As PropertyInfo
For Each pi In piArray
Dim name As String = pi.Name
Dim value As Object = pi.GetValue(test, Nothing)
Dim output As String = _
"The Value: {0} was stored in the variable named: {1}."
Debug.WriteLine(String.Format(output, value, name))
Next
End Sub
And, for completeness, here's the C# version:
void Main()
{
string xxx = "HELLO WORLD";
int yyy = 42;
DateTime zzz = DateTime.Now;
DetectName(new { xxx });
DetectName(new { yyy });
DetectName(new { zzz });
// or..
// DetectName(new { xxx, yyy, zzz });
}
public void DetectName<T>(T test) where T : class
{
PropertyInfo[] piArray = typeof(T).GetProperties();
foreach (PropertyInfo pi in piArray)
{
string name = pi.Name;
object value = pi.GetValue(test, null);
string output = "The Value: {0} was stored in the variable named: {1}.";
Debug.WriteLine(string.Format(output, value, name));
}
}
If I'm understanding what you're asking about, you shouldn't need to do what you're describing in the first part in order to accomplish what you say you're trying to do in the second part of your question. Since you can access the ID string of the textbox that gets created, you should be able to get the Property you're looking for by reflection:
PropertyDescriptor keyDescriptor = TypeDescriptor.GetProperties(dataItem).Find(keyPropertyName, false);
Key = keyDescriptor.GetValue(dataItem);
If you don't think this will work, can you clarify your question some more?
I agree with mihi, though, that you cannot discover the name of a variable that is local to the scope of a method.