Vegar
Vegar

Reputation: 12898

WPF: Databinding - usercontrol not behaving

I have a little databinding-problem. (I usually have...)

This is the error I get in the output window at runtime:

System.Windows.Data Error: 39 : BindingExpression path error: 'CurrentKlokke' property not found on 'object' ''UIKlokke' (Name='anaKlokke')'. BindingExpression:Path=CurrentKlokke; DataItem='UIKlokke' (Name='anaKlokke'); target element is 'UIKlokke' (Name='anaKlokke'); target property is 'klokke' (type 'Klokke')

'anaKlokke' is a instance of 'UIKlokke', a usercontrol representing an analog clock.

    <UserControl
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:Klokketrening"
        mc:Ignorable="d"
        x:Class="Klokketrening.UIKlokke"
        x:Name="UserControl"
        DataContext="{Binding RelativeSource={RelativeSource self}}"
        d:DesignWidth="400" d:DesignHeight="400">

        <UserControl.Resources>
            <ControlTemplate x:Key="clockTemplate">
                <Grid>
                    <Grid.Resources>
                        <local:TimeTilVinkel x:Key="hourToAngle"/>
                        <local:MinuttTilVinkel x:Key="minuteToAngle"/>
                    </Grid.Resources>
                    <Grid.LayoutTransform>
                        <ScaleTransform ScaleX="2" ScaleY="2" />
                    </Grid.LayoutTransform>
                    <Ellipse Width="108" Height="108" StrokeThickness="3">
                        <Ellipse.Stroke>
                            <LinearGradientBrush>
                                <GradientStop Color="LightBlue" Offset="0" />
                                <GradientStop Color="DarkBlue" Offset="1" />
                            </LinearGradientBrush>
                        </Ellipse.Stroke>
                    </Ellipse>


                    <Canvas Width="102" Height="102">
                        <Ellipse Width="8" Height="8" Fill="Black" Canvas.Top="46" Canvas.Left="46" />
                        <Rectangle x:Name="HourHand" Canvas.Top="26" Canvas.Left="48" Fill="Black" Width="4" Height="25">
                            <Rectangle.RenderTransform>
                                <RotateTransform x:Name="HourHand2" CenterX="2" CenterY="25" Angle="{Binding Converter={StaticResource hourToAngle}}" />                     
                            </Rectangle.RenderTransform>
                        </Rectangle>
                        <Rectangle x:Name="MinuteHand" Canvas.Top="16" Canvas.Left="49" Fill="Black" Width="2" Height="35">
                            <Rectangle.RenderTransform>
                                <RotateTransform CenterX="1" CenterY="35" Angle="{Binding Converter={StaticResource minuteToAngle}}" />
                            </Rectangle.RenderTransform>
                        </Rectangle>
                    </Canvas>
                </Grid>
            </ControlTemplate>
        </UserControl.Resources>
        <Grid>
            <Control Template="{StaticResource clockTemplate}" DataContext="{Binding klokke}" />
        </Grid> 
    </UserControl>

and the code behind:

public partial class UIKlokke
{

    public Klokke klokke
    {
        get {return (Klokke)GetValue(UIKlokke.KlokkeProperty); }
        set { SetValue(UIKlokke.KlokkeProperty, value); } 
    }

    public static readonly DependencyProperty KlokkeProperty;

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

    static UIKlokke()
    {
        UIKlokke.KlokkeProperty = DependencyProperty.Register("klokke", typeof(Klokke), typeof(UIKlokke));
    }
}

Where I use this usercontrol, I want to bind the usercontrols 'klokke'-property to the 'CurrentKlokke' property of an 'Game' object.

<local:UIKlokke x:Name="anaKlokke" Grid.Column="0" Grid.Row="1" klokke="{Binding CurrentKlokke}"/>

CurrentKlokke is a dependencyproperty.

    public Klokke CurrentKlokke
    {
        get { return (Klokke)GetValue(Game.CurrentKlokkeProperty); }
        set { SetValue(Game.CurrentKlokkeProperty, value);  }
    }
    public static readonly DependencyProperty CurrentKlokkeProperty;

    static Game()
    {
        Game.CurrentKlokkeProperty = DependencyProperty.Register("CurrentKlokke", typeof(Klokke), typeof(Game));
    }

I set the DataContext for the grid containing the UIKlokke instance in code:

        _game = new Game(Game.GameLevel.Easy, 10);
        gridGameUI.DataContext = _game;

I'm binding the itemsource of a listbox to another property of the Game object, and it works fine.

Can anybody help me out with this one?

Upvotes: 2

Views: 2542

Answers (2)

bendewey
bendewey

Reputation: 40235

Try removing the Klokke property from the UIKlokke control and bind the anaKlokke object's DataContext to the Klokke directly.

Also, you don't need to have the Control inside the grid inside the usercontrol. You can just use the UserControls.Template:

<UserControl ... DataContext="No needed its set on the game">
  <UserControl.Template>
    <ControlTemplate>
      <Grid>
        <!-- ... -->
      </Grid>
    </ControlTemplate>
  </UserControl.Template>
</UserControl>

This way the DataContext is set right throught directly to the UserControl

If you need to access the Klokke in the code-behind you can use

var klokke = DataContext as Klokke;
if (klokke == null) return;

// use klokke

Upvotes: 2

Anthony Brien
Anthony Brien

Reputation: 6166

Not sure about this, I'm just starting with WPF. But shouldn't you use Path in your binding like this:

<local:UIKlokke x:Name="anaKlokke"  
                Grid.Column="0" Grid.Row="1" 
                klokke="{Binding Path=CurrentKlokke}"/>

Upvotes: 0

Related Questions