1
votes

I have following ListBox in my WPF application:

<ListBox x:Name="Domaci_soupiska" Margin="0" Background="#FFF1DE8A" AllowDrop="True" Drop="Soupiska_D_drop" Grid.Column="1">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <StackPanel Orientation="Horizontal">
                <Label Content="{Binding Typ, Mode=TwoWay}" />
                <local:HracControl Hrac="{Binding Hrac, Mode=TwoWay}"/>
                <TextBox Text="{Binding Cas, Mode=TwoWay}" />
            </StackPanel>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

which ItemsSource is ObservableCollection<SoupiskaRow> where the SoupiskaRow is a simple class:

public class SoupiskaRow
{
    public string Typ { get; set; }
    public Hrac Hrac { get; set; }
    public string Cas { get; set; }
}

and the local:HracControl is a UserControl with dependency property Hrac (pretty much just a storage). However when I add an item to the ObervableCollecion only "default" HracControl is created inside the ListBox - without any data set. Moreover, when I put breakpoint to the set part of Hracdependency property the databinding does not even try to set this property.
The databinding sets the label context or textbox text just fine but I dont understand why it does not even attempt to set a custom property?
I found several threads on similar topic, but they suggested dropping any CustomControls and copy/paste its code into the DataTemplate of ListBox.
Code of HracControl is rather simple:

public Hrac Hrac
    {
        get { return (Hrac)GetValue(HracProperty); }
        set { SetValue(HracProperty, value);}
    }

    public static readonly DependencyProperty HracProperty =
            DependencyProperty.Register("Hrac", typeof(Hrac), typeof(HracControl) , new PropertyMetadata(new Hrac()));

    public HracControl()
    {
        this.InitializeComponent();
        this.DataContext = this;
    }

    public HracControl(Hrac hrac)
    {
        this.InitializeComponent();
        this.Hrac = hrac;
        this.DataContext = this;
    }
//and a methods for reordering/hiding some columns and drag/drop events
}

the inside of xaml:

<Grid x:Name="LayoutRoot">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="1*"/>
...
        </Grid.ColumnDefinitions>
        <Label x:Name="Hrac_ID" Content="{Binding Hrac.Hrac_ID}" HorizontalAlignment="Left" VerticalAlignment="Top"/>
        <Label x:Name="Jmeno" Content="{Binding Hrac.Jmeno}" HorizontalAlignment="Left" VerticalAlignment="Top" Grid.Column="1"/>
...
</Grid>

if you need more code, please let me know in comments

1
You will not see wrapper property setter/getter get called for DependencyProperty. It calls directly GetValue and SetValue. As to your problem do you do something like DataContex = this in your HracControl? - dkozl
Sure, I call DataContex = this; in the constructor. It might be the problem if it call it directly as part of my logic is in the set{}. - wondra
Each FrameworkElement can have only one DataContext. Either inherited through visual tree or set manually. When you set DataContext in control's constructor you change default binding context for control itself and all its children, including <local:HracControl Hrac="{Binding ....}"/>. Post you control code but instead of setting DataContext inside you need to change binding context per binding either via ElementName or RelativeSource binding. Long story short, at the moment you try to bind HracControl.Hrac to HracControl.Hrac - dkozl
DataTemplate would be the simplier smarter choise here unless the custom control is absolutley necessary. can you post the code for local:HracControl? - Omri Btian
@dkozl can you please be more specific how to change it per binding? - wondra

1 Answers

1
votes

As mentioned in the comment each FrameworkElement can have only one DataContext. It will be either inherited through visual tree or set manually.

public HracControl(Hrac hrac)
{
    ...
    this.DataContext = this;
}

By doing this you change default binding context for control itself and all its children, including

<local:HracControl Hrac="{Binding Hrac....}"/>. 

So it will search Hrac in HracControl, so it will try to bind HracControl.Hrac to HracControl.Hrac. Instead of setting DataContext manually in constructor you need to change binding context per binding either via ElementName or RelativeSource binding.

<UserControl ... x:Name="myControl">
    <Grid ...>
        <Label x:Name="Hrac_ID" Content="{Binding ElementName=myControl, Path=Hrac.Hrac_ID}" ... />
        <Label x:Name="Jmeno" Content="{Binding ElementName=myControl, Path=Hrac.Jmeno}" .../>
    </Grid>
</UserControl>