WPF two-way binding with internal setter

907 views Asked by At

I'm using WPF's two-way binding on a CLR property, which implements INotifyPropertyChanged. The set for the property is internal, while the get is public.

Unfortunately, I get the following error:

System.Windows.Markup.XamlParseException was unhandled Message: An unhandled exception of type 'System.Windows.Markup.XamlParseException' occurred in PresentationFramework.dll Additional information: A TwoWay or OneWayToSource binding cannot work on the read-only property 'Name' of type 'MyType'.

Is this the expected behavior? I would have thought that internal setters should work just fine... Note that the CLR-type is defined in another assembly, and are visible in the current assembly, with the [assembly: InternalsVisibleTo("MyAssembly")] attribute.

Does anyone have workarounds/suggestions? The declaring assembly is a class library, so it's not an option for me to change the set to public.

3

There are 3 answers

6
Omaer On

Oh my... I just found out, WPF bindings don't work with internal properties. Oh, Microsoft... Whatever were you thinking?


Update:

Here's what I've understood so far (Thank you, @Grx70):

  • WPF is not a native part of the .NET framework, it's just a "plug-in" framework that happens to be also written by Microsoft. That is why it can't access the internal members of your assembly.
  • Microsoft could have allowed WPF to respect the [assembly: InternalsVisibleTo("XXX")] attribute, but as of right now, WPF ignores it - which unfortunately does not leave one with any easy workarounds. Note: I tested using InternalVisibleTo - both Signed and Unsigned, with PresentationFramework, PresentationCore, and a whole bunch of other DLLs with no luck.
  • The only workaround I can think of right now is to create a "Proxy" class which can expose all required members as public. This is quite a PITA (I have a LOT of classes, and I hate the maintenance nightmare that comes with creating an equal number of "Proxy" classes) - so I might look into using PostSharp, or Fody or some kind of weaver to auto-create these "Proxy" classes if I can.

All the best to anyone else facing this issue.

5
Виталий Белоусов On

You can create your own NEW public wraper property and use getter and setter of it to interact with your internal property

         internal string _SideTabHeader;

            public string SideTabHeader
            {
                get { return _SideTabHeader; }
                set 
{
    if( value<0)
    {
        do nothing
    }
    else
    {
       _SideTabHeader=value;
    };
}
        }
0
Abyte0 On

This is very late and not solving the initial question, but as very related it may help someone else which very similar problem...

If your internal property is of type Enum else skip

In my case I was trying to do a WPF xaml binding to a property of type inherited from a WCF service. The easy way to solve that simple case was to use int.

public Dictionary<int, string> ProductsList => EnumExtensions.ProductsList;

public int ProductType
{
    get { return (int)_DeliveryProduct.ProductType; }
    set
    {
        if (value.Equals(ProductType)) return;
        _DeliveryProduct.ProductType = (ProductEnum)value;
        RaisePropertyChanged(() => ProductType);
    }
}

_DeliveryProduct is my reference to my domain object for which the property ProductType is an enum but in my viewmodel that property is an int. ... Note that ProductEnum is autogenerated from the API and can't be changed to public.

internal static Dictionary<int, string> ProductsList => new Dictionary<int, string>
{
    {(int)ProductEnum.Regular, ProductEnum.Regular.GetDisplayName()},
    {(int)ProductEnum.Intermediate, ProductEnum.Intermediate.GetDisplayName()},
    {(int)ProductEnum.Super, ProductEnum.Super.GetDisplayName()},
    {(int)ProductEnum.Diesel, ProductEnum.Diesel.GetDisplayName()}
};