Travis Pettry Travis Pettry - 7 days ago 5
C# Question

WPF User Control Not Data Binding

In my user control I have a dependency property that is not data binding. I have looked over several stack overflow posts and I cannot figure out what I am doing wrong. The Property changed method is never called. My Code so far:

My user control is basically a enhanced combo box. The DP lives inside of the user control. I am using this user control inside of a Data Grid.

The data context of the user control is set like this.
DataContext={Binding RelativeSource={RelativeSource Self}}

#region ProfileType DP

public static FrameworkPropertyMetadata ProfileTypeMetaData = new FrameworkPropertyMetadata(ProfileTypes.Default,
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault |
FrameworkPropertyMetadataOptions.Journal, new PropertyChangedCallback(ProfileType_PropertyChanged),
new CoerceValueCallback(ProfileType_CoerceValue),
false, UpdateSourceTrigger.PropertyChanged);

public static readonly DependencyProperty ProfileTypeProperty = DependencyProperty.Register(nameof(ProfileType), typeof(ProfileTypes),
typeof(MyClass), ProfileTypeMetaData, new ValidateValueCallback(ProfileType_Validate));

private static void ProfileType_PropertyChanged(DependencyObject dobj, DependencyPropertyChangedEventArgs e)
{
MyClass tp = (MyClass)dobj;
tp.SetUpProfiles();
}

private static object ProfileType_CoerceValue(DependencyObject dobj, object Value)
{
return Value;
}

private static bool ProfileType_Validate(object Value)
{
return true;
}

public ProfileTypes ProfileType
{
get
{
return (ProfileTypes)this.GetValue(ProfileTypeProperty);
}
set
{
this.SetValue(ProfileTypeProperty, value);
}
}

#endregion


In my xaml file I have the following:

<DataGrid ItemsSource="{Binding Missmatches}" CanUserAddRows="False" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Header="Target Profile" Binding="{Binding OldProfile}" />
<DataGridTemplateColumn Header="Mismatched Profile">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Tekla:TeklaProfiles SelectedProfile="{Binding NewProfile}" ProfileType="{Binding Type}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>


The DataGrid is bound to an ObservableCollection. Each object in the collection contains three auto props.

private ObservableCollection<ProfileMismatch> _missmatches;
public ObservableCollection<ProfileMismatch> Missmatches
{
get { return _missmatches; }
set
{
if (_missmatches == value)
return;
_missmatches = value;
RaisePropertyChanged(nameof(Missmatches));
}
}


No matter what I try I cannot seem to get the user control to data bind. If any one has some pro tips please let me know.

Answer

The data context of the user control is set like this. DataContext={Binding RelativeSource={RelativeSource Self}}

Remove that. Explicitly setting a UserControl's DataContext prevents inheriting a DataContext from the control's parent, e.g. here:

<DataTemplate>
    <Tekla:TeklaProfiles SelectedProfile="{Binding NewProfile}"
                         ProfileType="{Binding Type}" />
</DataTemplate>

The bindings are expected to be resolved against the current DataContext, i.e. a view model object with a NewProfile and Type property. However, since you've explicitly set the DataContext of the UserControl (to itself), it won't work.


So just don't explicitly set a UserControl's DataContext. Never. Any blogs or online tutorials telling you so are plain wrong.

Comments