Hi!
If i remove some property definition at runtime on code behind, then all other definition is only readonly on UI. I debugging the property definition list, but show is readonly = false after remove items, however UI is disabled.
The removed item is properly removed from UI.
What the problem?
This code using to remove:
EditProperty.PropertyDefinitions.RemoveRange(EditProperty.PropertyDefinitions.Where(x => x.OrderIndex == 500).ToList());
Usage:
[System.ComponentModel.DataAnnotations.Range(0, 2)]
//[Display(...)]
public
int
UpperLabelColumn
{
get
{
return
_upperLabelColumn; }
set
{ Set(() => UpperLabelColumn,
ref
_upperLabelColumn, value); }
}
In XAML:
<
DataTemplate
>
<
t:RadNumericUpDown
t:AutoBindBehavior.UpdateBindingOnElementLoaded
=
"Value"
IsInteger
=
"True"
>
<
i:Interaction.Behaviors
>
<
bs:RadNumericUpDownAttributeBehavior
/>
</
i:Interaction.Behaviors
>
</
t:RadNumericUpDown
>
</
DataTemplate
>
Implementation:
public
class
RadNumericUpDownAttributeBehavior : Behavior<RadNumericUpDown>
{
protected
override
void
OnAttached()
{
AssociatedObject.Loaded += OnLoaded;
AssociatedObject.DataContextChanged += OnDataContextChanged;
}
protected
override
void
OnDetaching()
{
AssociatedObject.Loaded -= OnLoaded;
AssociatedObject.DataContextChanged -= OnDataContextChanged;
}
private
void
OnLoaded(
object
sender, RoutedEventArgs e)
{
UpdateBinding((RadNumericUpDown) sender);
}
private
void
OnDataContextChanged(
object
sender, DependencyPropertyChangedEventArgs e)
{
UpdateBinding((RadNumericUpDown)sender);
}
private
void
UpdateBinding(RadNumericUpDown sender)
{
var binding = sender.GetBindingExpression(RadRangeBase.ValueProperty);
if
(binding ==
null
)
return
;
var attributes = GetCustomAttributes(binding.DataItem, binding.ParentBinding.Path.Path);
if
(attributes ==
null
|| attributes.Length == 0)
return
;
var rangeAttribute = attributes.OfType<RangeAttribute>().FirstOrDefault();
if
(rangeAttribute ==
null
)
return
;
sender.Minimum = Convert.ToDouble(rangeAttribute.Minimum);
sender.Maximum = Convert.ToDouble(rangeAttribute.Maximum);
}
protected
static
object
[] GetCustomAttributes(
object
source,
string
propertyPath)
{
if
(source ==
null
||
string
.IsNullOrEmpty(propertyPath))
return
null
;
PropertyInfo propertyInfo =
null
;
var currentType = source.GetType();
var path = propertyPath.Split(
'.'
);
for
(
int
i = 0, count = path.Length; i < count; i++)
{
var propertyStep = path[i];
propertyInfo = currentType.GetProperty(propertyStep);
if
(propertyInfo ==
null
|| source ==
null
|| i == count - 1)
break
;
source = propertyInfo.GetValue(source,
null
);
currentType = propertyInfo.PropertyType;
}
return
propertyInfo !=
null
? propertyInfo.GetCustomAttributes(
true
) :
null
;
}
}
Microsoft Silverlight (64-bit) Version: 5.1.41105.0
Windows 8.1 (64-bit)
Internet Explorer 11.0.9600.17416
Telerik 2017.1.117.1050
Hello! I found this discussion. 08 Oct 2014 Yoan says:
"I am afraid that this functionality is not supported since there are some conceptual impediments that prevent us to change the implementation of RadPropertyGrid. However, I have logged this in our system as feature request..."
Anyway, I spent a couple of hours and just put it here. All we need is:
In the ControlTemplate find "PART_NestedPropertiesButton" and replace it with
<
t:RadToggleButton
x:Name
=
"PART_NestedPropertiesButton"
Style
=
"{StaticResource PropertyGridNestedToggleButtonStyle}"
Background
=
"Transparent"
Width
=
"25"
IsChecked
=
"{Binding RelativeSource={RelativeSource TemplatedParent}, Path=IsExpanded, Mode=TwoWay}"
>
<
i:Interaction.Behaviors
>
<
behaviors:NestedPropertyVisibilityBehavior
PropertyGridField
=
"{Binding RelativeSource={RelativeSource TemplatedParent}}"
ShouldDisplayNestedProperties
=
"{Binding ShouldDisplayNestedProperties, RelativeSource={RelativeSource TemplatedParent}}"
/>
</
i:Interaction.Behaviors
>
</
t:RadToggleButton
>
Behavior class:
public
class
NestedPropertyVisibilityBehavior : Behavior<RadToggleButton>
{
public
static
readonly
DependencyProperty PropertyGridFieldProperty =
DependencyProperty.Register(
"PropertyGridField"
,
typeof
(PropertyGridField),
typeof
(NestedPropertyVisibilityBehavior),
new
PropertyMetadata(
null
, OnPropertyGridFieldChanged));
public
static
readonly
DependencyProperty ShouldDisplayNestedPropertiesProperty =
DependencyProperty.Register(
"ShouldDisplayNestedProperties"
,
typeof
(
bool
),
typeof
(NestedPropertyVisibilityBehavior),
new
PropertyMetadata(
false
, OnShouldDisplayNestedPropertiesChanged));
private
bool
_preventNesting;
public
PropertyGridField PropertyGridField
{
get
{
return
(PropertyGridField)GetValue(PropertyGridFieldProperty); }
set
{ SetValue(PropertyGridFieldProperty, value); }
}
public
bool
ShouldDisplayNestedProperties
{
get
{
return
(
bool
)GetValue(ShouldDisplayNestedPropertiesProperty); }
set
{ SetValue(ShouldDisplayNestedPropertiesProperty, value); }
}
private
static
void
OnShouldDisplayNestedPropertiesChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var sender = (NestedPropertyVisibilityBehavior) d;
sender.UpdateVisibility();
}
private
static
void
OnPropertyGridFieldChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var field = e.NewValue
as
PropertyGridField;
if
(field ==
null
)
return
;
var propDef = field.DataContext
as
PropertyDefinition;
if
(propDef ==
null
)
return
;
var attrs = GetCustomAttributes(propDef.Instance, propDef.SourceProperty.Name);
var sender = (NestedPropertyVisibilityBehavior) d;
sender._preventNesting = attrs.Any(x => x
is
PreventNestingAttribute);
sender.UpdateVisibility();
}
protected
override
void
OnAttached()
{
UpdateVisibility();
}
private
void
UpdateVisibility()
{
if
(AssociatedObject ==
null
)
return
;
AssociatedObject.Visibility = ShouldDisplayNestedProperties && !_preventNesting
? Visibility.Visible
: Visibility.Collapsed;
}
protected
static
object
[] GetCustomAttributes(
object
source,
string
propertyPath)
{
if
(source ==
null
||
string
.IsNullOrEmpty(propertyPath))
return
null
;
PropertyInfo propertyInfo =
null
;
var currentType = source.GetType();
var path = propertyPath.Split(
'.'
);
for
(
int
i = 0, count = path.Length; i < count; i++)
{
var propertyStep = path[i];
propertyInfo = currentType.GetProperty(propertyStep);
if
(propertyInfo ==
null
|| source ==
null
|| i == count - 1)
break
;
source = propertyInfo.GetValue(source,
null
);
currentType = propertyInfo.PropertyType;
}
return
propertyInfo !=
null
? propertyInfo.GetCustomAttributes(
true
) :
null
;
}
}
Attribute:
[AttributeUsage(AttributeTargets.Property)]
public
sealed
class
PreventNestingAttribute : Attribute { }
Usage in your Settings item:
[PreventNesting]
//[Display(Name = "Margin")]
public
Thickness Margin
{
get
{
return
_margin;
}
set
{ Set(() => Margin,
ref
_margin, value); }
}
I would be happy if it can be made more compact. I made it in haste.
Microsoft Silverlight (64-bit) Version: 5.1.41105.0
Windows 8.1 (64-bit)
Internet Explorer 11.0.9600.17416
Telerik 2017.1.117.1050
I have many instances of same class A. And there is several properties of class B inside A, which can be expanded in PropertySetMode="None".
But when I trying to edit multiple objects by passing IEnumerable<object> of A as Item, there is no expanders in Union/Intersect modes.
This is understandable for the Union, but not for Intersect, where only same properties presented.
Maybe I can use the DataTemplateSelector or something else to solve this problem?
Microsoft Silverlight (64-bit) Version: 5.1.41105.0
Windows 8.1 (64-bit)
Internet Explorer 11.0.9600.17416
Telerik 2017.1.117.1050
In my project I use RadPropertyGrid. I can't set custom editors in xaml because I don't know properties of PropertyGrid.Item in design mode.
I defined PropertyDefinition and set EditorTemplate in run time.
<
DataTemplate
x:Name
=
"CustomComboBox"
>
<
ComboBox
telerik:AutoBindBehavior.UpdateBindingOnElementLoaded
=
"SelectedValue"
SelectionMode
=
"Single"
Loaded
=
"ComboBox_Loaded"
/>
</
DataTemplate
>
I have dynamically set some properties of Editors in Loaded() event (for example ItemsSource for ComboBox).
I use PropertyGridField.AutoGeneratedPath to define witch editor is loading.
private
void
ComboBox_Loaded(
object
sender, RoutedEventArgs e)
{
string
propertyName = ((PropertyDefinition)((PropertyGridField)((ComboBox)sender).Parent).DataContext).AutoGeneratedPath;
//creating itemsList...
((ComboBox)sender).ItemsSource = itemsList;
((ComboBox)sender).DisplayMemberPath =
"DisplayName"
;
((ComboBox)sender).SelectedValuePath =
"Code"
;
}
In EditMode="Default" it works fine.
If I set EditMode to Single this solution will not work.
In Loaded() event sender.Parent = null.
In Single EditMode value of property is displayed in TextBlock.
How can I add a custom control instead this TextBlock?