What am I doing wrong? Dependency property inside custom Usercontrol with DataBinding

(Edited to fix DP syntax error - issue still persists)

I am having problems binding data to a Dependency property in a simple custom usercontrol and wondering if some of you experts can tell me where I am going wrong.

Basically, inside my usercontrol, I have a shortcut and two buttons. The label is bound to my Dependency property, and when you click the buttons, the amount increases or decreases depending on the click of the button, and then is displayed by the label.

If I do all this on a page with no user control, everything works correctly. However, as soon as I move it to usercontrol, it starts acting strangely. The initial count of 0 is displayed at the start as expected and when I click the button the revised score is displayed on the first click. However, if I click on the same button again, the dependency property is updated, but the value is not displayed (the label is empty). If I click on another button, the revised score is displayed, but only for the first click - this is all very strange and I'm stuck!

If I put a breakpoint in the 'TheCountProperty_Changed' method, I can check that the property value is updating correctly.

Here's the XAML for my custom control:

<UserControl
x:Class="DPTest.UserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:DPTest"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300"
d:DesignWidth="400"
x:Name="TestControl"
x:Uid="TestControl">

<Grid>
    <TextBlock x:Name="lblCount" HorizontalAlignment="Left" Margin="0,0,0,0" TextWrapping="Wrap" Text="{Binding Path=TheCount, ElementName=TestControl, Mode=OneWay}" VerticalAlignment="Top" FontSize="36"/>
    <Button x:Name="btnLess" Content="&lt;" HorizontalAlignment="Left" Margin="0,71,0,0" VerticalAlignment="Top" Width="75" Click="btnLess_Click" ClickMode="Press"/>
    <Button x:Name="btnMore" Content="&gt;" HorizontalAlignment="Left" Margin="91,71,0,0" VerticalAlignment="Top" Width="75" Click="btnMore_Click" ClickMode="Press"/>

</Grid>

      

And here is the CS for it:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;

namespace DPTest
{
public sealed partial class UserControl1 : UserControl
{
    public static readonly DependencyProperty TheCountProperty = DependencyProperty.Register("TheCount", typeof(int), typeof(UserControl1), new PropertyMetadata(0, new PropertyChangedCallback(TheCountProperty_Changed)));

    public int TheCount
    {
        get { return (int)GetValue(TheCountProperty); }
        set { SetValue(TheCountProperty, value); }
    }
    private static void TheCountProperty_Changed(DependencyObject source, DependencyPropertyChangedEventArgs e)
    {

    }

    public UserControl1()
    {
        this.InitializeComponent();
    }

    private void btnLess_Click(object sender, RoutedEventArgs e)
    {
        //lblCount.Text = (Convert.ToInt32(lblCount.Text) - 1).ToString();
        this.TheCount -= 1;
    }

    private void btnMore_Click(object sender, RoutedEventArgs e)
    {
        //lblCount.Text = (Convert.ToInt32(lblCount.Text) + 1).ToString();
        this.TheCount += 1;
    }
}
}

      

I'm guessing the Databinding syntax is a bit flawed, but what should it be?

(EDIT) - The plot thickens! I just wanted to add that I just tried the same syntax in a standard WPF application and everything works as expected. So I guess the question is, did I find a bug with WinRT / XAML or the syntax is different from that platform?

(Edit # 2 sorry for all the changes, but I'm still trying to figure this out!) I'm starting to believe in a display issue or an error with a control button. I just added an extra button, but didn't hook in any click event code for it or whatever. It's just a button that does nothing. Here's an interesting thing:

  • If I run the test app, click the btnMore button, then TheCount will increase and the Textblock will update as expected. If I then click the same button again, TheCount will increase, but the text value of lblCount becomes an empty string.
  • If, however, I run the test app and click btnMore and then click an unused button and keep repeating this, then the value keeps increasing and the TextBlock will keep updating - unless I hit btnMore twice on the lines, but click an empty button (or just simply focus the cursor on an empty text box or whatever ui thing) then the TextBlock will keep on displaying an increasing number. Second, I click btnMore more than once, then the lblCount value becomes empty string.

It is very strange....

+3


source to share


3 answers


This looks like a sync issue in WinRT. I used a converter to check what I was getting and it seemed like the int value gets null. As soon as I changed the code to asynchronously trigger updates on the property, it started working fine.

XAML:

<UserControl
    x:Class="DPTest.UserControl1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:DPTest"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    d:DesignHeight="300"
    d:DesignWidth="400"
    x:Name="TestControl"
    x:Uid="TestControl">

    <Grid>
        <Grid.Resources>
            <local:IntToStringConverter
                x:Key="IntToStringConverter" />
        </Grid.Resources>
        <TextBlock
            x:Name="lblCount"
            HorizontalAlignment="Left"
            Margin="0,0,0,0"
            TextWrapping="Wrap"
            Text="{Binding Path=TheCount, Converter={StaticResource IntToStringConverter}, ElementName=TestControl, Mode=OneWay}"
            VerticalAlignment="Top"
            FontSize="36" />
        <Button
            x:Name="btnLess"
            Content="&lt;"
            HorizontalAlignment="Left"
            Margin="0,71,0,0"
            VerticalAlignment="Top"
            Width="75"
            Click="btnLess_Click"
            ClickMode="Release" />
        <Button
            x:Name="btnMore"
            Content="&gt;"
            HorizontalAlignment="Left"
            Margin="91,71,0,0"
            VerticalAlignment="Top"
            Width="75"
            Click="btnMore_Click"
            ClickMode="Release" />
    </Grid>
</UserControl>

      



Code behind:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;

namespace DPTest
{
    public sealed partial class UserControl1 : UserControl
    {
        public static readonly DependencyProperty TheCountProperty =
            DependencyProperty.Register(
                "TheCount",
                typeof(int),
                typeof(UserControl1),
                new PropertyMetadata(
                    0,
                    new PropertyChangedCallback(TheCountProperty_Changed)));

        public int TheCount
        {
            get { return (int)GetValue(TheCountProperty); }
            set { SetValue(TheCountProperty, value); }
        }

        private static void TheCountProperty_Changed(DependencyObject source, DependencyPropertyChangedEventArgs e)
        {

        }

        public UserControl1()
        {
            this.InitializeComponent();
        }

        private void btnLess_Click(object sender, RoutedEventArgs e)
        {
            //lblCount.Text = (Convert.ToInt32(lblCount.Text) - 1).ToString();
            this.Dispatcher.InvokeAsync(
                Windows.UI.Core.CoreDispatcherPriority.Low,
                (s, a) => this.TheCount -= 1,
                this,
                null);
        }

        private void btnMore_Click(object sender, RoutedEventArgs e)
        {
            //lblCount.Text = (Convert.ToInt32(lblCount.Text) + 1).ToString();
            this.Dispatcher.InvokeAsync(
                Windows.UI.Core.CoreDispatcherPriority.Low,
                (s, a) => this.TheCount += 1,
                this,
                null);
        }
    }

    public class IntToStringConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, string language)
        {
            return value.ToString();
        }

        public object ConvertBack(object value, Type targetType, object parameter, string language)
        {
            throw new NotImplementedException();
        }
    }

}

      

+1


source


The third argument to DependencyProperty looks like "UserControl1", not "UserControl".

After deploying Win 8 and checking the code for myself, I saw the same problem you have.

From this I was able to determine two things:



1) The dependency property was mostly correct. I could observe the value of increasing and decreasing the property when buttons are pressed. This showed me that the problem was some kind of update issue.

2) Moving the code from UserControl to the main xaml page (in my test app it was the default "Blank.xaml" page) allowed the number to update correctly.

It seems to me that there is some update error with beta (err .. 'user preview) that can be worked around by structuring your application a little differently.

+2


source


I did something very similar by inheriting RichTextBox.

http://www.wpfsharp.com/2011/08/01/loading-a-richtextbox-from-an-rtf-file-using-binding-or-a-richtextfile-control/

I see that I didn't make my dependency property read-only (not sure if this matters)

Also, I assume you intend to fill this in:

private static void TheCountProperty_Changed(DependencyObject source, DependencyPropertyChangedEventArgs e)
{

}

      

0


source







All Articles