Wednesday, 23 February 2011

Use yield, yield...

Say I have an IEnumerable<T> array, I want to split this array to be some sub-arrays like this IEnumerable<IEnumerable<T>>, what I should do? Of course we must have a condition, say it is Predicate<T>, now it time to write an extension method to do this, the code is here:


   1:  public static IEnumerable<IEnumerable<T>> 
   2:      Spliter<T>(this IEnumerable<T> source, Predicate<T> predicate)
   3:  {
   4:      List<T> list = new List<T>();
   5:      foreach (var x in source)
   6:      {
   7:          if (predicate(x))
   8:          {
   9:              yield return list;
  10:              list = new List<T>();
  11:              continue;
  12:          }
  13:   
  14:          list.Add(x);
  15:      }
  16:   
  17:      if (list.Count > 0)
  18:          yield return list;
  19:  }


the whole codes are here:



   1:  using System;
   2:  using System.Collections.Generic;
   3:  using System.Linq;
   4:  using System.Text;
   5:   
   6:  namespace ConsoleApplication1
   7:  {
   8:      class Program
   9:      {
  10:          static void Main(string[] args)
  11:          {
  12:              testInt();
  13:              testString();
  14:   
  15:              Console.ReadLine();
  16:          }
  17:   
  18:          static void testString()
  19:          {
  20:              string[] x = new string[] 
  21:              {
  22:                  "rregr ",
  23:                  "rg regreg",
  24:                  "",
  25:                  "gegerg",
  26:                  "",
  27:                  "cvbbhbgb",
  28:                  "rregregreg",
  29:                  "",
  30:                  "gregregre",
  31:                  "gytjytj",
  32:                  "jrhrth",
  33:                  "htrhrth",
  34:                  "",
  35:                  "hthtrhrth",
  36:                  "hrthrthrth",
  37:                  "hrthtrh",
  38:                  "",
  39:                  "hrthrthrthrth",
  40:                  ""
  41:              };
  42:   
  43:              foreach (var z in x.Spliter(s => s.Length == 0))
  44:              {
  45:                  foreach (var q in z)
  46:                      Console.Write(string.Format("{0},", q));
  47:                  Console.WriteLine();
  48:              }
  49:   
  50:          }
  51:   
  52:          static void testInt()
  53:          {
  54:              int[] x = new int[] { 0, 2, 3, 
  55:                  45, 9, 5, 6, 7, 0, 3, 2, 
  56:                  5, 0, 3, 4 };
  57:              foreach (var z in x.Spliter(s => s == 0))
  58:              {
  59:                  foreach (var q in z)
  60:                      Console.Write(string.Format("{0} ", q));
  61:                  Console.WriteLine();
  62:              }
  63:   
  64:          }
  65:      }
  66:   
  67:      public static class Helper
  68:      {
  69:          public static IEnumerable<IEnumerable<T>> 
  70:              Spliter<T>(this IEnumerable<T> source, Predicate<T> predicate)
  71:          {
  72:              List<T> list = new List<T>();
  73:              foreach (var x in source)
  74:              {
  75:                  if (predicate(x))
  76:                  {
  77:                      yield return list;
  78:                      list = new List<T>();
  79:                      continue;
  80:                  }
  81:   
  82:                  list.Add(x);
  83:              }
  84:   
  85:              if (list.Count > 0)
  86:                  yield return list;
  87:          }
  88:      }
  89:  }

see, it's pretty easy and beautiful and fast 

Silverlight C1RichTextBox Selection Problem

During developing with C1RichTextBox, I found a problem that I have to pay attention, the problem is like this:
  1. Include the namespaces in the XAML codes:
       1:  <navigation:Page ...
       2:   xmlns:c1rtbtb="clr-namespace:C1.Silverlight.RichTextBox;assembly=C1.Silverlight.RichTextBox.Toolbar" 
       3:   xmlns:c1rtb="clr-namespace:C1.Silverlight.RichTextBox;assembly=C1.Silverlight.RichTextBox"
       4:   xmlns:c1="clr-namespace:C1.Silverlight;assembly=C1.Silverlight">

  2. Add a C1RichTextBoxToolBar, a C1RichTextBox and a TextBlock to the Grid
       1:  <c1rtbtb:C1RichTextBoxToolbar 
       2:      RichTextBox="{Binding ElementName=rtb}" 
       3:      Grid.Row="0" />
       4:  <StackPanel Grid.Row="1" Grid.Column="0">
       5:      <c1rtb:C1RichTextBox 
       6:      x:Name="rtb"             
       7:      Margin="5" MinHeight="50"
       8:      SelectionChanged="rtb_SelectionChanged"/>
       9:      <TextBlock x:Name="textBlockMessage" MinWidth="250" Margin="5"/>
      10:  </StackPanel>

  3. Write C# codes for SelectionChanged event which is rtb_SelectionChanged:
  4.    1:  private void rtb_SelectionChanged(object sender, EventArgs e)
       2:  {
       3:      textBlockMessage.Text = (this.rtb.Selection.Start.Element as C1Run).Text;
       4:  }
  5. Run the Application, and watch the text change in textBlockMessage(is a TextBlock)
Now, let's input some text like this, see the screenshot:









    Now the C1TextElement 1234567890ABCDEF9999 has three different C1Runs, they are
    C1Run: 1234567890
    C1Run: ABCDEF
    C1Run: 9999

    if you put the cursor in between any of the two C1Runs, for example, if we put the cursor between 0 and A, like this:










    you can see that the textBlockMessage.Text is outputting 1234657890 which is the previous C1TextElement of the cursor, very good, now if we put the cursor between F and 9, like this:










    what you can see that the this.rtb.Selection.Start.Element is still pointing to the previous element of the cursor. very good, but if you keeping changing the position of the cursor by using the keyboard and mouse, sometimes, you will find the output like this:









    well, this time, the this.rtb.Selection.Start.Element is pointing to the element behind the cursor.

    for the user, this is ok, but for developers who want to use the Selection.Start as the condition, this is a big problem. So please remember : If the start or the end is in between two different C1Runs,the start and end property of the C1RichTextBox.Selection is unpredictable. So if you are developing on C1RichTextBox.Selection and find your codes actioning weirdly, please check this issue

    Hello World

    Hi, This is Chun Xu( or call me Matt ), in this blog, I will keep posting the Silverlight/C#/.Net experience

    Welcome to follow up