6

I have just realized I've been coercing binding/dependency properties and not really fundamentally understanding the concept.

Heres the dependency property:

public string Problem
{
    get { return (string)GetValue(ProblemProperty); }
    set { SetValue(ProblemProperty, value); }
}

public static readonly DependencyProperty ProblemProperty =
    DependencyProperty.Register(
    "Problem",
    typeof(string),
    typeof(TextBox));

The XAML is as so:

<TextBlock Text="{Binding Path=Problem}"/>

I'm manually setting the Problem property to a value in the constructor of the object but it doesn't update the TextBlock accordingly . . . any ideas? I've tried Mode="OneWay" and Mode="TwoWay" on the binding and it still doesn't work.

I thought this was supposed to work automatically? Or am i fundamentally getting something wrong?

Thanks

Giffyguy
  • 20,378
  • 34
  • 97
  • 168
Dave
  • 291
  • 1
  • 3
  • 8

6 Answers6

11

The problem your having is definitely related to your DataContext. The {Binding} extension needs to know where the property lives that you are binding to. The default location it looks at is the elements DataContext which by default is always set to the DataContext of it's parent element. If you walk the DataContext up the logical tree to the parent window, The DataContext would be null (because the DataContext of your window is null). Therefore your {Binding} on your textblock is saying "Bind my Text property to the Problem roperty of my DataContext...which is null.

There are a couple of ways to solve this. One would be to do just like Jobi mentioned and set the Element property of you binding to point to the Window where the DependencyProperty is defined like this:

<TextBlock Text="{Binding Path=Problem,ElementName=_window}" />

Another option would be to set the DataContext of your Window to point to itself. That way all the elements contained in it's content will all have the DataContext of the window.

<Window ....
        DataContext="{Binding RelativeSource={RelativeSource Self}}">

Now anytime you need to binding to properties defined in the window (like your Problem dependency property), then you can just do this:

<TextBlock Text="{Binding Problem}" />
Micah
  • 111,873
  • 86
  • 233
  • 325
  • The solution with setting the datacontext of the window it itself does not work for me. It only works when I set the datacontext of an element one level down or more (the first grid works) to the window. Is this expected? – Erik83 Feb 26 '16 at 13:16
2

You can use ElementName Binding here , element will be the Window itself.

<Window x:Class="WpfToolTip.Window1"
x:Name="_window"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <StackPanel>
        <Button Click="OnClick" Content="OK" />
        <Button Click="OnCancel" Content="Cancel" />
        <TextBlock Text="{Binding Path=Problem,ElementName=_window}" />
</StackPanel>

Jobi Joy
  • 49,102
  • 20
  • 108
  • 119
2

try the typeof(object) instead of typeof(string).

Juan Mellado
  • 14,973
  • 5
  • 47
  • 54
panallen
  • 21
  • 1
0

Its a Window this is set in.

public partial class Window1 : Window
{
    public string Problem
    {
        get { return (string)GetValue(ProblemProperty); }
        set { SetValue(ProblemProperty, value); }
    }

    public static readonly DependencyProperty ProblemProperty =
                    DependencyProperty.Register(
                    "Problem",
                    typeof(string),
                    typeof(Window1));


    public Window1()
    {
        InitializeComponent();

        Problem = "ifowiof";
    }

    public void OnClick(object sender, EventArgs e)
    {
        Problem = "behl";
    }

    public void OnCancel(object sender, EventArgs e)
    {
       Problem = "eioeopje";
    }
}

XAML:

<Window x:Class="WpfToolTip.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
        <StackPanel>
            <Button Click="OnClick" Content="OK" />
            <Button Click="OnCancel" Content="Cancel" />
            <TextBlock Text="{Binding Path=Problem}" />
    </StackPanel>
</Window>

It works if I set the RelativeSource like you said when it loads, but if i change the Problem property in code manually (ie. via a button click) it never updates the TextBlock with the new value.

Kent Boogaart
  • 175,602
  • 35
  • 392
  • 393
Dave
  • 291
  • 1
  • 3
  • 8
  • Did you ever find an answer to this? I'm having a similar problem. It seems that the binding is lost when you set the problem property. I'm not sure what the correct procedure is for updating the value this way. – David Turvey Dec 19 '08 at 09:18
0

There are two ways to understand the reason of problem that you described.

At first - you should try to set property changed handler (in dependency property declaration) and put the breakpoint there. You will see whether your property is changing or not.

At second - you should check the type of dependency property owner.

Could you please show full xaml and codebehind?

madcyree
  • 1,427
  • 3
  • 15
  • 28
0

In your code you register the Dependency Property for the class TextBox (last line of quotation).

public static readonly DependencyProperty ProblemProperty =
DependencyProperty.Register(
"Problem",
typeof(string),
typeof(TextBox));

So you can set a value for the ProblemProperty only for textboxes, but I cannot find any textbox in any of the code snippets. You should register your dependency property for the type, to which the value will be assigned, from your sample the right choice is not obvious to me. You could, as Micah does, define it to be a DP of the window, then set the property on your instantiated window. Or you could define it to any named dependency object inside the window, i.e. some object with Name=m_ContentElement, and then set your binding to
{Binding ElementName=m_ContentElement, Path=Problem}
or shorter:
{Binding Problem, ElementName=m_ContentElement}

Simon D.
  • 4,451
  • 2
  • 28
  • 57