ContentProperty and DataContext.
I have a custom control like this:
And I have a framework object like this:
And I set tiers like this:
How do I see the Tiers to the TieredProgressBar's DataContext? I tried doing this:
Code: Select all
[ContentProperty("Tiers")]
public class TieredProgressBar : Control
{
public static readonly DependencyProperty TiersProperty = DependencyProperty.Register("Tiers", typeof(ObservableCollection<Tier>), typeof(TieredProgressBar));
public ObservableCollection<Tier> Tiers
{
get => (ObservableCollection<Tier>)GetValue(TiersProperty);
set => SetValue(TiersProperty, value);
}
}Code: Select all
public class Tier : FrameworkElement
{
public static readonly DependencyProperty ValueProperty = DependencyProperty.Register("Value", typeof(float), typeof(Tier));
public float Value
{
get => (float)GetValue(ValueProperty);
set => SetValue(ValueProperty, value);
}
}Code: Select all
<TieredProgressBar Maximum="10">
<salt:Tier Value="{Binding TotalValue}" />
<salt:Tier Value="2" />
<TieredProgressBar>but the Value bindings still fail. Is there a way to have them set automatically to the TieredProgressBar? Thanks!tier.DataContext = DataContext;
Re: ContentProperty and DataContext.
In order to using bindings in dependency properties, certain conditions must be met. The object must be Freezable (and if it is a collection of objects then the collection must be a FreezableCollection), this allows it to be thread safe. The object must also be part of the logical tree, to allow for dependency values (like DataContext) to be inherited.
To meet the first condition, Freezable, you should have the Tier class inherit from Animatable instead of FrameworkElement. You'll also need the Tiers dependency property to be a FreezableCollection.
For the second requirement, adding the object to the logical tree, this requires the FrameworkElement.AddLogicalChild method, which is not currently exposed in our C# SDK. Adding this functionality is in our roadmap.
What this means is that for now you need to bind the Tier's Value property to a a named element, since they do not inherit the DataContext from the logical tree.
Let me know if you have any questions.
To meet the first condition, Freezable, you should have the Tier class inherit from Animatable instead of FrameworkElement. You'll also need the Tiers dependency property to be a FreezableCollection.
Code: Select all
public class Tier : Animatable
{
public static readonly DependencyProperty ValueProperty = DependencyProperty.Register("Value", typeof(float), typeof(Tier));
public float Value
{
get => (float)GetValue(ValueProperty);
set => SetValue(ValueProperty, value);
}
}
public class TierCollection : FreezableCollection<Tier> { }
[ContentProperty("Tiers")]
public class TieredProgressBar : Control
{
public static readonly DependencyProperty TiersProperty = DependencyProperty.Register("Tiers", typeof(TierCollection), typeof(TieredProgressBar));
public TierCollection Tiers
{
get => (TierCollection)GetValue(TiersProperty);
set => SetValue(TiersProperty, value);
}
}
What this means is that for now you need to bind the Tier's Value property to a a named element, since they do not inherit the DataContext from the logical tree.
Code: Select all
<TieredProgressBar x:Name="TieredProgress" Maximum="10">
<salt:Tier Value="{Binding DataContext.TotalValue, ElementName=TieredProgress}" />
<salt:Tier Value="2" />
<TieredProgressBar>
Re: ContentProperty and DataContext.
Thanks for the info. Which type of FreezeableCollection should I use? It has a protected constructor.
Edit: Oh, I see each type has its own type. I created one for my Tiers and it works, thanks!
Edit: Oh, I see each type has its own type. I created one for my Tiers and it works, thanks!
Re: ContentProperty and DataContext.
Hmm, I am running into an issue where the Tier's Value property isn't being notified of any change. The initial value is being set, but nothing after that.
If I bind to BaseValue outside of the Tier object, the notification works properly.
Code: Select all
public float Value
{
get => (float)GetValue(ValueProperty);
set
{
SetValue(ValueProperty, value); //Breakpoint
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Value"));
}
}Code: Select all
<salt:Tier Value="{Binding ElementName=tiered, Path=DataContext.BaseValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<salt:Tier.Brush>
<SolidColorBrush Color="Green" />
</salt:Tier.Brush>
</salt:Tier>Code: Select all
public int BaseValue
{
get => _baseValue;
set => Set(ref _baseValue, value);
}Re: ContentProperty and DataContext.
I have created an example project to test the bindings, I am not experiencing the same issue. You can download this project here, to check your code against it.
I noticed that you have a PropertyChanged invocation inside of your Value property setting. Dependency properties have property changed functionality built in, this invocation is not needed.
I noticed that you have a PropertyChanged invocation inside of your Value property setting. Dependency properties have property changed functionality built in, this invocation is not needed.
Who is online
Users browsing this forum: Google [Bot] and 7 guests