I'm still in the process of learning WPF myself, so I was curious and decided to play around with this. Here's what I think is happening:
Before the binding is set, the String dependency property just has a simple backing field for the o2 instance. Setting a binding, however, changes it from a backing field to a BindingExpression which links it to the binding source. If you try BindingOperations.GetBindingExpression() before and after setting the binding, you'll notice it's null before, and an instance after. Doing this appears to clobber any value that may have been there already. When you think about it, this makes perfect sense for every type of binding except OneWayToSource.
Even for OneWayToSource bindings though, it still somewhat makes sense when you realize that bindings are usually set immediately in the constructor, either through XAML or in code. This usually happens before the property is ever used at all, so in most situations it's probably never noticed.
Quote:When I set BindingMode to TwoWay, everything works as expected.
I'm not sure that it does. If you set a value changed callback on the String property, then use a TwoWay binding, you'll notice that it immediately pulls in the value from its binding source (the Bool property in this case). Since the default value for bools is false, the converter will yield "nope" which is the same value you're setting on String right off the bet. If you instead set string to "yep" and try the two way binding, it still comes out as "nope" after the binding is set.
I'm not sure that there's anything you can do about this except either setting your bindings before using the property, or caching the value, setting the binding, then setting the value back again.