Posts
49
Comments
83
Trackbacks
0
January 2008 Entries
Allow other pages to be anonymously viewed with Forms Authentication

I was playing around with Live ID Controls and trying to do a sample project to have my page integrate both Live ID authentication and my own forms-based authentication.  This reminds me of the first .NET project that I did way back...

Rewind time...

Back in 2001, I got involved in creating a new web page to allow our clients to send their files to us, and we decided to use .NET (still in Beta 1 at the time).  I learned about using Forms-based authentication, which was nice since accesses to any page other than the login page will automatically be redirected back to the login page.  But we wanted to provide a password recovery page as well, and looking as hard as I can, I could not find a way to set exception on pages (in the same web project) to not use the forms-based authentication, which we like to have for all other pages.

I was annoyed by that and in the end admitted defeat and ended up creating a separate (1 webform) project that contains the password recovery page.

Fast forward in time...

I haven't done much web development in the past 4 years, mostly desktop client apps, and my playing around with Windows Live ID reminded me of that challenge.  Distracted, I set out to seek if I can find an answer this time, especially since I know with the set of login controls in ASP.NET 2.0, it has a password recovery control as well.  I went to MSDN and start reading on those controls, read on the authentication / authorization elements in web.config, dug around a bit, and found my answer.

Apparently there's a <location> element that you can apply to specify a path (directory or actual file) that you can then specify different authorization mechanism.  The kicker was that the element is not a child of <system.web>, rather (for my need) it will become a parent of <system.web>.  Oh yeah, it's also new in .NET 2.0.

So, without further ado, the following config will allow a page (PasswordRecovery.aspx) to be accessed without any authentication, while still retaining Forms-based authentication for all the other pages.

 <location path="PasswordRecovery.aspx">
    <system.web>
      <authorization>
        <allow users="?" />
      </authorization>
    </system.web>
 </location>
 
 <system.web>
    <authentication mode="Forms" >
      <forms loginUrl="UserLogin.aspx" />
    </authentication>
    <authorization>
      <deny users="?" />
    </authorization>
 
    <!-- Other configuration settings -->
 </system.web>

You can provide a directory path instead to have all the webforms in that directory be free of Forms-based authentication.  I'm somewhat glad to get this particular piece of knowledge, because it has been nagging me for quite a long time.  In any case, the solution doesn't quite work for the website I worked on - this solution only works for .NET 2.0 and up, and the website (still running strong) is still using .NET 1.1.  So if anyone knows how to do this in 1.1 (or 1.0), I would appreciate the info.

posted @ Saturday, January 26, 2008 7:23 AM | Feedback (0)
An alternative to notifying CollectionView of multiple items changed

While trying to sort out a different problem, I ended up looking at the NotifyCollectionChangedEventArgs constructor where the first overload only needs a NotifyCollectionChangedAction enumeration with no items needed.  It must've escaped my mind since most of the implementation I had so far will actually raise the CollectionChanged event when adding or removing an item, and most of those implementation will just specify the item being added/removed.

This single parameter constructor documentation specifies the action has to be NotifyCollectionChangedAction.Reset.  It piques my interest to learn more as to what Reset does.  The documentation states that Reset means 'The content of the collection changed dramatically'.  I remembered one of my post where I complained that CollectionView does not support multiple items being added/removed, and my solution then was to call the Refresh method of the CollectionView, which even though it's fine, it's very CollectionView specific.

So I went through my test projects, and voila, CollectionView accepts (and behave appropriately) the Reset action.  As such, the code to handle CollectionView becomes much simpler:

public class MyObservableCollection<T> : ObservableCollection<T>

{

   private bool _delayCollectionChangeNotification = false;

   // Want to delay change notification when inserting multiple items

   public bool DelayCollectionChangeNotification

   {

      get { return _delayCollectionChangeNotification; }

      set

      {

         if (_delayCollectionChangeNotification != value)

         {

            _delayCollectionChangeNotification = value;

            if (value == false)

               OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));

         }

      }

   }

 

   public void AddRange(IEnumerable<T> items)

   {

      DelayCollectionChangeNotification = true;

      foreach (T item in items)

      {

         Add(item);

      }

      DelayCollectionChangeNotification = false;

   }

 

   protected override void OnCollectionChanged(System.Collections.Specialized.NotifyCollectionChangedEventArgs e)

   {

      if (_delayCollectionChangeNotification == false)

         base.OnCollectionChanged(e);

   }

}

No more need to walk thru the event subscriber, and you can somewhat control it from the outside thru the DelayCollectionChangeNotification property.  I learned something new today...

posted @ Friday, January 25, 2008 12:10 PM | Feedback (0)
protected internal modifier weirdness

I was talking with my peer today, and she told me about the weird behavior of using 'protected internal' access modifier.  Using that modifier does NOT mean that the property/field is protected (can only be accessed by that class or derived classes) AND internal (if the derived class is in a different assembly that derived class won't be able to see that property/field).

It turns out to be an OR - (per msdn) - that property/field is now protected (can only be accessed by that class or derived classescan only be accessed by that class or derived classes) AND that property field is now available internally as public (property/field can be accessed publically by any class in that assembly - it's not treated as protected anymore in that assembly).

The following code becomes valid:

// Both BaseClass and OtherClass resides in the same assembly, say assy1.dll

public class BaseClass

{

   private int _value;

 

   protected internal int Value

   {

      get { return _value; }

      set { _value = value; }

   }

}

 

public class OtherClass

{

   public void Test()

   {

      BaseClass bc = new BaseClass();

      bc.Value = 5; // This is valid now

   }

}

In my mind, this doesn't make sense; why would it be treated as if it's protected OR internal?  Derived classes in other assemblies work as expected, as the following code shows:

// Both these classes are in the same assembly, say assy2.dll

public class SomeClass

{

   public void Test()

   {

      BaseClass bc = new BaseClass();

      bc.Value = 9; // This causes CS0122 but will go away if you have

                    // [assembly: InternalsVisibleTo("assy2.dll")]

   }

}

 

public class DerivedClass : BaseClass

{

   public void Test()

   {

      base.Value = 7;

   }

}

The DerivedClass works as expected, it can access base.Value since it is a protected property.  The Test method in SomeClass will error out during compilation.  However, if you use the InternalsVisibleToAttribute, it will work again, since it treats assy2.dll as if it belongs in the same assembly.

So, the above construct doesn't help to achieve a situation where you want:

  • a public base class defined in an infrastructure DLL
  • one of its property/field is protected (can't be accessed within non-derived classes in said infrastructure DLL)
  • derived classes in other assemblies can't access that property/field (limiting that property so it can only be accessed in the infrastructure DLL)

I'm somewhat disappointed with this revelation, because we actually have s design that would benefit from having this ability; we have a base class where we want its function to only be available to some derived classes in other assemblies, but not others (mostly for 3rd party consumers), and we thought we can make those functions to be protected and also make it internal - assemblies that need access to those function will be allowed using the InternalsVisibleToAttribute.  But it wasn't meant to be...

posted @ Wednesday, January 23, 2008 6:49 PM | Feedback (1)
Casting value type to object and back to another value type...

This may be old news for other people, but new to me and I am trying to put in new stuff that I learned.  I wasn't aware of this, and after thinking about it, it does make sense (looking at it from how boxing/unboxing works), but I wished it had worked.

The following code will throw an InvalidCastException

 private void PassValue()

{

   float f = 5;

   double d = CastValue(f);

}

 

private double CastValue(object o)

{

   return (o is float) ? (double)o : double.NaN;

}

So would the following.

private void PassValue()

{

   int i = 5;

   object o = i;

   Int64 j = (Int64)o;

 

}

When .NET boxes a value type, it keeps the type with it, and any effort to cast it as something else will fail.  I was surprised with this; a consumer of my infrastructure project was telling about this exception where a piece of code was casting an object passed as a double.  He was passing a float.

Like I mentioned, after looking at it and thinking about it in terms of .NET boxing/unboxing, it makes sense.  I just wished it had worked.  I could've just used the Convert.ToDouble (or use IConvertible), but I wanted to make sure the passed value IS a numeric type.  If it's a string, or a byte for instance, I want to throw an exception.  Now I have to change my code so it checks for all possible numeric type and throw an exception if it's not.  Bummer...

posted @ Monday, January 21, 2008 5:12 PM | Feedback (0)
Understanding Garbage Collection in relation to CollectionView classes

In my post yesterday, I created a rudimentary mechanism to detect if/when an object is garbage collected in .NET.  In the example I gave, I created a ListCollectionViewEx class deriving from ListCollectionView.  The sample code then tries to create 100 ListCollectionViewEx and then for a GC.Collect.  To my surprise, the ListCollectionViewEx objects are not garbage collected.

Now, I know the mechanism to record garbage collected item works, because I've tried it with other objects.  So what gives?  From MSDN, it states that ListCollectionView is 'Represents the collection view for collections that implement IList.'.  CollectionView is its base class, which should be used for collections that are not in List format.  You can see that both does not have a parameterless constructor, CollectionView requires an IEnumerable to be passed, and ListCollectionView requires an IList to be passed - it then uses that collection to provide a view for that collection.

One of the nice advantages to using these is that if the underlying collection changes, and the collection implements INotifyCollectionChanged interface, the view also will show those changes.  Based on this knowledge, we can surmise that those classes will be a subscriber to the CollectionChanged event.  This causes a relation (object graph) to be created from the underlying collection.  I'll illustrate it in the code snippet below:

public class Test
{
   private INotifyCollectionChanged _list = new ObservableCollection<string>();
 
   public INotifyCollectionChanged List
   {
      get { return _list; }
   }
 
   public void Subscribe()
   {
      _list.CollectionChanged += _list_CollectionChanged;
   }
 
   void _list_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
   {
      // Do stuff
   }
}

In the above code, I have a Test class that contains a list (which is an ObservableCollection - implements INotifyCollectionChanged) - whenever a Test object is created, the list will also be created and since it is contained in the Test class, you can draw an object graph from that Test object to the list object.  Because of this, the list object can't be garbage collected until the Test object is not reachable (contained or referenced).

The function will then have the Test object subscribe to the CollectionChanged event from the list - since the event originates from the list to the subscriber (Test object), this creates another object graph from the list to the Test object, which meant the list now references the Test object.  This also means that while the list is referenced by another object, the Test object and the list object can't be garbage collected.

We're assuming that CollectionView/ListCollectionView works similarly where it subscribes to the CollectionChanged event of the collection being passed in the constructor.  Is there a way to verify this?  It's a good thing that we're using our own collection class, the ThreadAwareObservableCollection<T>.  So I created a helper function in it for verification.

public class ThreadAwareObservableCollection<T> : ObservableCollection<T>
{
   public string[] GetCreationIdsFromSubscribers()
   {
      System.Collections.Specialized.NotifyCollectionChangedEventHandler eventHandler = CollectionChanged;
      if (eventHandler == null)
         return new string[0];
 
      List<string> creationIds = new List<string>();
      Delegate[] delegates = eventHandler.GetInvocationList();
      // Walk thru invocation list
      foreach (System.Collections.Specialized.NotifyCollectionChangedEventHandler handler in delegates)
      {
         ListCollectionViewEx lcv = handler.Target as ListCollectionViewEx;
         if (lcv != null)
            creationIds.Add(lcv.CreationId);
      }
 
      return creationIds.ToArray();
   }
   public void RemoveAllCollectionViewSubscriber()
   {
      System.Collections.Specialized.NotifyCollectionChangedEventHandler eventHandler = CollectionChanged;
      if (eventHandler == null)
         return;
 
      Delegate[] delegates = eventHandler.GetInvocationList();
      // Walk thru invocation list
      foreach (System.Collections.Specialized.NotifyCollectionChangedEventHandler handler in delegates)
      {
         if (handler.Target is ListCollectionViewEx)
            CollectionChanged -= handler;
      }
   }
}
 
private void TestFunction()
{
   for (int i = 0; i < 100; i++)
   {
      ListCollectionViewEx lcv = new ListCollectionViewEx(ItemCollector.ItemsCreated);
   }
 
   GC.Collect();
 
   string[] creationIds = ItemCollector.ItemsCreated.GetCreationIdsFromSubscribers();
   ItemCollector.ItemsCreated.RemoveAllCollectionViewSubscriber()
   GC.Collect();
   creationIds = ItemCollector.ItemsCreated.GetCreationIdsFromSubscribers();
}

I've added helper functions in the ThreadAwareObservableCollection<T> class that helps in getting the creation Ids of the ListCollectionViewEx subscribers, and another one to remove all ListCollectionViewEx subscribers from its CollectionChanged event.  Running the code above and stepping through the TestFunction shows that after a GC.Collect(), the number of subscribers doesnt' change even after the GC.Collect, and the creationIds returned are the creation Ids from the ListCollectionViewEx class.  Calling the method to remove CollectionView subscribers, then calling GC.Collect a second time will populate our collection that contains destroyed items.

This shows a fairly dangerous repercussions; collections that gets viewed via CollectionView (or its derived classes) will not be able to be garbage collected until the collection itself goes out of scope.  In fact, any event subscriber will not be able to be garbage collected until the event-generating object goes out of scope.  There are ways to solve this: the WeakEvent pattern is one, but this is usable if you're creating the listener class yourself.  I'll talk about an approach I took to solve this, it's not pretty, it's better than manually unsubscribing.

posted @ Friday, January 18, 2008 3:06 PM | Feedback (1)
Verifying objects do get Garbage Collected

I learned something new, relating to when/how to dispose CollectionView, but it comes after a series of steps of proving it.  Along the way I learned some new stuff to, so I'll stagger them so it becomes easier to read & digest.  This post will become the first one in this series (of 3 I think).

I'm always somewhat wary about the automatic garbage collection nature of .NET, so every now and then I need to prove to myself that something is actually garbage collected.  The technique I use is to create a Finalizer in my class that will signify that that object's finalize is being called (which means it is being garbage collected).  If the finalizer doesn't get hit, then the object doesn't get garbage collected.

Single objects are fine to debug - you put a breakpoint in your finalizer and be done with.  But there are times I wanted to verify that multiple objects are garbage collected - there are also times when I wanted to know what objects are not yet garbage collected, and what has.  So, I developed the following mechanism.

public static class ItemCollector

{

   private static int _counter = 0;

   // This function creates an Id String for the object being created

   public static string GetStringForItemCreation(Type itemType)

   {

      string id = string.Format("{0} number {1}", itemType.FullName, ++_counter);

      _itemsCreated.Add(id);

      return id;

   }

 

   // This function will add the id to the itemsDestroyed collection

   public static void ReturnStringForItemDestruction(string id)

   {

      _itemsDestroyed.Add(id);

   }

 

   private static ThreadAwareObservableCollection<String> _itemsCreated = new ThreadAwareObservableCollection<string>();

   // String collection of all item id created

   public static ThreadAwareObservableCollection<String> ItemsCreated

   {

      get { return _itemsCreated; }

   }

 

   private static ThreadAwareObservableCollection<string> _itemsDestroyed = new ThreadAwareObservableCollection<string>();

   // String collection of all item id destroyed

   public static ThreadAwareObservableCollection<string> ItemsDestroyed

   {

      get { return _itemsDestroyed; }

   }

}

This static class has 2 string collection - I'm using the thread-aware collection since garbage collection will be called by a different thread - one to collect all string for items that are created, and another one to collect string for item that is garbage collected.  The GetStringForItemCreation will return a string giving a unique Id for that item and add it to the first collection - the ReturnStringForItemDestruction will just add the given Id to the second collection.

These functions will be called by my objects in their construction and destruction - for instance I'd like to see when ListCollectionViews are garbage collected, so I create a class deriving from it as follows:

public class ListCollectionViewEx : ListCollectionView

{

   public ListCollectionViewEx(System.Collections.IList list)

      : base(list)

   {

   }

 

   ~ListCollectionViewEx()

   {

      ItemCollector.ReturnStringForItemDestruction(_creationId);

   }

 

   private string _creationId = ItemCollector.GetStringForItemCreation(typeof(ListCollectionViewEx));

}

Now, whenever this class is created, it will get a string Id (and add it to the main collection), and when the object is garbage collected, the finalizer will return the string id to our ItemCollector class.  You can modify the ItemCollector class so it also puts a timestamp, removes the id from ItemsCreated collection, etc. - but the basic idea is the same: On object construction you'd like to register an object has been constructed, and on destruction you want to note that the object has been destructed.  By having this information, you can then see which objects are still not garbage collected, and which objects have been.

Please note that you only want to put finalizers for debugging purposes - having a finalizer will impact performance (and garbage collection) of your objects.  Once you verify the item is being garbage collected, then you can take them out.  I thought about using [Conditional("DEBUG")] but that attribute doesn't work on constructors/destructors.

A small test code I made then is as follows:

for (int i = 0; i < 100; i++)
{
   ListCollectionViewEx lcv = new ListCollectionViewEx(ItemCollector.ItemsCreated);
}
 
GC.Collect();

Pretty simple - you can use this just to prove that your objects are being garbage collected. Calling GC.Collect will force garbage collection, thus since the ListCollectionViewEx objects are not collected / referenced, all those objects should be garbage collected.  You can use this construct to test your classes.  The only kicker is that the above code will result in no items / Ids being added to our ItemsDestroyed list.  Why is that?  That's for tomorrow's blog - I have to pace myself you know .

posted @ Thursday, January 17, 2008 2:10 PM | Feedback (0)
Changed blog's display skin

After looking at some other blogs that reside here, they all look... better for lack a more suitable word.  Went into my configuration and there I saw Display Skin selection, so I gave that a try.

Most of the skins/styles are narrow-ish, which doesn't work very well with blogs that may contain code (like I'm planning mine would).  I got it down to a few selection that would work, and I'll just put it here so I can remember what they are (and not try them again one-by-one if I wanted to change it in the future).

AnotherEon001 – has about &frac12; inch blank space on the left side – I actually like the layout to this.
Cogitation – I actually like this quite a bit, but the couple of blogs I went to uses this exact skin too.  Maybe I’ll try something else first…
informatif – The fonts were way too big on this one – it looks decent, if only it can be customized to be smaller?
Lightz – This is pretty good – the only thing is that posts have fixed width, but code (I usually put them in tables) sticks out.  So it doesn’t lay out very well for me.
Semagogy – This is what ended up choosing, it’s also fairly down there in the list.  I wish the background color can be changed – I prefer a lighter, cheerier tone.  But the layout is great – it provides plenty of space to show the texts & code, it expands based on the largest table size being displayed.  The biggest drawback is that code sections are being displayed with large spacing.

I would appreciate any help anyone can give me (or point a link to) on how to customize small parts of the styles.  Let me know if this layout doesn’t quite work too.

Oh, I also found the preview button in the post editor - third button on top, the one with magnifier.  Since I post code, I usually maximize the editor when I type.

posted @ Thursday, January 17, 2008 9:23 AM | Feedback (1)
Have worker thread update ObservableCollection that is bound to a ListCollectionView

While playing around with WPF, I tried to do some multithreading where I have a worker thread updating my ObservableCollection, while having a ListCollectionView of that ObservableCollection being shown on a ListBox.

It was surprising to see that I get a NotSupportedException thrown, with the message saying 'This type of CollectionView does not support changes to its SourceCollection from a thread different from the Dispatcher thread.'.  That doesn't seem to make sense - In my mind, I understand how the thread that created the UI should be the one that handles all UI updates.  However, the data itself should be able to reside anywhere, and I should be able to update it however and whenever I want.

Looking for a solution, I created a class deriving from ObservableCollection thinking that I would just manually walk through the event's invocation list.  Well, that didn't quite work, since events are not accessible (other than for adding/removing delegates) to child classes.  Looking at the documentation, the CollectionChanged event in ObservableCollection is virtual - that means I can override it! Yeah!  I am glad someone at Microsoft decided to make that virtual.

So here's the code that I created - the pain is I now have to rename all occurrences of ObservableCollection to this new class.  Oh well, at least making it work with threads isn't too painful.

protected override void OnCollectionChanged(System.Collections.Specialized.NotifyCollectionChangedEventArgs e)

{

   // Be nice - use BlockReentrancy like MSDN said

   using (BlockReentrancy())

   {

      System.Collections.Specialized.NotifyCollectionChangedEventHandler eventHandler = CollectionChanged;

      if (eventHandler == null)

         return;

 

      Delegate[] delegates = eventHandler.GetInvocationList();

      // Walk thru invocation list

      foreach (System.Collections.Specialized.NotifyCollectionChangedEventHandler handler in delegates)

      {

         DispatcherObject dispatcherObject = handler.Target as DispatcherObject;

         // If the subscriber is a DispatcherObject and different thread

         if (dispatcherObject != null && dispatcherObject.CheckAccess() == false)

         {

            // Invoke handler in the target dispatcher's thread

            dispatcherObject.Dispatcher.Invoke(DispatcherPriority.DataBind, handler, this, e);

         }

         else // Execute handler as is

            handler(this, e);

      }

   }

}

 

 Update:

There is a bug with the code where subscribers in the same thread won't get called - the code above has been updated with the fix.

 

It also uses CheckAccess (available, but not shown via Intellisense as mentioned here).

posted @ Wednesday, January 16, 2008 6:30 PM | Feedback (13)
ListCollectionView/CollectionView doesn't support NotifyCollectionChanged with multiple items

One issue with an app I'm developing is speed.  It's a WPF desktop app, and it has a global list of entities being loaded, and we're using ListCollectionView to show the entities (filtered accordingly by each ListCollectionView created).  We always thought that it was a DB issue, so yesterday I went researching how to optimize the DB call & code in general.

My code was very spartan; paraphrasing, it goes as follows:

BaseEntity[] entities = GetEntities(parentId);

foreach (BaseEntity entity in entities)

{

   ProcessEntity(entity);

   GlobalList.Add(entity);

}

GlobalList is a KeyedCollection derived-class that implements INotifyCollectionChanged.  The GetEntities method hits the DB and reads some 3000+ records, instantiating an entity for each record.  This whole 6 liner takes 20+ seconds.  When I profile this, the DB call took 200+ ms; the GlobalList.Add took almost 20 seconds by itself.  I was piqued by this, and went deeper.

For each item being added to the list, the class raises the CollectionChanged event.  And there were 45 ListCollectionView that is created from this GlobalList; hence each of them become subscribers of that event.  Doing the math, with over 3000 items being added, the event raising results in over 150000 delegate calls - which is why it took almost 20 seconds to do.

Since we created the code for the this GlobalList class, I added an AddRange method, which will accept IList<BaseEntity> as its parameter which will then just raise the event once by calling OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, items)); passing in the items as the parameter to the event argument.

Piece of cake, right?  It turns out that ListCollectionView will throw a NotSupportedException saying that range actions are not supported.  CollectionView behaves the same way too.  The easiest solution, and it makes sense too, and it is NOT supported - I was blown out of my mind.

The second solution I tried was to just raise the event once, passing the last item being added as the event argument.  No dice; the ListCollectionView will only show 1 additional item (instead of the 3000+ items being added).

The solution I came up with is to then still use the AddRange method, and in the OnCollectionChanged method iterate through the invocation list of the event, and if the target is a CollectionView then do not call the handler, but call its Refresh method (which will recreate the view).  Code follows:

protected virtual void OnCollectionChangedMultiItem(NotifyCollectionChangedEventArgs e)

{

   NotifyCollectionChangedEventHandler handlers = this.CollectionChanged;

   if (handlers != null)

   {

      foreach (NotifyCollectionChangedEventHandler handler in handlers.GetInvocationList())

      {

         if (handler.Target is CollectionView)

            ((CollectionView)handler.Target).Refresh();

         else

            handler(this, e);

      }

   }

}

Result? Our loading code went from 27 seconds to 5 seconds.

Moral of the story?  Coming from my C++ background, I got used to properly delete items, counting references, and making sure things get cleaned up when possible.  C# espouses faster application development, it's more intuitive, better IDE, and given its automatic garbage collection, we sometimes forget to that we still have to manage stuff under the hood where necessary.  Better understanding of how things work under the hood is still key to creating fast performing, efficient code, even if you can't look at the source for the code.

Please note that the above code works well when you add multiple items - when you're adding items one by one (or you're forced to, can't add in bulk), you'll still get the same slowdown.  Another way to solve this is to have a public property on the collection class (say DeferCollectionChangedEvent); when it's set to true, then you will just accumulate the items and then raise the event whenever DeferCollectionChangedEvent gets reset to false (or provide a function that can trigger the CollectionChanged event).

Hopefully this may become useful to those trying to use WPF & uses CollectionView extensively.

posted @ Wednesday, January 16, 2008 9:33 AM | Feedback (1)
Binding to an Attached Property

Yesterday, I have some ideas in my mind on how to give out ValidationRule errors after the values passes the converter, and I was trying to see if I can use Attached Properties for that.

When trying to do this, one of the things I'd like to do was set a control's text to the Attached Property's value and that's when I realized that I don't know the syntax to do that.

A quick Google search yields some results; someone asked the same question and the answer suggested using parentheses.  The following example where the TextBox will display the row index the textbox is residing show how this works:

Bind to Grid.Row attached property

<Grid>

    <Grid.RowDefinitions>

        <RowDefinition Height="Auto"/>

        <RowDefinition Height="Auto"/>

        <RowDefinition Height="Auto"/>

        <RowDefinition Height="Auto"/>

    </Grid.RowDefinitions>

    <Grid.ColumnDefinitions>

        <ColumnDefinition/>

    </Grid.ColumnDefinitions>

    <TextBox Text="{Binding (Grid.Row),RelativeSource={RelativeSource Self}}"

             Height="23" Grid.Column="0" Grid.Row="0" VerticalAlignment="Top" />

    <TextBox Text="{Binding (Grid.Row),RelativeSource={RelativeSource Self}}"

             Height="23" Grid.Column="0" Grid.Row="1" VerticalAlignment="Top" />

    <TextBox Text="{Binding (Grid.Row),RelativeSource={RelativeSource Self}}"

             Height="23" Grid.Column="0" Grid.Row="2" VerticalAlignment="Top" />

    <TextBox Text="{Binding (Grid.Row),RelativeSource={RelativeSource Self}}"

             Height="23" Grid.Column="0" Grid.Row="3" VerticalAlignment="Top"

             Name=”textBox4” />

</Grid>

You can also see that I didn't use Path=(Grid.Row), by default the first parameter is assigned to the Path property of the Binding class.

What about if we want to do it in code; it's very similar: 

Binding b = new Binding("(Grid.Row)");

b.Source = textBox4;

BindingOperations.SetBinding(textBox4, TextBox.TextProperty, b);

The binding path is the same; (Grid.Row) and the other important tidbit is that the source is the textbox itself.  This is logical since when assigning a value to an Attached Property, you're assigning that value for a given DependencyObject.  In this case, we want the text to be set to the Grid.Row attached property for that particular textbox too.

Verifying that it works, now I continue on with my class that implements the Attached Property.  However, since I need to refer to my class using XML namespace, how would the Path look?  The path has to use the namespace too, as the sample below shows:

 

<Grid xmlns:local="clr-namespace:BindingToAttachedProperty">

    <Grid.RowDefinitions>

        <RowDefinition Height="Auto"/>

        <RowDefinition Height="Auto"/>

        <RowDefinition Height="Auto"/>

        <RowDefinition Height="Auto"/>

    </Grid.RowDefinitions>

    <Grid.ColumnDefinitions>

        <ColumnDefinition/>

    </Grid.ColumnDefinitions>

    <TextBox Text="{Binding Path=(local:LocalClass.SomeValue),RelativeSource={RelativeSource Self}}"

             local:LocalClass.SomeValue="1"

             Height="23" Grid.Column="0" Grid.Row="0" Vertical.Alignment="Top" />

    <TextBox Text="{Binding (local:LocalClass.SomeValue),RelativeSource={RelativeSource Self}}"

             local:LocalClass.SomeValue="2"

             Name="textBox2"

             Height="23" Grid.Column="0" Grid.Row="1" VerticalAlignment="Top" />

</Grid>

I found a weird condition in WPF; you can see that for the first TextBox, the Binding has the Path=, while the second one doesn't.  The sample above works, the first textbox will display 1, and the second textbox will display 2.  However, if you take out that Path= string, the example will not work; the BindingExpression specifies PathError.  I believe this is because without the first Path=, WPF doesn't know what is (local:LocalClass.SomeValue).  By specifying Path=, WPF compiles it correctly, and the subsequent encounter of (local:LocalClass.SomeValue) in textBox2 results in a correct interpretation.

OK, the XAML works; how to do it in code?  I tried all kinds of combination for the path, and could not get anything to work - it took me about 2 hours trying around and finally I got a solution.

Binding b = new Binding();

b.Path = new PropertyPath(LocalClass.SomeValueProperty);

b.Source = textBox2;

BindingOperations.SetBinding(textBox2, TextBox.TextProperty, b);

Most of the time, people will just create a new Binding instance, passing the string path in its constructor.  I could not get this to work; all types of string values that I tried results in PathError.  Finally, I took a good look at the Path property in the Binding class and found that one of the PropertyPath constructor accepts an object parameter that can be a DependencyProperty.

This would be my first 'New Thing I Learned' to document .  I'm sure I will look at this information again in the future, and I hope other people can benefit from this.

posted @ Tuesday, January 15, 2008 12:53 PM | Feedback (7)
Trying to blog...

Blogging is new territory for me, so I'm trying to look & see what stuff can I do with this blog site.

I found that you can create new categories, and then each post (I was correct that you blog by creating post - see my first post ) can be associated with 0 or more of these categories.  Found a way to edit my first post, so I can associate it with my categories.  Also found a way to hyperlink to my first post - again we'll see if this works later.

Doesn't seem to be any way to preview or test the post.  I'm pretty sure the experienced bloggers out there uses tools and whatnot to actually post anything.  I've also seen other blogs where there are tags associated with each post - I'm assuming the categories are it, but it doesn't seem to be visible in the actual post.

Lots of things to learn and see - got my password changed, and I think I need to go through the configuration and see what they actually do.  Defaults are usually nice and all, when I have time I'll check them out.

I hope that I can be disciplined enough to spend a few minutes every couple of days to document my learning - most probably that'll be the hardest part.  It's also a bit weird typing this - it's like talking to myself; oh well...

Second Post!

posted @ Tuesday, January 15, 2008 11:45 AM | Feedback (2)
Prologue

This is my first post.

It should be my first post... hopefully - we'll see...

This is my first venture into the world of blogging; I hope this would be a good move - I believe it will have some nice benefits for me, and I hope it can help others too.

I plan to use this blog to catalog & detail (somewhat) any new things I learned during my day-to-day experience.  Sometime early last year, I realized that I learn quite a bit of new stuff just by doing my regular work.  I would just try to remember it though, and not actually document or do much with it.  Over time, that knowledge gets lost or changed in my brain - and there are enough occasions where I would encounter some trouble and I know I solved it before, but I've forgotten by then.

By logging these things I've learned, I can go back and look at it and it will help me with my general work / knowledge.  And if it may help other people, the better.

posted @ Tuesday, January 15, 2008 11:12 AM | Feedback (0)
News