Binding to DependencyObject Properties
I want to pass some objects (of a particular type) to a DependencyProperty in XAML, and have the values of properties on those objects set via bindings.
I've tried a number of methods, but none have worked.
This was my latest attempt:
C#
XAML:
Could you explain why this doesn't work? And perhaps suggest another method to achieve a similar result?
Thanks!
I've tried a number of methods, but none have worked.
This was my latest attempt:
C#
Code: Select all
public class ParameterDependencyObject : DependencyObject
{
public static readonly DependencyProperty KeyProperty =
DependencyProperty.Register(nameof(Key), typeof(string), typeof(ParameterDependencyObject), new PropertyMetadata(null));
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register(nameof(Value), typeof(string), typeof(ParameterDependencyObject), new PropertyMetadata(null));
public string Key
{
get { return (string)GetValue(KeyProperty); }
set { SetValue(KeyProperty, value); }
}
public string Value
{
get { return (string)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
}
[ContentProperty("Parameters")]
public class TextParametersDependencyObject : DependencyObject
{
public ObservableCollection<ParameterDependencyObject> Parameters
{
get { return (ObservableCollection<ParameterDependencyObject>)GetValue(ParametersProperty); }
set { SetValue(ParametersProperty, value); }
}
// Using a DependencyProperty as the backing store for Parameters. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ParametersProperty =
DependencyProperty.Register("Parameters", typeof(ObservableCollection<ParameterDependencyObject>), typeof(TextParametersDependencyObject), new PropertyMetadata(null));
}
Code: Select all
<common:TextContentControl HorizontalAlignment="Center" VerticalAlignment="Center" Style="{StaticResource common_style_hermes_textShadowedNormal1}" Text="((common_txt_tripleInsertionTEST))" >
<!-- TextContentControl has a TextParametersDependencyObject TextFormatParametersProperty -->
<common:TextContentControl.TextFormatParameters>
<viewModels:TextParametersDependencyObject>
<!-- Works fine -->
<viewModels:ParameterDependencyObject Key="Key1" Value="This works"/>
<!-- Error in Unity "StaticResource 'airshipHUD_string_test' not found." -->
<viewModels:ParameterDependencyObject Key="Key2" Value="{StaticResource airshipHUD_string_test}" />
<!-- Error in Unity "StaticResource 'airshipHUD_string_test' not found." -->
<viewModels:ParameterDependencyObject Key="Key3" Value="{Binding CurrentSpeed}" />
</viewModels:TextParametersDependencyObject>
</common:TextContentControl.TextFormatParameters>
</common:TextContentControl>
Thanks!
-
sfernandez
Site Admin
- Posts: 3005
- Joined:
Re: Binding to DependencyObject Properties
It is not working because the items in your collection are not part of the logical tree so resources and bindings can't walk up the tree to resolve the references.
You can use a FreezableCollection that automatically connects its items to the tree:
You can use a FreezableCollection that automatically connects its items to the tree:
Code: Select all
public class ParameterCollection : FreezableCollection<Parameter> { }
[ContentProperty("Parameters")]
public class ParameterList : DependencyObject
{
public ParameterList()
{
Parameters = new ParameterCollection();
}
public ParameterCollection Parameters
{
get { return (ParameterCollection)GetValue(ParametersProperty); }
set { SetValue(ParametersProperty, value); }
}
public static readonly DependencyProperty ParametersProperty = DependencyProperty.Register(
"Parameters", typeof(ParameterCollection), typeof(ParameterList),
new PropertyMetadata(null));
}
public class Parameter : DependencyObject
{
public string Key
{
get { return (string)GetValue(KeyProperty); }
set { SetValue(KeyProperty, value); }
}
public static readonly DependencyProperty KeyProperty = DependencyProperty.Register(
"Key", typeof(string), typeof(Parameter),
new PropertyMetadata(string.Empty));
public string Value
{
get { return (string)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
public static readonly DependencyProperty ValueProperty = DependencyProperty.Register(
"Value", typeof(string), typeof(Parameter),
new PropertyMetadata(string.Empty, OnValueChanged));
private static void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
Parameter param = (Parameter)d;
UnityEngine.Debug.Log($"Key={param.Key}, Value={e.NewValue}");
}
}
Re: Binding to DependencyObject Properties
This is excellent, thank you.
Re: Binding to DependencyObject Properties
Thanks! Marking as solved
Re: Binding to DependencyObject Properties
Hi Jesús and Sergio,
I have just got arround to testing this.. but it only works in dependency properties which add their values to the logical tree, such as ContentControl.Content.
Such as this, where ParameterViewData inherits from FrameworkElement:
Here ParameterViewData becomes part of the logical tree and so {Binding CurrenciesData.Fuel} binds correctly.
However if I define a new dependency property, the value is not added to the logical tree and so the binding fails:
In WPF I could use FrameworkElement.AddLogicalChild(object) to add the ParameterViewData value to the logical tree, which allows the {Binding CurrenciesData.Fuel} binding to work. However Noesis does not implement FrameworkElement.AddLogicalChild(object)/FrameworkElement.RemoveLogicalChild(object).
Will you ever be implementing these methods, or is there another solution to allow this behaviour?
Thanks!
I have just got arround to testing this.. but it only works in dependency properties which add their values to the logical tree, such as ContentControl.Content.
Such as this, where ParameterViewData inherits from FrameworkElement:
Code: Select all
<common:TextContentControl Text="((holdingsScreen_txt_title))">
<common:TextContentControl.Content>
<common:ParameterViewData Key="key2" Value="{Binding CurrenciesData.Fuel}" />
</common:TextContentControl.Content>
</common:TextContentControl>
However if I define a new dependency property, the value is not added to the logical tree and so the binding fails:
Code: Select all
<common:TextContentControl Text="((holdingsScreen_txt_title))">
<common:TextContentControl.TextParameters>
<common:ParameterViewData Key="key2" Value="{Binding CurrenciesData.Fuel}" />
</common:TextContentControl.TextParameters>
</common:TextContentControl>
Code: Select all
private static void OnTextParametersChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is TextContentControl textContentControl)
{
if (e.OldValue != null)
{
textContentControl.RemoveLogicalChild(e.OldValue);
}
if (e.NewValue != null)
{
textContentControl.AddLogicalChild(e.NewValue);
}
}
}
Thanks!
-
sfernandez
Site Admin
- Posts: 3005
- Joined:
Re: Binding to DependencyObject Properties
FrameworkElement AddLogicalChild() and RemoveLogicalChild() is something we should add in a future release, could you please report it in our bugtracker?
In the meantime you can use a Binding with ElementName like this:
In the meantime you can use a Binding with ElementName like this:
Code: Select all
<common:TextContentControl x:Name="textControl" Text="((holdingsScreen_txt_title))">
<common:TextContentControl.TextParameters>
<common:ParameterViewData Key="key2" Value="{Binding DataContext.CurrenciesData.Fuel, ElementName=textControl}" />
</common:TextContentControl.TextParameters>
</common:TextContentControl>
Re: Binding to DependencyObject Properties
Hi guys,
The workaround you provided doesn't work:
I've tired this same pattern in a number of different cases, none of them bind successfully (though the binding is correct).
Static values do work.
Any update on when https://www.noesisengine.com/bugs/view.php?id=1937 will be in?
The workaround you provided doesn't work:
I've tired this same pattern in a number of different cases, none of them bind successfully (though the binding is correct).
Static values do work.
Any update on when https://www.noesisengine.com/bugs/view.php?id=1937 will be in?
-
sfernandez
Site Admin
- Posts: 3005
- Joined:
Re: Binding to DependencyObject Properties
Hi, as the parameter objects are part of a template, to correctly clone them when applying the template they should inherit from Freezable.
I created and attached a small sample that demonstrates this working.
Regarding the bug #1937 I've been doing some tests and the implementation turned to be more complex than expected so we are leaving it for the upcoming major release (due in July before GDC).
I created and attached a small sample that demonstrates this working.
Regarding the bug #1937 I've been doing some tests and the implementation turned to be more complex than expected so we are leaving it for the upcoming major release (due in July before GDC).
- Attachments
-
- ParametersList.unitypackage
- (4.74 KiB) Downloaded 189 times
Who is online
Users browsing this forum: Roms6 and 1 guest