From the XAML editor, I can set the namespace to the Viewmodel contained in a C# project
namespace ViewModelDB
{
public class DependencyViewModel : IViewModelDB
{
public string Message { get; set; }
}
}
And in my xaml
<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:ViewModelDB="clr-namespace:ViewModelDB;assembly=ViewModelDB"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"
>
<UserControl.DataContext>
<ViewModelDB:DependencyViewModel/>
</UserControl.DataContext>
<Grid>
<TextBlock Text="{Binding Message}"/>
</Grid>
</UserControl>
The binding "Message" is then recognized.
When I point at a F# namespace of similar constituency
namespace ModuleDBGraph
open Infrastructure
open Microsoft.Practices.Prism.Regions;
open Microsoft.Practices.Unity;
type IDependencyViewModel =
inherit IViewModel
abstract Message : string with get, set
type DependencyViewModel () =
interface IDependencyViewModel with
member val Message = "" with get, set
I then loose the recognition of the binding Message
<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:ViewModelDB="clr-namespace:ViewModelDB;assembly=ViewModelDB"
xmlns:ViewModelDBFS="clr-namespace:ModuleDBGraph;assembly=ViewModelDBGraphFS"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"
>
<UserControl.DataContext>
<ViewModelDBFS:DependencyViewModel/>
</UserControl.DataContext>
<Grid>
<TextBlock Text="{Binding Message}"/>
</Grid>
</UserControl>
Am I doing something wrong ? This is due to Message being an implementation of the interface IDependencyViewModel and explicit implementation of interfaces in F#, which is a good thing, but is there away to work around this here ?
I don't think there is a better solution than the one we discussed in comments, so I'm turning that into a longer answer.
The reason why it does not work is - as you already suggested - that F# implements interfaces explicitly and so WPF does not see the Message
property when it is an interface member. The most direct workaround is to define it as an explicit property (and the interface implementation can just refer to the main property):
type DependencyViewModel () =
member val Message = "" with get, set
interface IDependencyViewModel with
member x.Message with get() = x.Message and set(v) = x.Message <- v
In general, I think the patterns recommended for C# do not always work nicely in F#. For example, because F# is more succinct (making things easier to rewrite) and less error-prone (catching more bugs statically), I think you might not actually need an interface in this case at all.
A more complicated workaround would be to generate an implicit implementation of the interface using reflection at runtime (from the explicit implementation) and then set it as DataContext
but that would not work nicely with editors, so maybe that's not a good direction.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With