Learning C#



  • I starting to learn C# (figured it'll be easier writing UWP apps in that then in C++)

    Couple questions...

    Assume some C++ like

    vector<int> someInts;
    ...
    map<int, int> counts;
    for (auto iter = someInt.begin(); iter != someInts.end(); ++iter) {
        ++counts[*iter];
    }
    

    I want to do the same in C# - currently I'm using a SortedDictionary<int, int>. But ++ causes an exception. (So does +=) Reading the docs, it'll create the create entry on set but throw on get if it doesn't exist. Problem is ++ and += both get then set. Is there any way to get the C# version to work the same as C++? (My actual use case involves parsing, so I'd rather not run a first pass to init) Currently I'm catching the exception and doing the equivalent of counts[*iter] = 1

    Another question - I want to restrict input in a textbox. Using KeyDown won't work - my valid input is "0123456789()". Googling says capture TextChanging and change the text. A sample I found does

    if (!Regex.IsMatch(sender.Text, (@"^[\(\)\d]*?[\(\)\d]*$")))
    {
        int pos = sender.SelectionStart - 1;
        sender.Text = sender.Text.Remove(pos, 1);
        sender.SelectionStart = pos;
    }
    

    But I've found the input cursor sometimes jumps backwards.
    Inputting "12sd34" will end up with 1243. If I type the 'sd' really slowly, it's ok. But typing at normal speed means the 3 will be appended, then the cursor moves, and 4 ends up as you see. Needless to say, that's annoying!

    Still fighting XAML a bit, but managing. Well, once I found out trying to use the mouse on a hiDPI monitor a selecting an item from a drop list (like the zoom factor - or any xaml object properties) simply DOESN'T WORK! It'll drop the list it'll select. And ... nothing. Moving back to the 100% screen and all works. (vs2017)


  • FoxDev

    @dcon For the first case, you can do it in one line using LINQ:

    // Assume `ints` is int[]
    ints = ints.Select(i => i++).ToArray();
    

    The beauty of that is it'll work on anything that implements IEnumerable, which includes arrays and all collection types.

    As for the second, you're better off responding to the LostFocus event instead of TextChanging. Also, I think Regex has a Replace method, so you could use that instead of messing around with selections.


  • FoxDev

    @dcon said in Learning C#:

    Still fighting XAML a bit, but managing. Well, once I found out trying to use the mouse on a hiDPI monitor a selecting an item from a drop list (like the zoom factor - or any xaml object properties) simply DOESN'T WORK! It'll drop the list it'll select. And ... nothing. Moving back to the 100% screen and all works. (vs2017)

    Is the project configured properly for HDPI support?



  • @RaceProUK said in Learning C#:

    For the first case, you can do it in one line using LINQ:

    I think he only wants to increment certain ones.

    @dcon said in Learning C#:

    I want to do the same in C# - currently I'm using a SortedDictionary<int, int>. But ++ causes an exception. (So does +=) Reading the docs, it'll create the create entry on set but throw on get if it doesn't exist. Problem is ++ and += both get then set. Is there any way to get the C# version to work the same as C++? (My actual use case involves parsing, so I'd rather not run a first pass to init) Currently I'm catching the exception and doing the equivalent of counts[*iter] = 1

    
    var someInts = new List<int>();
    var counts = new SortedDictionary<int,int>();
    
    ....
    
    ....
    
    // merge where if counts contains a value at the key, it uses that. For the rest of the values in someInts, it initializes the dictionary entry to 0.
    counts = new SortedDictionary<int,int>(counts.Keys.Union(someInts).ToDictionary(k => k, k => counts.ContainsKey(k) ? counts[k] : 0));
    foreach (var value in someInts)
    {
        ++counts[value];
    }
    


  • @RaceProUK said in Learning C#:

    @dcon said in Learning C#:

    Still fighting XAML a bit, but managing. Well, once I found out trying to use the mouse on a hiDPI monitor a selecting an item from a drop list (like the zoom factor - or any xaml object properties) simply DOESN'T WORK! It'll drop the list it'll select. And ... nothing. Moving back to the 100% screen and all works. (vs2017)

    Is the project configured properly for HDPI support?

    It's the XAML editor in VS that's the issue. It makes using the mouse to select an item in a droplist impossible. It's not the project.



  • @RaceProUK said in Learning C#:

    For the first case, you can do it in one line using LINQ:

    Except I don't really have a list/vector. I was using that just as an example source. The data is actually extracted by parsing a string. ("12(43)31" -> x[1]==2,x[2]==1,x[3]==1,x[43]==1) In std::map, the map can actually be modified by reading it. In C#, it can't. I was hoping for some type of pattern that could.

    @RaceProUK said in Learning C#:

    As for the second, you're better off responding to the LostFocus event

    Except that I want to update the digit counts as the user types. So it's not really validation I'm doing - it's input filtering.



  • @RaceProUK said in Learning C#:

    Also, I think Regex has a Replace method, so you could use that instead of messing around with selections.

    I tried to play with that, but my regex is elementary. The one I have matches what I want. For Replace, I need the inverse.



  • @dcon said in Learning C#:

    the map can actually be modified by reading it

    The code I posted worked. It incremented every key in the someInts.



  • @dcon TBH, I never do XAML except by hand. I've heard the UWP designer is better, but even so, I don't trust it.



  • @dcon said in Learning C#:

    vector<int> someInts;
    ...
    map<int, int> counts;
    for (auto iter = someInt.begin(); iter != someInts.end(); ++iter) {
        ++counts[*iter];
    }
    
    IEnumerable<int> someInts;
    ...
    var counts = new Dictionary<int, int>();
    foreach (var iter in someInts)
    {
        int count = 0;
        counts.TryGetValue(iter, out count);
        count++;
        counts[iter] = count;
    }
    


  • @ben_lubar said in Learning C#:

    @dcon said in Learning C#:

    vector<int> someInts;
    ...
    map<int, int> counts;
    for (auto iter = someInt.begin(); iter != someInts.end(); ++iter) {
        ++counts[*iter];
    }
    
    IEnumerable<int> someInts;
    ...
    var counts = new Dictionary<int, int>();
    foreach (var iter in someInts)
    {
        int count = 0;
        counts.TryGetValue(iter, out count);
        count++;
        counts[iter] = count;
    }
    

    For the record, in Go it's

    counts := make(map[int]int)
    for _, i := range someInts {
        counts[i]++
    }
    


  • @dcon Regarding second question, tweaking the example in:

    "should" work with KeyDown events, for some untested values of "should".



  • @dcon said in Learning C#:

    Another question - I want to restrict input in a textbox. Using KeyDown won't work - my valid input is "0123456789()". Googling says capture TextChanging and change the text. A sample I found does

    It's a long time since I did this sort of stuff, but I remember listening for the KeyUp event and if the key released was in the bad group simply changing it to the backspace key.



  • @Magus said in Learning C#:

    TBH, I never do XAML except by hand. I've heard the UWP designer is better, but even so, I don't trust it.

    I've been going thru Bob Tabor's Win10 dev for beginners series and am finding I'm usually handcoding too. I'm only in the properties stuff when I'm not sure what's available. Or my brain shuts off and I forget what bottom is in "0,10,21,43"!



  • @MathNerdCNU said in Learning C#:

    @dcon Regarding second question, tweaking the example in:

    "should" work with KeyDown events, for some untested values of "should".

    Um, no. '(' is not a keydown. On a US keyboard, that's a number9 down (plus a preceding shift). The KeyPress that page mentions would be perfect - that that no longer appears to be an event in UWP.


  • kills Dumbledore

    I've only done this in Winforms, not the newer frameworks, but isn't there OnTextChanging for before the value is actually updated and OnTextChanged for after? So you'd want to intercept Changing and remove any unwanted characters?

    The trouble with the OnKeyDown/Up handlers is that you have to handle pasting as well, without forgetting shift + ins as well as ctrl + v, and handle right click, paste etc. Text changing is what you're actually looking for so those should be the events you handle



  • @coldandtired said in Learning C#:

    but I remember listening for the KeyUp event and if the key released was in the bad group simply changing it to the backspace key.

    If I cared about physical keys, that would work. One of the characters I want is created by: keydown(shift), keydown(9), keyup(9), keyup(shift) (the last 2 could be in opposite order)

    (I am hooking keydown as the enter key does something special too)



  • @Jaloopa said in Learning C#:

    I've only done this in Winforms, not the newer frameworks, but isn't there OnTextChanging for before the value is actually updated and OnTextChanged for after? So you'd want to intercept Changing and remove any unwanted characters?

    That's what I'm currently doing. But I end up in a weird state where sometimes the cursor jumps backwards one letter (only at the end of the string)


  • kills Dumbledore

    @dcon I think the keydown handlers let you check for shift,ctrl etc. being active as well (your way wouldn't work with sticky keys), but doing that would still tie you to a particular set of keyboard layouts, and since it's universal there's technically mobile or at least all in one's with soft keyboards to account for too


  • kills Dumbledore

    @dcon looking at the sample, it's probably a race condition where it's still running the previous replace/move when you've already typed the next character. That also doesn't account for pasting in multiple characters, although it seems to be trying to handle adding characters added in the middle of the string.

    I'd try something simpler that just removes all invalid characters and doesn't try to mess with the cursor position. Probably a regex replace but the specific regex is beyond what I can come up with off the top of my head.



  • BTW, for some context - I'm "translating" a C++ program of mine. This is a simple program designed to help in scoring dog agility runs. One of the runs is called Gamblers - we can run any path we want - each obstacle is worth points. The program works best on a computer with a number pad - I can just rest my hand there and type the numbers by touch while looking at the scribe sheet with the dog's path. The program adds all the numbers and presents a summary (how many of each obstacle, total points). Then I hit enter to clear everything and start over. Our trials will typically have up to 60 dogs in one event.



  • @Jaloopa said in Learning C#:

    @dcon looking at the sample, it's probably a race condition where it's still running the previous replace/move when you've already typed the next character. That also doesn't account for pasting in multiple characters, although it seems to be trying to handle adding characters added in the middle of the string.

    That's what I was thinking... I was rather surprised how long I had to wait while typing - about a full second. (BTW, I'm not worried about pasting in this particular case - this is a dumb helper program, not Enterprise Ready!)

    I'd try something simpler that just removes all invalid characters and doesn't try to mess with the cursor position. Probably a regex replace but the specific regex is beyond what I can come up with off the top of my head.

    Beyond the top or bottom of my head!



  • I'm not 100% sure if this is what the C++ code's supposed to do, but if you're counting the number of occurances of each integer in the list, you'd do something like this in C#:

    static void Main(string[] args)
    {
    	var blah = new List<int> { 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 8, 2, 5, 2, 8, 2, 5, 9, 0, };
    
    	var plop = blah.Distinct()
    			.Select(y => new { digit = y, count = blah.Count(z => z == y) })
    			.OrderBy(x => x.digit);
    }
    

    It could probably be simplified a bit, I'm not LINQ super-mega-expert. But it looks a hell of a lot nicer than looping. (It also creates a nice anonymous type there for you with the digit and count labeled.)

    And of course, the nice thing as someone above said is if you change your types in the source list, the LINQ keeps working like a champ. As long as whatever your type is supports .Equals(), and whatever your collection is implements IEnumerable.

    It is admittedly slower than the naive looping version, so if your reaction time is, say, 50 nanoseconds or faster maybe consider optimizing.



  • @dcon I think its the same order as HTML, left top right bottom (The first is left, then it goes clockwise).

    But yeah, certainly not intuitive. I imagine you can split the margin and set it as XML or something, and then get better intellisense; most things in XAML don't care if they're an attribute or an element.



  • @dcon MSDN still shows KeyDownEvent on UIElement and I did a quick blank VS 2015 UWP, TextBox still has the KeyDown event.



  • @dcon I remember the good old days when all we had was WinForms... which has a MaskedTextBox specifically to control the types of things you could input.



  • @MathNerdCNU said in Learning C#:

    MSDN still shows KeyDownEvent on UIElement and I did a quick blank VS 2015 UWP, TextBox still has the KeyDown event.

    Yes, KeyDown. It's KeyPress that's now missing.



  • I'd suggest hooking into the OnTextChanging event and replacing the contents of control.Text with the sanitised version, leaving selection and cursor positions alone.

    Also see:



  • One could also try subscribing to the KeyDown event and then simply setting the event's handled property to true.

    private void TextBox_KeyDown(object sender, KeyPressEventArgs e) {
         if(unwanted_character) 
              e.handled = true;
    }
    

  • 🚽 Regular

    @Magus said in Learning C#:

    I think its the same order as HTML, left top right bottom

    I think you're havingTRouBLe remembering HTML's order.



  • @Zecc Ah. But I think it may be the correct order in XAML.


  • Winner of the 2016 Presidential Election

    @Magus said in Learning C#:

    @Zecc Ah. But I think it may be the correct order in XAML.

    Microsoft says:

    each value describing a distinct margin to apply to the left, top, right, and bottom (in that order).



  • @Dreikin That is the order I said. I was just wrong about it being the same one as HTML


  • Winner of the 2016 Presidential Election

    @Magus said in Learning C#:

    @Dreikin That is the order I said. I was just wrong about it being the same one as HTML

    Yes, I wasn't correcting you, just providing an authoritative source.


  • Dupa

    @ben_lubar said in Learning C#:

    @ben_lubar said in Learning C#:

    @dcon said in Learning C#:

    vector<int> someInts;
    ...
    map<int, int> counts;
    for (auto iter = someInt.begin(); iter != someInts.end(); ++iter) {
        ++counts[*iter];
    }
    
    IEnumerable<int> someInts;
    ...
    var counts = new Dictionary<int, int>();
    foreach (var iter in someInts)
    {
        int count = 0;
        counts.TryGetValue(iter, out count);
        count++;
        counts[iter] = count;
    }
    

    For the record, in Go it's

    counts := make(map[int]int)
    for _, i := range someInts {
        counts[i]++
    }
    

    For the record, of you used LINQ it would be a one liner.


  • Trolleybus Mechanic

    @blakeyrat said in Learning C#:

    I'm not 100% sure if this is what the C++ code's supposed to do, but if you're counting the number of occurances of each integer in the list, you'd do something like this in C#:

    static void Main(string[] args)
    {
    	var blah = new List<int> { 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 8, 2, 5, 2, 8, 2, 5, 9, 0, };
    
    	var plop = blah.Distinct()
    			.Select(y => new { digit = y, count = blah.Count(z => z == y) })
    			.OrderBy(x => x.digit);
    }
    

    It could probably be simplified a bit, I'm not LINQ super-mega-expert. But it looks a hell of a lot nicer than looping. (It also creates a nice anonymous type there for you with the digit and count labeled.)

    And of course, the nice thing as someone above said is if you change your types in the source list, the LINQ keeps working like a champ. As long as whatever your type is supports .Equals(), and whatever your collection is implements IEnumerable.

    It is admittedly slower than the naive looping version, so if your reaction time is, say, 50 nanoseconds or faster maybe consider optimizing.

    Not that it probably matters for this app, but you'd want to use GroupBy so you touch the source enumerable less. https://msdn.microsoft.com/en-us/library/bb534501(v=vs.110).aspx



  • @mikehurley said in Learning C#:

    Not that it probably matters for this app, but you'd want to use GroupBy so you touch the source enumerable less.

    My initial version used GroupBy, then I figured this simplified it a bit without changing behavior-- the thing with GroupBy is you then have to select-out the keys, so you're doing two LINQ operations:

    GroupBy(blah => blah).Select(tard => tard.Key)
    

    Instead of the one operation I ended up with using Distinct. (For this use, you don't want the data structure returned by GroupBy-- you only want the key bit of it. Thanks to deferred execution, that'll mostly be optimized out I believe, but.) The real reason the looping version's more efficient is the repeated calls to .Count().

    You may be right though. Either way, stuff like this ought to be written in LINQ.



  • @dcon said in Learning C#:

    @RaceProUK said in Learning C#:

    @dcon said in Learning C#:

    Still fighting XAML a bit, but managing. Well, once I found out trying to use the mouse on a hiDPI monitor a selecting an item from a drop list (like the zoom factor - or any xaml object properties) simply DOESN'T WORK! It'll drop the list it'll select. And ... nothing. Moving back to the 100% screen and all works. (vs2017)

    Is the project configured properly for HDPI support?

    It's the XAML editor in VS that's the issue. It makes using the mouse to select an item in a droplist impossible. It's not the project.

    Bug confirmed. Who knows if/when it will be fixed... Status is set to Future with the comment

    Thank you for your feedback. We have determined that this issue will not be addressed in the upcoming release. We will continue to evaluate it for future releases. Thank you for helping us build a better Visual Studio.


  • Impossible Mission - B

    @dcon said in Learning C#:

    Thank you for your feedback. We have determined that this issue will not be addressed in the upcoming release. We will continue to evaluate it for future releases. Thank you for helping us build a better Visual Studio.

    Thank you for helping us help you help us all.


Log in to reply