none
[UWP][VB]Temporarily Remove PropertyChangedCallback for DependencyProperty RRS feed

  • Question

  • I have a DependencyProperty for which I have a PropertyChangedCallback. However, this is causing a StackOverflowException. I think that this is because one of the steps in PropertyChangedCallback stack also modifies that property. In this case, it is the following line which sorts the Integers in the property's array:
    Me.Cards = Me.Cards.OrderByDescending(Function(x) x).ToArray()
    So I understand why I am receiving the Exception, but I am not sure how to avoid it. What I would like to do is disable the PropertyChangedCallback immediately before this line, and then reenable it immediately afterwards. Is there a way to do this? If so, what is it? Thanks.

    Nathan Sokalski njsokalski@hotmail.com http://www.nathansokalski.com/

    Monday, July 29, 2019 2:28 AM

Answers

  • I think I found a solution. Instead of setting the ItemsSource property, I am updating the current binding as follows:
    Private Shared Sub CardsChanged(sender As DependencyObject, e As DependencyPropertyChangedEventArgs)
    	Dim itmCards As ItemsControl = CType(CType(CType(sender, PlayerControl).Content, Grid).Children(4), ItemsControl)
    	Try
    		itmCards.SetBinding(ItemsControl.ItemsSourceProperty, itmCards.GetBindingExpression(ItemsControl.ItemsSourceProperty).ParentBinding)
    	Catch ex As NullReferenceException
    	End Try
    End Sub
    This seems to be working (and it is probably what I should have been doing anyway). Thank you for all your help!

    Nathan Sokalski njsokalski@hotmail.com http://www.nathansokalski.com/

    Monday, July 29, 2019 3:40 PM

All replies

  • Hi Nathan,

    Can you provide your full property changed callback code?

    Obviously, you know the cause of the problem, it is the repeated call of the variable. So is it possible to introduce a third temporary variable to temporarily store changes in state values?

    Best regards.

    Monday, July 29, 2019 9:39 AM
  • Here are the different parts of the class.

    The DependencyProperty:

    Public Shared ReadOnly CardsProperty As DependencyProperty = DependencyProperty.Register("Cards", GetType(Integer()), GetType(PlayerControl), New PropertyMetadata(New Integer() {}, AddressOf CardsChanged))
    The property wrapper:
    Public Property Cards As Integer()
    	Get
    		Return CType(GetValue(CardsProperty), Integer())
    	End Get
    	Set(ByVal value As Integer())
    		SetValue(CardsProperty, value)
    	End Set
    End Property
    The code where the DependencyProperty wrapper is called (first line of the Get statement):
    Public ReadOnly Property Sets() As Integer()()
    	Get
    		Me.Cards = Me.Cards.OrderByDescending(Function(x) x).ToArray()
    		Select Case Me.Cards.Length
    			Case 0 : Return {}
    			Case 1 : Return {Me.Cards}
    			Case Else
    				'Indexes of the highest card in each set
    				Dim firstcardindexes As IEnumerable(Of Integer) = Me.Cards.Where(Function(x, index) index = 0 OrElse x + 1 <> Me.Cards(index - 1)).Select(Function(x) Array.IndexOf(Me.Cards, x))
    				'The number of cards in each set
    				Dim setsizes As IEnumerable(Of Integer) = firstcardindexes.Concat({Me.Cards.Count()}).Select(Function(x, index) If(index = 0, 0, x - firstcardindexes(index - 1))).Skip(1)
    				Return firstcardindexes.Select(Function(cardindex, setindex) Me.Cards.Skip(cardindex).Take(setsizes(setindex)).ToArray()).ToArray()
    		End Select
    	End Get
    End Property
    The PropertyValueChanged handler:
    Private Shared Sub CardsChanged(sender As DependencyObject, e As DependencyPropertyChangedEventArgs)
    	Dim itmCards As ItemsControl = CType(CType(CType(sender, PlayerControl).Content, Grid).Children(4), ItemsControl)
    	itmCards.ItemsSource = Nothing
    	itmCards.ItemsSource = CType(sender, PlayerControl).CardSets
    End Sub
    The Property that accesses the Get method of the "Sets" Property:
    Public ReadOnly Property CardSets() As IEnumerable(Of IEnumerable(Of Object))
    	Get
    		Return Me.Sets.Select(Function(currset) currset.Select(Function(cardnum, index) New With {.CardNumber = cardnum, .CardOffset = New Thickness(If(index = 0, 0, -85), 0, 0, 0)}))
    	End Get
    End Property
    The "CardSets" Property is used in binding in XAML, so the binding is the basic start of everything passed through, and then the problem occurs when the "Sets" property repeatedly triggers the PropertyValueChanged handler. I need the PropertyValueChanged handler so that the ItemsControl in my UserControl is updated when the "Cards" Property is changed. What should I do? Thanks.

    Nathan Sokalski njsokalski@hotmail.com http://www.nathansokalski.com/

    Monday, July 29, 2019 3:06 PM
  • I think I found a solution. Instead of setting the ItemsSource property, I am updating the current binding as follows:
    Private Shared Sub CardsChanged(sender As DependencyObject, e As DependencyPropertyChangedEventArgs)
    	Dim itmCards As ItemsControl = CType(CType(CType(sender, PlayerControl).Content, Grid).Children(4), ItemsControl)
    	Try
    		itmCards.SetBinding(ItemsControl.ItemsSourceProperty, itmCards.GetBindingExpression(ItemsControl.ItemsSourceProperty).ParentBinding)
    	Catch ex As NullReferenceException
    	End Try
    End Sub
    This seems to be working (and it is probably what I should have been doing anyway). Thank you for all your help!

    Nathan Sokalski njsokalski@hotmail.com http://www.nathansokalski.com/

    Monday, July 29, 2019 3:40 PM
  • I am very happy that you have solved your problem and your answer will help more people.

    thank you for your support.


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Tuesday, August 13, 2019 5:53 AM