I'm attempting to bind to a readonly property on a third party control (so no control over the implementation of the property). As I understand, I need to do this as a onewaytosource binding type, and also need to do it in code.
I have the following code to set the binding:
Binding svBinding = new Binding();
svBinding.Path = new PropertyPath("SurfaceScrollViewer");
svBinding.Source = DataContext;
svBinding.Mode = BindingMode.OneWayToSource;
Ds.SetBinding(DiagramSurface.ScrollViewerProperty, svBinding);
And my property implementation on the view model:
public DiagramScrollViewer SurfaceScrollViewer
{
get
{
return surfaceScrollViewer;
}
set
{
surfaceScrollViewer = value;
}
}
private DiagramScrollViewer surfaceScrollViewer;
I can access other properties in the same data context by code, but for some reason, I cannot get this property to bind. Can anyone see where I'm going wrong?
It doesn't work, because it is a bug of wpf. Take a look of this http://meleak.wordpress.com/2011/08/28/onewaytosource-binding-for-readonly-dependency-property/
Hi I misunderstood your question Sorry. It is a kind of bug in wpf for binding ReadOnly properties with OneWayToSource BindingMode you can get exact answer for this is here
Related
Is there anyway to bind to the value of a property, not property itself.
For example: There is a generic grid with two columns "Name" and "Code"
In viewmodel:
NameMemberPath = "Title"; // fetch from database
CodeMemberPath = "ProductCode"; // fetch from database
In Xaml:
<telerik:GridViewDataColumn UniqueName="Name" DataMemberBinding="{Binding Path=NameMemberPath}" />
<telerik:GridViewDataColumn UniqueName="Code" DataMemberBinding="{Binding Path=CodeMemberPath}" />
How to bind the Name to "Title" insted of NameMemberPath
It's possible to do it programmatically but I need to do it declaratively!
i would suggest to change your concept because the ViewModel should provides the Properties for the View directly
let's suggest you want a generic View which will bind to a Property MyAnyProb so it is now to problem of your ViewModel to present this Property.
your ViewModel does now his job by providing this property
public object MyAnyProb
{
get { return getMagic(); }
set { setMagic(value); }
}
// and her is the part where you need to add your logic
private object getMagic()
{
// let magic happen
}
private void setMagic(object probValue)
{
// other magic
}
now you are able to use your view generic with no worries about the property because your generic ViewModel will take care about it
for example:
var MyStrings = new List<string>();
MyStrings = MyFunctionToRetrieveAListOfStrings();
foreach(var str in MyStrings)
{
Binding binding = new Binding("YourControlValue");
binding.Source = str;
YourControl.SetBinding(TextBlock.TextProperty, binding)
}
http://msdn.microsoft.com/en-us/library/ms742863.aspx
IMHO you cannot do that in xaml. How about adding columns to your telerik grid from code behind? I am not very sure if this solution is feasible to you or not but worth a try.
GridViewDataColumn column = new GridViewDataColumn();
column.DataMemberBinding = new Binding(CodeMemberPath.ToString());
this.yourTelerikGrid.Columns.Add(column);
Hope this helps.
The key is to use the "SetBinding" method.
TextBlock myTextBlock = new TextBlock();
myTextBlock.SetBinding(TextBlock.TextProperty, new Binding("SomePropertyName"));
That should do the trick
No you always bind a DependencyProperty to a (public) Property.
(source: microsoft.com)
Read more about Binding in the MSDN!
I've found few solutions which assumes that I have 2 or 3 binding objects(or data templates) - that is not good solution for me. Is there an easy way to do this? I can think of cycling through the visual tree and set the binding that way but still this solution doesn't look very neat.
Thank you in advance.
You can write a custom attached property for this that changes the binding and attach it to the UIElelement where you want to change the binding. All you would have to do now is to trigger a change to that attached property whenever the binding is supposed to change. In the property changed eventhander of your attached dependency property you have access to the UIElement.
<TextBlock local:Helper.DynamicBinding="{Binding SomeStatePropertyOfTheCurrentDataContext}" />
And in the changed eventhandler method:
private void OnDynamicBindingChanged(DependencyObject sender, PropertyChangedEventArgs args)
{
var senderButton = sender as TextBlock;
if((args.NewValue as string) == "MainText")
{
// bind to the property "MainText" of the current datacontext now
}
else if((args.NewValue as string) == "OtherText")
{
// bind to the property "OtherText" of the current datacontext now
}
}
However if you come across the need of changing the binding at runtime like this, chances are that your overall design can be improved!
I'm in the midst of testing a user control I've built, and I'm encountering something that's inexplicable to me.
The control's an extension of the ComboBox that handles values of a specific custom type. It has a dependency property of that custom type that is the target property of a Binding.
I've got a trace statement in the setter, and I can see that the property is getting set. But it's not appearing in my user control.
Now, ordinarily I'd say, okay, I've got a bug in my user control. I probably do, though I'm baffled about it. But this question isn't about finding the bug in my control. Read on; here is where it gets weird.
I'm also using Bea Stollnitz's little value converter to help debug the Binding:
public class DebuggingConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return value; // Add the breakpoint here!!
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException("This method should never be called");
}
}
The idea behind this is that I add this converter to my Binding and can set a breakpoint to see what value is being pushed out to the target. Okay, that works just fine. I can see that the value is being pushed out.
In fact, it works a little too fine. If the DebuggingConverter is attached to the Binding, the user control displays the value. If it's not, it doesn't.
How is that even possible? How could a value converter that does nothing affect the behavior of a bound control?
Edit:
Not that it's likely to help, but here's the XAML for the user control:
<a:CodeLookupBox
Grid.Column="1"
Grid.IsSharedSizeScope="True"
MinWidth="100"
Style="{Binding Style}">
<a:CodeLookupBox.CodeLookupTable>
<Binding Path="Codes" Mode="OneWay"/>
</a:CodeLookupBox.CodeLookupTable>
<a:CodeLookupBox.SelectedCode>
<Binding Path="Value" Mode="TwoWay" ValidatesOnDataErrors="True"/>
</a:CodeLookupBox.SelectedCode>
</a:CodeLookupBox>
Without the converter on the second binding, the control behaves as though I didn't set SelectedCode. Even though a trace statement in the OnSelectedCodePropertyChanged handler shows that e.Value does indeed contain the correct value. This happens irrespective of whether the converter's attached or not.
I've been trying to reverse-engineer this problem with a thought experiment: if you wanted to create a bound user control whose behavior changed if a no-op converter were attached to its binding, how would you do it? I don't know enough about binding to come up with an answer.
Well, the good news is, I know why SelectedCode isn't being set when I'm not using a value converter. The bad news is, I still have something of a mystery, but the problem's been pushed up the food chain a bit, and I have a workaround.
This control is essentially a strongly-typed combo box with a bunch of additional features that are made possible by the fact that it knows what kind of items are in it. The SelectedCode and CodeLookupTable properties are strongly typed, and they hide the underlying SelectedItem and ItemsSource properties, which aren't. (This, by the way, is why this is a user control and not a subclass of ComboBox; I don't want those properties to be visible because a lot of things can happen if they get set improperly, none of them good.)
Here's what's happening. This is my debugging output when the value converter is attached (the number is the hash code of the control, because I've got a bunch of them that all get drawn simultaneously when the program's initialized):
14626603: OnCodeLookupTablePropertyChanged
CodeLookupTable property set to Proceedings.Model.CodeLookupTable
box.MainComboBox.ItemsSource = MS.Internal.Data.EnumerableCollectionView
14626603: OnSelectedCodePropertyChanged:
SelectedCode property set to Unlicensed Driver [VC12500(A)]
box.MainComboBox.ItemsSource = MS.Internal.Data.EnumerableCollectionView
This is the expected behavior. The CodeLookupTable property is set, so setting SelectedCode to one of the items in that collection correctly sets SelectedItem on the underlying ComboBox.
But without the value converter, we get this:
16143157: OnSelectedCodePropertyChanged:
SelectedCode property set to Unlicensed Driver [VC12500(A)]
box.MainComboBox.ItemsSource =
16143157: OnCodeLookupTablePropertyChanged
CodeLookupTable property set to Proceedings.Model.CodeLookupTable
box.MainComboBox.ItemsSource = MS.Internal.Data.EnumerableCollectionView
Here, the SelectedCode property is being set before the CodeLookupTable property is. So when the method tries to set SelectedItem on the underlying ComboBox, nothing happens, because the ItemsSource is null.
And here is the root of the problem. I've foolishly assumed that the order that bindings update their target in is the same as the order they're declared in the XAML. (One of the reasons I've expressed the bindings as elements instead of attributes is because the order of elements in an XML document is deterministic and the order of attributes isn't. It's not like I didn't think about this.) This is apparently not the case.
I've also assumed, maybe a little less foolishly, that the order in which bindings update their target isn't dependent on whether or not they have attached value converters. Well, it is. I wonder what else it depends on.
Mercifully, I have a way to work around this. Since my CodeLookup object contains a reference to the CodeLookupTable, I can make the SelectedCode setter set the CodeLookupTable (and thus the ItemsSource) property first, if it hasn't already been set. That'll make this problem go away without having to stick a fake value converter on the binding and hope that the way bindings behave never changes.
Edit
Here's what the property declarations look like:
#region SelectedCode
public static readonly DependencyProperty SelectedCodeProperty = DependencyProperty.Register(
"SelectedCode", typeof(CodeLookup), typeof(CodeLookupBox),
new FrameworkPropertyMetadata(OnSelectedCodePropertyChanged));
private static void OnSelectedCodePropertyChanged(DependencyObject source, DependencyPropertyChangedEventArgs e)
{
CodeLookupBox box = (CodeLookupBox)source;
CodeLookup code = e.NewValue as CodeLookup;
// this right here is the fix to the original problem:
if (box.CodeLookupTable == null && code != null)
{
box.CodeLookupTable = code.Table;
}
box.MainComboBox.SelectedItem = e.NewValue;
}
public CodeLookup SelectedCode
{
get { return GetValue(SelectedCodeProperty) as CodeLookup; }
set { SetValue(SelectedCodeProperty, value); }
}
#endregion
#region CodeLookupTable
public static readonly DependencyProperty CodeLookupTableProperty = DependencyProperty.Register(
"CodeLookupTable", typeof(CodeLookupTable), typeof(CodeLookupBox),
new FrameworkPropertyMetadata(OnCodeLookupTablePropertyChanged));
private static void OnCodeLookupTablePropertyChanged(DependencyObject source,
DependencyPropertyChangedEventArgs e)
{
CodeLookupBox box = (CodeLookupBox)source;
CodeLookupTable table = (CodeLookupTable)e.NewValue;
box.ViewSource = new CollectionViewSource { Source = table.Codes };
box.View = box.ViewSource.View;
box.MainComboBox.ItemsSource = box.View;
}
public CodeLookupTable CodeLookupTable
{
get { return GetValue(CodeLookupTableProperty) as CodeLookupTable; }
set { SetValue(CodeLookupTableProperty, value); }
}
#endregion
try to implement the ConvertBack function too, you are using two-way binding so the problem may be that the exception will be ignored by the "xaml" but when you step in debug mode you maybe stop the "send value back"-operation?
Hmm...very strange. I've seen similar behavior when dealing with MultiBindings with multiple converters, but not on a simple binding. Out of curiosity, how are you defining your DPs on the control? (including the callbacks, metadata options, etc)
Some stuff to try (after removing the converter hook):
Default the mode (ie, remove the TwoWay)
Remove the ValidatesOnDataErrors
Add an AffectsRender to the SelectedCode DP
What does setting SelectedCode do? Can you post the code for the property changed handler?
You've suggested that debugging shows the property is being set to the correct value, so the most obvious suggestion is that the code providing your intended behaviour is incorrect.
Let's say I have a Class called ModelBase
public class ModelBase
{
public string Name
{
get { return "one"; }
}
}
and I have a property named Model of type ModelBase.
Now to the question how do I Bind to the Name property? The c# code would be this.Model.Name.
I've been trying to get this to work a long time, can some one enlighten me?
Not sure why you are having trouble with this.
You should be able to set the object that the Model property is on as the DataContext for your control, then simply bind using {Binding Model.Name}...
What have you tried to do so far?
(You can definitely bind to properties in Silverlight BTW)
You need to assign Model to the datacontext property before you can do any data binding, an example would be:
this.DataContext = Model;
In xaml, setup binding in this way:
<TextBlock Text={Binding Name}/>
Note: The way you declare the Name property only allows one time binding, to allow OneWay/TwoWay binding, look at dependencyproperty or INotifyPropertyChanged interface.
You can definitely databind to properties.
If you want more, you can use dependency properties of silverlight.
Check this URL.
Silverlight doesn't allow binding to properties. You'll need to expose a property on your viewmodel that returns the value of the models properties to bind correctly.
I have such WPF binding code:
TestModel source = new TestModel();
TestModel target = new TestModel();
Bind(source, target, BindingMode.OneWay);
source.Attribute = "1";
AssertAreEqual(target.Attribute, "1");
target.Attribute = "foo";
source.Attribute = "2";
AssertAreEqual(target.Attribute, "2");
The second assertion fails! This seems odd for me.
Also, I tried 'OneWayToSource' instead of 'OneWay', and all works as expected.
Bind(source, target, BindingMode.OneWayToSource);
target.Attribute = "1";
AssertAreEqual(source.Attribute, "1");
source.Attribute = "foo";
target.Attribute = "2";
AssertAreEqual(source.Attribute, "2");
Other details:
void Bind(TestModel source, TestModel target, BindingMode mode)
{
Binding binding = new Binding();
binding.Source = source;
binding.Path = new PropertyPath(TestModel.AttributeProperty);
binding.Mode = mode;
BindingOperations.SetBinding(target, TestModel.AttributeProperty, binding);
}
class TestModel : DependencyObject
{
public static readonly DependencyProperty AttributeProperty =
DependencyProperty.Register("Attribute", typeof(string), typeof(TestModel), new PropertyMetadata(null));
public string Attribute
{
get { return (string)GetValue(AttributeProperty); }
set { SetValue(AttributeProperty, value); }
}
}
What is wrong with my code?
Setting target.Attribute = "foo"; cleared the binding.
MSDN:
Not only do dynamic resources and
bindings operate at the same
precedence as a local value, they
really are a local value, but with a
value that is deferred. One
consequence of this is that if you
have a dynamic resource or binding in
place for a property value, any local
value that you set subsequently
replaces the dynamic binding or
binding entirely. Even if you call
ClearValue to clear the locally set
value, the dynamic resource or binding
will not be restored. In fact, if you
call ClearValue on a property that has
a dynamic resource or binding in place
(with no "literal" local value), they
are cleared by the ClearValue call
too.
Not a binding expert but I believe you are running into a WPF dependency property precedence issues. It's likely that setting the value directly takes precedence over the binding value. That's why it overrides the binding.
Here's a full dependency property listing: http://msdn.microsoft.com/en-us/library/ms743230.aspx
Example: TextProperty is "Text"
dependency property of TextBox.
Calling these in code should be:
TextBox1.TextProperty="value";
WPF properties can be set two ways:
by invoking DependencyObject.SetValue method (eg. instance.SetValue(TextProperty,"some text"))
or
using CLR Wrapper (eg. instance.Text="some text").
TextBox.TextProperty is a static DependencyProperty object, so you can't assign a string value to a reference type.
If you set Binding Mode to OneWay, this means that the binding works only in one way: the target is updated when the source change.
But the target must be a dependency property, and the code you have is a CLR .NET property. You should set the value on the the target using the registered dependency property name, not just an ordinary .NET property name. The Jared's answer is quite right, this might bring confusion in resolving conflict between WPF dependency property and ordinary .NET CLR property.
If you follow the convention, the dependency property should be in the form of "propertyname"+property.
Example: TextProperty is "Text" dependency property of TextBox. Calling these in code should be:
TextBox1.TextProperty="value";
For more information on setting the source of Binding:
http://msdn.microsoft.com/en-us/library/ms743643.aspx