Adding an ExceptionValidationRule to a Binding in code - wpf

I have been developing an ErrorProvider control that inherits from Decorator. It validates any elements within the control that are bound to something. It loops through every binding and within a FrameworkElement and adds an ExceptionValidationRule as well as a DataErrorValidation to the binding's ValidationRules.
This is the method that does the work:
Private Sub ApplyValidationRulesToBindings()
Dim bindings As Dictionary(Of FrameworkElement, List(Of Binding)) = GetBindings()
For Each felement In bindings.Keys
Dim knownBindings As List(Of Binding) = bindings(felement)
For Each knownBinding As Binding In knownBindings
'Applying Exception and Data Error validation rules'
knownBinding.ValidationRules.Add(New ExceptionValidationRule())
knownBinding.ValidationRules.Add(New DataErrorValidationRule())
Next
Next
End Sub
Apparently the DataErrorValidationRule is applied to the binding, but the ExceptionValidationRule is not.
Does anyone know why this might be the case?
Edit:
Ok, so a little more info on the problem.
I've been reading tons of MSDN documentation on Validation and the Binding class. The Binding.UpdateSourceExceptionFilter Property allows you to specify a function that handles any exceptions that occur on a binding if an ExceptionValidationRule has been associated with the Binding.
I added a method for the UpdateSourceExceptionFilter Property and guess what! It was executed. BUT!! Even though I returned the exception, a ValidationError object was NOT added to Validation.Errors collection of the bound element even though the MSDN documentation said that it would be...
I commented out the code that adds the ExceptionValidationRule dynamically and manually added one to the Binding in XAML like so:
<TextBox HorizontalAlignment="Left" Name="TextBox1" VerticalAlignment="Top"
Width="200">
<TextBox.Text>
<Binding Path="Name">
<Binding.ValidationRules>
<ExceptionValidationRule />
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
The UpdateSourceException method was executed (I didn't change it) and the error was added to the Validation.Errors as the MSDN stated.
What is curious about this whole thing is the fact that the ExceptionValidationRule is in fact added to the binding when done through the VB.NET code (or else the the UpdateSourceException would never have executed); however, the Validate.Errors is not updated with the error.
As I stated earlier, the DataErrorValidationRule is added to the binding and works properly...I'm just having problems with the ExceptionValidationRule.
My Solution:
It turns out that I had to call the BindingOperations.SetBinding Method for the binding and the property to apply the validation rules to the binding. I had no way of retrieving the DependencyProperty that for the element/binding in my ApplyValidationRulesToBindings method so I moved the code that applied rules to the call back method provided my method that retrieves all of the bindings recursively.
Here is my solution:
''' <summary>'
''' Gets and returns a list of all bindings. '
''' </summary>'
''' <returns>A list of all known bindings.</returns>'
Private Function GetBindings() As Dictionary(Of FrameworkElement, List(Of Binding))
If _bindings Is Nothing OrElse _bindings.Count = 0 Then
_bindings = New Dictionary(Of FrameworkElement, List(Of Binding))
FindBindingsRecursively(Me.Parent, AddressOf RetrieveBindings)
End If
Return _bindings
End Function
''' <summary>'
''' Recursively goes through the control tree, looking for bindings on the current data context.'
''' </summary>'
''' <param name="element">The root element to start searching at.</param>'
''' <param name="callbackDelegate">A delegate called when a binding if found.</param>'
Private Sub FindBindingsRecursively(ByVal element As DependencyObject, ByVal callbackDelegate As FoundBindingCallbackDelegate)
' See if we should display the errors on this element'
Dim members As MemberInfo() = element.[GetType]().GetMembers(BindingFlags.[Static] Or BindingFlags.[Public] Or BindingFlags.FlattenHierarchy)
For Each member As MemberInfo In members
Dim dp As DependencyProperty = Nothing
' Check to see if the field or property we were given is a dependency property'
If member.MemberType = MemberTypes.Field Then
Dim field As FieldInfo = DirectCast(member, FieldInfo)
If GetType(DependencyProperty).IsAssignableFrom(field.FieldType) Then
dp = DirectCast(field.GetValue(element), DependencyProperty)
End If
ElseIf member.MemberType = MemberTypes.[Property] Then
Dim prop As PropertyInfo = DirectCast(member, PropertyInfo)
If GetType(DependencyProperty).IsAssignableFrom(prop.PropertyType) Then
dp = DirectCast(prop.GetValue(element, Nothing), DependencyProperty)
End If
End If
If dp IsNot Nothing Then
' we have a dependency property. '
'Checking if it has a binding and if so, checking if it is bound to the property we are interested in'
Dim bb As Binding = BindingOperations.GetBinding(element, dp)
If bb IsNot Nothing Then
' This element has a DependencyProperty that we know of that is bound to the property we are interested in. '
' Passing the information to the call back method so that the caller can handle it.'
If TypeOf element Is FrameworkElement Then
If Me.DataContext IsNot Nothing AndAlso DirectCast(element, FrameworkElement).DataContext IsNot Nothing Then
callbackDelegate(DirectCast(element, FrameworkElement), bb, dp)
End If
End If
End If
End If
Next
'Recursing through any child elements'
If TypeOf element Is FrameworkElement OrElse TypeOf element Is FrameworkContentElement Then
For Each childElement As Object In LogicalTreeHelper.GetChildren(element)
If TypeOf childElement Is DependencyObject Then
FindBindingsRecursively(DirectCast(childElement, DependencyObject), callbackDelegate)
End If
Next
End If
End Sub
''' <summary>'
''' Called when recursively populating the Bindings dictionary with FrameworkElements(key) and their corresponding list of Bindings(value)'
''' </summary>'
''' <param name="element">The element the binding belongs to</param>'
''' <param name="binding">The Binding that belongs to the element</param>'
''' <param name="dp">The DependencyProperty that the binding is bound to</param>'
''' <remarks></remarks>'
Sub RetrieveBindings(ByVal element As FrameworkElement, ByVal binding As Binding, ByVal dp As DependencyProperty)
'Applying an exception validation and data error validation rules to the binding'
'to ensure that validation occurs for the element'
If binding.ValidationRules.ToList.Find(Function(x) GetType(ExceptionValidationRule) Is (x.GetType)) Is Nothing Then
binding.ValidationRules.Add(New ExceptionValidationRule())
binding.ValidationRules.Add(New DataErrorValidationRule())
binding.UpdateSourceExceptionFilter = New UpdateSourceExceptionFilterCallback(AddressOf ReturnExceptionHandler)
'Resetting the binding to include the validation rules just added'
BindingOperations.SetBinding(element, dp, binding)
End If
' Remember this bound element. This is used to display error messages for each property.'
If _bindings.ContainsKey(element) Then
DirectCast(_bindings(element), List(Of Binding)).Add(binding)
Else
_bindings.Add(element, New List(Of Binding)({binding}))
End If
End Sub
Thanks!
-Frinny

I'm not really following how your code works but you can't modify a Binding after it has been used, so you can't add ValidationRules to an existing Binding. I think you'll have to copy the Binding, Property for Property and then add the ValidationRules and then set the new copied Binding with BindingOperations.SetBinding(...).
Another approach may be to create your own subclassed Binding where you add the ValidationRules directly e.g
public class ExBinding : Binding
{
public ExBinding()
{
NotifyOnValidationError = true;
ValidationRules.Add(new ExceptionValidationRule());
ValidationRules.Add(new DataErrorValidationRule());
}
}
Useable like
<TextBox Text="{local:ExBinding Path=MyProperty}"/>
Update
I don't think you understood my answer. You can't modify a Binding once it is in use so what you're trying to do won't work. Here's a C# sample app that shows this. It contains three TextBoxs where
First TextBox adds the Binding with the ExceptionValidationRule in Xaml
Second TextBox adds the Binding in Xaml and adds the ExceptionValidationRule in its Loaded event
Third TextBox adds the Binding with the ExceptionValidationRule in the Loaded event
The ExceptionValidationRule will work for TextBox 1 and 3 but not for 2. Uploaded the sample here: http://www.mediafire.com/?venm09dy66q4rmq
Update 2
You could get this to work if you set the Binding again after you've added the Validation Rule like
BindingExpression bindingExpression = textBox.GetBindingExpression(TextBox.TextProperty);
Binding textBinding = bindingExpression.ParentBinding;
textBinding.ValidationRules.Add(new ExceptionValidationRule());
// Set the Binding again after the `ExceptionValidationRule` has been added
BindingOperations.SetBinding(textBox, TextBox.TextProperty, textBinding);
I'm not sure how your GetBindings method look, but maybe you could add a SetBindings method where you set the Bindings again and call that method after you've added the ExceptionValidationRules

Related

WPF: Design time support for dependency properties with default values

I have written a custom control based on a ListBox. It contains a default ItemTemplate which shows an image given to the ListBox by a custom dependency property. The control also contains a default image, which is used when the user doesn't give an image to the dependency property.
This works so far, but now I've found a little problem and I don't know how to fix that.
When I use my custom control in the XAML designer, it first shows the default image. When I set the image's dependency property to an other image, the new image is immediately shown in the XAML designer.
But when I remove the XAML attribute for the new image again, the XAML designer only shows a white rectangle instead of the default image.
I assume it's because with setting the image's dependency property to some value and then removing it I nulled the value. But even when I check for null in the CoerceCallback and give back the default image when the coerced value is null, doesn't work.
What's the best way to support fallback values for dependency properties?
TestControl.vb
Public Class TestControl
Inherits ListBox
Private Shared _defaultResources As ResourceDictionary
Shared Sub New()
_defaultResources = New ResourceDictionary
_defaultResources.Source = New Uri("...")
End Sub
Public Shared ReadOnly TestProperty As DependencyProperty = DependencyProperty.Register(NameOf(TestControl.Test),
GetType(ImageSource),
GetType(TestControl),
New FrameworkPropertyMetadata(Nothing,
AddressOf TestControl.OnTestChanged,
AddressOf TestControl.OnTestCoerce))
Public Property Test As ImageSource
Get
Return DirectCast(MyBase.GetValue(TestControl.TestProperty), ImageSource)
End Get
Set(value As ImageSource)
MyBase.SetValue(TestControl.TestProperty, value)
End Set
End Property
Private Shared Sub OnTestChanged(d As DependencyObject, e As DependencyPropertyChangedEventArgs)
End Sub
Private Shared Function OnTestCoerce(d As DependencyObject, value As Object) As Object
If (value Is Nothing) Then
Return TryCast(_defaultResources.Item("TestImage"), ImageSource)
End If
Return value
End Function
Public Sub New()
Me.Test = TryCast(_defaultResources.Item("TestImage"), ImageSource)
End Sub
End Class
When I use that control like this
<local:TestControl ItemsSource="{Binding Items}" />
every item shows the default image at design time. When I change the XAML to
<local:TestControl ItemsSource="{Binding Items}"
Test="{StaticResource NewImage}" />
every item shows the new item at design time. But when I remove the Test="{StaticResource NewImage}" again, it doesn't go back to the default image.
Ok, after some testing (using this technique) I have discovered the source of your issue.
First of all, you are not using PropertyMetadata to set your default value, but instead the constructor. I assume you have a good reason to do so, but this essentially means that now you are relying on the coercion callback to set the default value.
However, it is not called (the framework assumes that your "true" default value - Nothing - doesn't need to be validated) after you remove the
Test="{StaticResource TestString}" line. Only the OnTestChanged
is called. This means we can use it to restore the default value:
void OnTestChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (e.NewValue is null)
{
((TestControl)d).Test = yourDefaultImage;
return;
}
//Actual "OnChanged" code
}
A clumsy solution indeed, but it works. Depending on your exact situation, you might also want to take a look at Binding's FallbackValue and TargetNullValue properties:
Test="{Binding Source={ }, FallbackValue={ }, TargetNullValue={ }}"

WPF INotifyErrorInfo Validation.Error Event Not Raising

I'm encountering a strange problem. Despite setting everything correctly, the Validation.Error doesn't get fired.
Here are the details:
<DataTemplate x:Key="dtLateComers">
<TextBox Text="{Binding ParticipantTag, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True, NotifyOnValidationError=True, NotifyOnSourceUpdated=True}" Validation.Error="Validation_Error" >
</DataTemplate>
Code behind (VB.Net) to set ItemsSource of HeaderedItemsControl:
hicLateComers.ItemsSource = _LateComersViewModels
_LateComersViewModels is ObservableCollection(Of ParticipantViewModel)
Implementation of ParticipantViewMode:
Public Class ParticipantViewModel
Implements INotifyPropertyChanged, IDataErrorInfo
Private _ParticipantTag As String = ""
Public Property ParticipantTag() As String
Get
Return _ParticipantTag
End Get
Set(ByVal value As String)
_ParticipantTag = value
_ParticipantTag= _ParticipantTag.ToUpper
NotifyPropertyChanged("ParticipantTag")
End Set
End Property
Public ReadOnly Property Item(byVal columnName As String) As String Implements IDataErrorInfo.Item
Get
Dim errorString As String = String.Empty
If columnName.Equals("ParticipantTag") Then
If not ParticipantValidationManager.IsValidKeypadTag(_ParticipantTag, True) then
errorString = "Incorrect entry. Please try again."
End If
End If
Return errorString
End Get
End Property
Public ReadOnly Property [Error] As String Implements IDataErrorInfo.Error
Get
Throw New NotImplementedException()
End Get
End Property
End Class
Problem
When I set ItemSource property (as mentioned above in code), Item index is called as many times as there are items in _LaterComersViewModels. Validation works and as a result I get red circle next to TextBox. However, Validation_Error never gets fired until I start typing in Textbox. Typing in TextBox changes the Property binds to it and validate it. Base on validation Validation.Error event is raised, and handled by application. Within that event handler I maintain a count of errors.
So the Question is, why Validation.Error doesn't get raised when one/more items fail on a validation rule during initial data binding? Though it does get raised once property is changed by typing into that TextBox.
Feel free to share any idea, assumption or a solution. Any type of help will be appreciated. Thanks.
Side note: I've a simple C# application which doesn't use data templating. In that application, Validation.Error event gets raised perfectly on start, and on property change. Though in that application, Model is binding to DataContext property of Grid.
Since Validation.Error is an attached event, you could hook up the event handler on the HeaderedItemsControl:
<HeaderedItemsControl x:Name="hicLateComers" ItemTemplate="{StaticResource dtLateComers}" Validation.Error="Validation_Error" />
The result should be pretty much the same since you can easily access both the TextBox and the ParticipantViewModel object in the event handler:
Private Sub Validation_Error(sender As Object, e As ValidationErrorEventArgs)
Dim textBox = CType(e.OriginalSource, TextBox)
Dim participant = CType(textBox.DataContext, ParticipantViewModel)
'...
End Sub

Converting normal property to dependency property

I have a control that I am using for my new application. This control has a regular property as such.
Public Property Value() As String
Get
If AutoCompleteTextBox.SearchText Is Nothing Then
Return String.Empty
Else
Return AutoCompleteTextBox.SearchText.ToString.Trim
End If
End Get
Set(value As String)
AutoCompleteTextBox.SearchText = value
End Set
End Property
Edit:
So, after multiple tries, I am finally at this stage.
Public Shared ValueProperty As DependencyProperty = DependencyProperty.Register("Value", GetType(String), GetType(AutoCompleteBox))
Public Property Value() As String
Get
Return Me.GetValue(ValueProperty).ToString
End Get
Set(value As String)
Me.SetValue(ValueProperty, value)
End Set
End Property
Public Event PropertyChanged As PropertyChangedEventHandler _
Implements INotifyPropertyChanged.PropertyChanged
This is the dependency property. This property is still not binding. No errors are shown in output window for binding.
Text="{Binding RelativeSource={RelativeSource Self}, Path=Value, Mode=TwoWay}"
This is my binding method. I have no idea what else I can do. At least if there was an error, I could have figured out something. Without any error, I am just a headless chicken here.
Please refer to the following url for all the dependency fundamentals
http://www.wpftutorial.net/dependencyproperties.html
Basically, you can get a property changed event of dependency property by providing a FrameworkPropertyMetadata.
new FrameworkPropertyMetadata( [Default Value],
OnCurrentTimePropertyChanged);
And you can get back the target control (DependencyObject) at the event handler and implement your logic over there
private static void OnCurrentTimePropertyChanged(DependencyObject source,
DependencyPropertyChangedEventArgs e)
{
AutoCompleteTextBox control = source as AutoCompleteTextBox;
string time = (string)e.NewValue;
// Put some update logic here...
}
Declaring a dependency property in a control is a good thing.
You could make some binding in the xaml (sorry I don't have your XAML - I imagine).
Something like :
<TextBox x:Name="AutoCompleteTextBox"
Text="{Binding RelativeSource={RelativeSource=Self},Path=Value}"/>
Regards
TextBox has a property called Text. When you access Text property it will give you text entered in TextBox. Same is your case. Now why you want to convert it into a DP ? A DP would be useful if you want o bind this DP to some other control.
Extend this control itself. Make a new control and introduce this new DP.
While a DP is used where you want to bind this property to some control. This property then gets updated from control or control gets updated from this DP depending upon binding mode set.
How to do binding :
<TextBox x:Name="UserInput" />
<uc:MyAutoCompleteTextBox ValueDP="{Binding Text, ElementName=UserInput, Mode=OneWay}" />
MyAutoCompleteTextBox is new control which extends(inherits) from your old AutoComplete control.
If you want to apply some filtering logic or anything else, you can apply it in your DP itself like this :
Get
someVariable = TryCast(Me.GetValue(ValueProperty), String)
' apply somg logic to someVariable
' use your old Value property from here
Return someVariable
End Get
There are many WPF Binding tutorials on net.
I recommend :
http://blog.scottlogic.com/2012/04/05/everything-you-wanted-to-know-about-databinding-in-wpf-silverlight-and-wp7-part-one.html
Just change your code with following code and you should be good
your code
Public Shared ReadOnly ValueProperty As DependencyProperty = DependencyProperty.Register("Value", GetType(String), GetType(AutoCompleteBox))
Public Property Value() As String
Get
Return TryCast(Me.GetValue(ValueProperty), String)
End Get
Set(value As String)
Me.SetValue(ValueProperty, value)
End Set
End Property
New code
Public Shared ReadOnly ValueProperty As DependencyProperty = DependencyProperty.Register("Value", GetType(String), GetType(AutoCompleteBox))
Public Property Value() As String
Get
If AutoCompleteTextBox.SearchText Is Nothing Then
Return String.Empty
Else
Return AutoCompleteTextBox.SearchText.ToString.Trim
End If
End Get
Set(value As String)
AutoCompleteTextBox.SearchText = value
End Set
End Property
This DP will do what your Older property was doing. But just think about your requirement there can be a better way of writing the things.
Thanks

OnVisualChildrenChanged is called before dependency properties are set

I have created a custom control (CartesianCanvas) that stores some of the properties of any child element when it is added. To do this I have created a new collection property(ItemsInfo) and overrode OnVisualChildrenChanged so that when a child is added or removed the corresponding properties are added or removed from the collection property.
However, when I add children to the control through XAML, OnVisualChildrenChanged seemes to be called before the properties have been set as all the properties have their default values. This is not the case when a child is added after the window has been loaded. How can I ensure that the child's properties have been set when OnVisualChildrenChanged is called?
Here is my code:
Public ReadOnly Property ItemsInfo As Collection(Of CartesianInfo)
Get
Return DirectCast(GetValue(ItemsInfoProperty), Collection(Of CartesianInfo))
End Get
End Property
Friend Shared ReadOnly ItemsInfoKey As System.Windows.DependencyPropertyKey = System.Windows.DependencyProperty.RegisterReadOnly("ItemsInfo", GetType(Collection(Of CartesianInfo)), GetType(CartesianCanvas), New System.Windows.PropertyMetadata(New Collection(Of CartesianInfo)))
Public Shared ReadOnly ItemsInfoProperty As DependencyProperty = ItemsInfoKey.DependencyProperty
Protected Overrides Sub OnVisualChildrenChanged(visualAdded As DependencyObject, visualRemoved As DependencyObject)
Try
If Not visualAdded Is Nothing Then
If Not GetType(FrameworkElement).IsAssignableFrom(visualAdded.GetType) Then
Me.Children.Remove(visualAdded)
Throw New Exception("The object added:" & visualAdded.ToString & " was not of type or decended from: FrameworkElement and so was removed from CartesianCanvas")
Else
AddItemInfo(visualAdded)
End If
End If
Catch ex As Exception
Console.WriteLine(ex.Message)
End Try
If Not visualRemoved Is Nothing Then
RemoveItemInfo(visualRemoved)
End If
MyBase.OnVisualChildrenChanged(visualAdded, visualRemoved)
End Sub
Private Sub AddItemInfo(ByRef item As FrameworkElement)
Dim itemsInfoCollection As New Collection(Of CartesianInfo)
itemsInfoCollection = ItemsInfo
Dim ItemXCoordinate As Double
Dim ItemYCoordinate As Double
Dim ItemCalculateFromVerticalCenter As Boolean
Dim ItemCalculateFromHorizontalCenter As Boolean
If Double.IsNaN(Canvas.GetLeft(item)) Then
Canvas.SetLeft(item, 0)
End If
If Double.IsNaN(Canvas.GetTop(item)) Then
Canvas.SetTop(item, 0)
End If
ItemXCoordinate = Canvas.GetLeft(item)
ItemYCoordinate = Canvas.GetTop(item)
If item.VerticalAlignment = Windows.VerticalAlignment.Center Then
ItemCalculateFromVerticalCenter = True
End If
If item.HorizontalAlignment = Windows.HorizontalAlignment.Center Then
ItemCalculateFromHorizontalCenter = True
End If
ItemsInfo.Add(New CartesianInfo(item, ItemXCoordinate, ItemYCoordinate, ItemCalculateFromVerticalCenter, ItemCalculateFromHorizontalCenter))
SetValue(ItemsInfoKey, ItemsInfo)
PositionChild(item)
End Sub
Here is my XAML
<local:CartesianCanvas x:Name="MainCanvas">
<Button Width="50" Height="100" Canvas.Top="100" Canvas.Left="20"
Content="test" Click="Button_Click"/>
</local:CartesianCanvas>
WPF is pretty complicated especially when writing custom controls therefore my first suggestion would be - leave it. Take an already existing control or composite few already existing controls into UserControl instead of writing everything from scratch.
Controls in WPF may contain any other control and the control's children are loaded only when needed. That is why you run into your problem.
The solution is when OnVisualChildrenChanged event fires, you should run through all children and subscribe to their Initialized or Loaded event. Once the child is loaded the event will fire and the handler will be called. Furthermore inside the handler you shouldn't forget to unsubscribe to the event.

Binding from multiple sources

My scenario:
I've got a Silverlight Application with a View, where i want to bind the textboxes to an object (two-way) and all labels to a dictionary holding the label translations.
My approach was to set the datacontext of the page to a dictionary with two items, one of them is the object and the other is the translation-dictionary.
In xaml the code looks like the following:
<TextBlock Text="{Binding [dict].[name],FallbackValue='Fallback'}" />
<TextBox Text="{Binding [obj].name,Mode=TwoWay}" />
This works initially, if I however change the object on the datacontext, the xaml is not notified about any changes and doesn't update.
I've had a working solution using a Converter for the translations, however due to the limitations on one converterparameter I didn't like the solution. In addition it wasn't possible to place a fallback-value in the textblock, which resulted in "invisible" textblocks while designing the page.
Any suggestions on how to solve this issue? It doesn't have to be using my dictionary, it would be also okay if i could set the datacontext to the object (which works) and bind the labels somehow different.
I know this will get a lot of traditional answers, but I would also like to put forward something completely original we tried (and succeeded) doing ourselves for more efficient localisation of Silverlight using Attached Properties instead of binding:
Localisation of Silverlight projects after completion
What would be the most flexible is rather than setting the DataContext for the view to a dictionary, you would be better off having the DataContext be something like a ViewModel. That is, a simple class that holds multiple properties: one for your "object" and one for your translation dictionary.
Then have the class that acts as your ViewModel implement INotifyPropertyChanged.
Create a method in your class called OnPropertyChanged that takes in a string representing your property name. In that method raise the PropertyChanged event passing in the instance of the ViewModel class and a new PropertyChangedEventArgs passing in the property name.
Back in the properties you created (object and dictionary) in the Set, after setting the value, call OnPropertyChanged passing in the string name of that property. This will notify the UI that the value of this property has changed and will essentially rebind the control to that property.
Finally, bind the Text properties of your controls on your View to the new properties you just created in your ViewModel. That should ensure that the controls on the view stay up to date.
I found a solution, but wasn't able to answer my own question (8h limit..)
I think this is just the approach Hydroslide suggested.
Create a class which holds all data and implements INotifyPropertyChanged
Public Class MyDatacontext
Implements ComponentModel.INotifyPropertyChanged
'Properties
Private _obj As Object
Private _dict As Dictionary(Of String, String)
'Events
Public Event PropertyChanged(ByVal sender As Object, ByVal e As System.ComponentModel.PropertyChangedEventArgs) Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged
'Methods
Public Property Obj As Object
Get
Return _obj
End Get
Set(ByVal value As Object)
_obj = value
'Notify the xaml about the changed Object
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("Obj"))
End Set
End Property
Public Property Dict As Dictionary(Of String, String)
Get
Return _dict
End Get
Set(ByVal value As Dictionary(Of String, String))
_dict = value
'Notify the xaml about the changed translation
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("Dict"))
End Set
End Property
End Class
Define a private var in your page code
Private mycontext As New MyDatacontext
In the constructor of your page, fill your "mycontext" with the desired data
mycontext.Dict = LoadDictionary()
mycontext.Obj = LoadObject()
Me.DataContext = mycontext
Change your xaml to the following
<TextBlock Text="{Binding Dict.[name],FallbackValue=MyFallback}" />
<TextBox Text="{Binding Obj.name,Mode=TwoWay}" />
Update your object/dictionary as you like using
mycontext.Obj = LoadNextObject()

Resources