I have class which derived from Control
and it is inside of the UserControl
. So my UserControl
is connection layer for bindings and everything going on in xaml
.
Code looks as such:
public partial class CombinedControl: UserControl{}
public class DerivedControl: MainControl
{
public int ExampleProp{get; set;}
}
What I want to do is to access MainControl properties in xaml. I have its instance in CombinedControl and I can expose the object itself via DependancyProperty
.
public DerivedControl Instance
{
get
{
return (DerivedControl)GetValue(InstanceProperty);
}
set
{
SetValue(InstanceProperty, value);
}
}
public static readonly DependencyProperty InstanceProperty=
DependencyProperty.Register("Instance", typeof(DerivedControl), typeof(CombinedControl));
My goal : <NameSpaceName:CombinedControl Instance.ExampleProp = "10"/>
Question : How to access and alter initialized object properties in xaml?
Since you can't use normal element-/property-level syntax, you could use a Blend behavior to target the Instance
property on your CombinedControl
and set its ExampleProp
property to whatever value you want. This requires adding a reference to System.Windows.Interactivity, which is part of the Blend SDK (which comes with Visual Studio). First is the main behavior:
using System;
using System.ComponentModel;
using System.Reflection;
using System.Windows;
using System.Windows.Interactivity;
// Sets properties on targeted items via XAML.
public class SetPropertyBehavior : Behavior<FrameworkElement>
{
// Name of the property we want to set on our target.
public static DependencyProperty PropertyNameProperty =
DependencyProperty.Register( "PropertyName", typeof( string ), typeof( SetPropertyBehavior ),
new PropertyMetadata( OnTargetPropertyOrValueChanged ) );
public string PropertyName
{
get { return (string)GetValue( PropertyNameProperty ); }
set { SetValue( PropertyNameProperty, value ); }
}
// Value of the property we want to set.
public static DependencyProperty PropertyValueProperty =
DependencyProperty.Register( "PropertyValue", typeof( object ), typeof( SetPropertyBehavior ),
new PropertyMetadata( OnTargetPropertyOrValueChanged ) );
public object PropertyValue
{
get { return GetValue( PropertyValueProperty ); }
set { SetValue( PropertyValueProperty, value ); }
}
// Target object that has the property we want to set. If this is null, the behavior's
// associated object will be the target instead.
public static DependencyProperty TargetProperty =
DependencyProperty.Register( "Target", typeof( object ), typeof( SetPropertyBehavior ),
new PropertyMetadata( OnTargetPropertyOrValueChanged ) );
public object Target
{
get { return GetValue( TargetProperty ); }
set { SetValue( TargetProperty, value ); }
}
protected override void OnAttached()
{
UpdateTargetProperty();
}
private static void OnTargetPropertyOrValueChanged( DependencyObject d, DependencyPropertyChangedEventArgs e )
{
var behavior = d as SetPropertyBehavior;
if( behavior != null )
behavior.UpdateTargetProperty();
}
private void UpdateTargetProperty()
{
// Ensure we have a property name and target to work with.
if( string.IsNullOrEmpty( this.PropertyName ) )
return;
var target = this.Target ?? this.AssociatedObject;
if( target == null )
return;
// Make sure our property is actually on our target.
var targetType = target.GetType();
PropertyInfo propInfo = targetType.GetProperty( this.PropertyName,
BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic );
if( propInfo == null )
return;
// Try to convert the string from the XAML to a value the target property can store.
TypeConverter converter = TypeDescriptor.GetConverter( propInfo.PropertyType );
object propValue = null;
try
{
if( converter.CanConvertFrom( this.PropertyValue.GetType() ) )
propValue = converter.ConvertFrom( this.PropertyValue );
else
propValue = converter.ConvertFrom( this.PropertyValue.ToString() );
}
catch( Exception )
{
// Do whatever is appropriate in your case.
propValue = null;
}
propInfo.SetValue( target, propValue );
}
}
Then depending on where it makes most sense for you to set the value for ExampleProp
, you would add the behavior via XAML. For example, if you added the behavior inside the XAML for your CombinedControl
, it might look something like this:
<UserControl x:Class="NameSpaceName.CombinedControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:NameSpaceName"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
x:Name="Root">
<i:Interaction.Behaviors>
<local:SetPropertyBehavior Target="{Binding Instance, ElementName=Root}" PropertyName="ExampleProp" PropertyValue="10"/>
</i:Interaction.Behaviors>
<!-- Rest of control here -->
</UserControl>
If you wanted to do it from the XAML of whatever parent is hosting your CombinedControl
, you could something like this (using a basic WPF Window
as an example):
<Window x:Class="NameSpaceName.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:NameSpaceName"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
Title="MainWindow" Height="350" Width="525">
<i:Interaction.Behaviors>
<local:SetPropertyBehavior Target="{Binding Instance, ElementName=myCombinedControl}" PropertyName="ExampleProp" PropertyValue="10"/>
</i:Interaction.Behaviors>
<Grid>
<local:CombinedControl x:Name="myCombinedControl"/>
</Grid>
</Window>
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.