I am having trouble databinding a TextBox.Text
property to a object's method. The idea is allowing the user to write in a TextBox
a file name and then have a TextBlock
output that file's extension.
class GetFileInfo
{
public string GetFileExtension(string fileName)
{
return Path.GetExtension(fileName);
}
}
Here is my XAML:
<Window.Resources>
<ObjectDataProvider x:Key="getFileInfo" MethodName="GetFileExtension" ObjectType="{x:Type local:GetFileInfo}">
<ObjectDataProvider.MethodParameters>
<sys:String>abc.text</sys:String>
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
</Window.Resources>
<StackPanel>
<TextBox Name="textBox1">
<TextBox.Text>
<Binding Source="{StaticResource getFileInfo}" Path="MethodParameters[0]" BindsDirectlyToSource="True" UpdateSourceTrigger="PropertyChanged" />
</TextBox.Text>
</TextBox>
<TextBlock Name="textBlock1" Text="{Binding Source={StaticResource getFileInfo}}"/>
</StackPanel>
For some reason it is not doing anything. Anyknow could point out what may be the reasons?
Here is what I see on the designer and when I run the application:
And here is what happens when I try setting other text at run-time:
Here is the error given by de debugger when trying to set other text at run-time:
System.Windows.Data Error: 8 : Cannot save value from target back to source. BindingExpression:Path=MethodParameters[0]; DataItem='ObjectDataProvider' (HashCode=2207369); target element is 'TextBox' (Name='textBox1'); target property is 'Text' (type 'String') ArgumentException:'System.ArgumentException: Object of type 'MS.Internal.Data.PropertyPathWorker+IListIndexerArg' cannot be converted to type 'System.Int32'.
at System.RuntimeType.TryChangeType(Object value, Binder binder, CultureInfo culture, Boolean needsSpecialCast)
at System.RuntimeType.CheckValue(Object value, Binder binder, CultureInfo culture, BindingFlags invokeAttr)
at System.Reflection.MethodBase.CheckArguments(Object[] parameters, Binder binder, BindingFlags invokeAttr, CultureInfo culture, Signature sig)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, Boolean skipVisibilityChecks)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at System.Reflection.RuntimePropertyInfo.SetValue(Object obj, Object value, BindingFlags invokeAttr, Binder binder, Object[] index, CultureInfo culture)
at MS.Internal.Data.PropertyPathWorker.SetValue(Object item, Object value)
at MS.Internal.Data.ClrBindingWorker.UpdateValue(Object value)
at System.Windows.Data.BindingExpression.UpdateSource(Object value)'
Best Answer
While it's possible to use
Binding
to call a method and get its return value, it's not straightforward. It's much simpler to bind to properties, and to use the combination of binding and change notification to get the result you're looking for.Create a class with two properties,
Filename
andExtension
.Filename
is just a read/write string property.Extension
is a read-only string property whose getter calls the method that you're trying to call.Now make that class implement
INotifyPropertyChanged
, because if a property can change in code, it needs a way of telling the binding that it has done so. Make the setter of theFilename
property notify bindings that theExtension
property has changed.Add a
Binding
to aTextBox
that binds to theFilename
property using theTwoWay
mode. Add aBinding
to aTextBox
that binds toExtension
using the defaultOneWay
mode.The sequence of events is:
Filename
into a boundTextBox
and presses TAB.TextBox
loses focus.Binding
's mode isTwoWay
, and it's using the default behavior of updating the source when the target loses focus, that's what it does.Binding
updates the source by calling theFilename
setter.Filename
setter raisesPropertyChanged
.Binding
handlesPropertyChanged
, looks at its argument, and sees that theExtension
property has changed.Binding
calls theExtension
property's getter.Extension
property's getter calls the method to determine the extension forFilename
, and returns it to theBinding
.Binding
updates its targetTextBox
with the new value ofExtension
.This is the core concept underlying data binding and the MVVM pattern. Once you understand it, it becomes second nature, and WPF development becomes about ten million times easier.