我有一个派生自Control
的课程,它位于UserControl
内。所以我的UserControl
是绑定的连接层,以及xaml
中发生的所有事情。
代码看起来像这样:
public partial class CombinedControl: UserControl{}
public class DerivedControl: MainControl
{
public int ExampleProp{get; set;}
}
我想要做的是访问xaml中的MainControl属性。我在CombinedControl中有它的实例,我可以通过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));
我的目标:<NameSpaceName:CombinedControl Instance.ExampleProp = "10"/>
问题:如何在xaml中访问和更改初始化的对象属性?
答案 0 :(得分:1)
由于您无法使用普通的元素/属性级语法,因此可以使用“混合”行为来定位Instance
上的CombinedControl
属性,并将其ExampleProp
属性设置为无论你想要什么价值。这需要添加对System.Windows.Interactivity的引用,它是Blend SDK(Visual Studio附带)的一部分。首先是主要行为:
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 );
}
}
然后,根据您为ExampleProp
设置值最有意义的位置,您可以通过XAML添加行为。例如,如果您在CombinedControl
的XAML中添加了行为,则可能如下所示:
<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>
如果您想从托管CombinedControl
的任何父级的XAML中执行此操作,您可能会这样(使用基本WPF Window
作为示例):
<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>