Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 449
Inferis Avatar asked Mar 18 '09 13:03

Inferis


People also ask

How does binding work in XAML?

Data binding is a mechanism in XAML applications that provides a simple and easy way for Windows Runtime Apps using partial classes to display and interact with data. The management of data is entirely separated from the way the data is displayed in this mechanism.

What is OneWayToSource data binding in WPF?

OneWayToSource: The Source property will change if the target property is changed. If the user changes the TextProperty , the UserName property will take up the changed value. This again is of intermediate cost as the binding system watches only Target for changes.

What is ItemsSource binding WPF?

ItemsSource can be data bound to any sequence that implements the IEnumerable interface, although the type of collection used does determine the way in which the control is updated when items are added to or removed.


2 Answers

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");     }  .... 
like image 122
alex2k8 Avatar answered Oct 06 '22 00:10

alex2k8


This is a limitation of WPF and it is by design. It is reported on Connect here:
OneWayToSource binding from a readonly dependency property

I made a solution to dynamically be able to push read-only dependency properties to the source called PushBinding which I blogged about here. The example below does OneWayToSource Bindings from the read-only DP's ActualWidth and ActualHeight to the Width and Height properties of the DataContext

<TextBlock Name="myTextBlock">     <pb:PushBindingManager.PushBindings>         <pb:PushBinding TargetProperty="ActualHeight" Path="Height"/>         <pb:PushBinding TargetProperty="ActualWidth" Path="Width"/>     </pb:PushBindingManager.PushBindings> </TextBlock> 

PushBinding works by using two Dependency Properties, Listener and Mirror. Listener is bound OneWay to the TargetProperty and in the PropertyChangedCallback it updates the Mirror property which is bound OneWayToSource to whatever was specified in the Binding.

Demo Project can be Downloaded Here.
It contains source code and short sample usage.

like image 42
Fredrik Hedblad Avatar answered Oct 05 '22 22:10

Fredrik Hedblad