Search code examples
wpfdata-bindingxamlreadonly

OneWayToSource binding from readonly property in XAML


I'm trying to bind to a Readonly property with OneWayToSource as mode, but it seems this cannot be done in XAML:

<controls:FlagThingy IsModified="{Binding FlagIsModified, 
                                          ElementName=container, 
                                          Mode=OneWayToSource}" />

I get:

The property 'FlagThingy.IsModified' cannot be set because it does not have an accessible set accessor.

IsModified is a readonly DependencyProperty on FlagThingy. I want to bind that value to the FlagIsModified property on the container.

To be clear:

FlagThingy.IsModified --> container.FlagIsModified
------ READONLY -----     ----- READWRITE --------

Is this possible using just XAML?


Update: Well, I fixed this case by setting the binding on the container and not on the FlagThingy. But I'd still like to know if this is possible.


Solution

  • Some research results for OneWayToSource...

    Option # 1.

    // Control definition
    public partial class FlagThingy : UserControl
    {
        public static readonly DependencyProperty IsModifiedProperty = 
                DependencyProperty.Register("IsModified", typeof(bool), typeof(FlagThingy), new PropertyMetadata());
    }
    
    <controls:FlagThingy x:Name="_flagThingy" />
    
    // Binding Code
    Binding binding = new Binding();
    binding.Path = new PropertyPath("FlagIsModified");
    binding.ElementName = "container";
    binding.Mode = BindingMode.OneWayToSource;
    _flagThingy.SetBinding(FlagThingy.IsModifiedProperty, binding);
    

    Option # 2

    // Control definition
    public partial class FlagThingy : UserControl
    {
        public static readonly DependencyProperty IsModifiedProperty = 
                DependencyProperty.Register("IsModified", typeof(bool), typeof(FlagThingy), new PropertyMetadata());
    
        public bool IsModified
        {
            get { return (bool)GetValue(IsModifiedProperty); }
            set { throw new Exception("An attempt ot modify Read-Only property"); }
        }
    }
    
    <controls:FlagThingy IsModified="{Binding Path=FlagIsModified, 
        ElementName=container, Mode=OneWayToSource}" />
    

    Option # 3 (True read-only dependency property)

    System.ArgumentException: 'IsModified' property cannot be data-bound.

    // Control definition
    public partial class FlagThingy : UserControl
    {
        private static readonly DependencyPropertyKey IsModifiedKey =
            DependencyProperty.RegisterReadOnly("IsModified", typeof(bool), typeof(FlagThingy), new PropertyMetadata());
    
        public static readonly DependencyProperty IsModifiedProperty = 
            IsModifiedKey.DependencyProperty;
    }
    
    <controls:FlagThingy x:Name="_flagThingy" />
    
    // Binding Code
    Same binding code...
    

    Reflector gives the answer:

    internal static BindingExpression CreateBindingExpression(DependencyObject d, DependencyProperty dp, Binding binding, BindingExpressionBase parent)
    {
        FrameworkPropertyMetadata fwMetaData = dp.GetMetadata(d.DependencyObjectType) as FrameworkPropertyMetadata;
        if (((fwMetaData != null) && !fwMetaData.IsDataBindingAllowed) || dp.ReadOnly)
        {
            throw new ArgumentException(System.Windows.SR.Get(System.Windows.SRID.PropertyNotBindable, new object[] { dp.Name }), "dp");
        }
     ....