fsprojects / FsXaml

F# Tools for working with XAML Projects
http://fsprojects.github.io/FsXaml/
MIT License
172 stars 48 forks source link

Return type for Converter<'a,'b> is too strict #12

Closed isaacabraham closed 10 years ago

isaacabraham commented 10 years ago

On a WPF project. I have a ValueConverter that is bound to a TextBlock. It takes in the object (lets say of type Thing) that is bound to TextBlock and returns a decimal figure. The TextBlock binds to a String, but my converter returns a Decimal value.

If I create a Converter<Thing, Decimal>, the converter will always fail because the return types are not compatible i.e. Decimal and String (inside the fWrapped function). I have to change my converter to return a string and explicitly ToString() the decimals.

In another case I also had a converter that returns a SolidColorBrush, yet the destination control expected just a Brush. So again I had to cast them to that.

I don't want to have to worry about the output type to be honest - I want to be able to return decimals and let WPF decide how to render it.

ReedCopsey commented 10 years ago

@isaacabraham I'm not completely sure I follow here...

Can you provide an example converter, with how you are writing it now and how you'd like to write it?

In the 2nd case (SolidColorBrush requiring cast for converter typed as Brush), that's more of an F# language "issue" than an IValueConverter issue, at least as I'm understanding it.

isaacabraham commented 10 years ago

See https://gist.github.com/isaacabraham/abc499625af63d798bcd.

The contract I have defined for the converter is string -> float. The target type of the target element (a textbox) is String. If I return the float from the native converter (having upcast it to an obj), the Textbox will happily display it. The Converter<'a,'b> will reject this as float isn't compatible with String.

I'm not sure exactly what the solution is - it's just a little confusing that it all compiles, and it would work with the native converter, but the extra check in the converter<'a,'b> stops it working.

ReedCopsey commented 10 years ago

I think I have an idea of how to approach this. Right now, I'm checking against the target type in the binding, and returning the default if the types don't match. That's the root of this issue, at least with float->string.

I could add a couple of extra checks in there - if both typeof<'b> and the IValueConverter's targetType implement IConvertible, I could use Convert.ChangeType to coerce the types (with exception handling to fallback to default). I could also have a special case for where the return type is a subclass of the target type, and return in that case. This would provide a behavior more like the default binding behavior.

If either does not implement IConvertible, it'd have to fallback to the current behavior.

Does that seem like a reasonable way to handle this to you? I think it would solve the issue raised by the gist.

ReedCopsey commented 10 years ago

@isaacabraham Can you see if the latest push addresses this for your scenario(s)? It should allow both of the above scenarios to work properly, as far as I can tell.

ReedCopsey commented 10 years ago

@isaacabraham Just following up - I think that last push should have solved this - can I close this issue, or are you still running into problems?

isaacabraham commented 10 years ago

Haven't had a chance to test it - give me until tomorrow, I'll give it a bash then :-)

isaacabraham commented 10 years ago

Just tried it, works now as expected - lovely.