通过 xaml 中的依赖属性公开初始化对象的内部属性

本文关键字:属性 初始化 对象 内部 xaml 依赖 通过 | 更新日期: 2023-09-27 18:33:19

我有从Control派生的类,它位于UserControl内部。所以我UserControl是绑定的连接层以及xaml中发生的一切。

代码如下所示:

public partial class CombinedControl: UserControl{}
public class DerivedControl:   MainControl
{
    public int ExampleProp{get; set;}
}

我想做的是访问 xaml 中的主控件属性。我在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 中访问和更改初始化的对象属性?

通过 xaml 中的依赖属性公开初始化对象的内部属性

由于不能使用普通的元素/属性级语法,因此可以使用 Blend 行为来定位CombinedControl上的 Instance 属性,并将其 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 添加行为。例如,如果在 XAML 中为CombinedControl添加了行为,它可能如下所示:

<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>