2016-02-05 55 views
0

我有從Control派生的類,它位於UserControl的內部。所以我的UserControl是綁定的連接層,所有事情都在xaml通過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

典型的方法是也暴露UserControl中的'ExampleProp'。在UserControl的XAML中,您可以將DerivedControl的ExampleProp綁定到UserControl實例的DerivedControl的ExampleProp。 – Clemens

+0

是的,那對我來說是不幸的。由於MainControl擁有超過100個屬性,並且將它們全部放入CombinedControl中並不是一種方法,所以我的目標是通過對象本身訪問屬性。注意:MainControl來自第三方,所以我沒有它的來源。這就是爲什麼我甚至使用這個派生模型。 – Karolis

回答

1

由於您無法使用正常的元素/屬性級語法,因此您可以使用混合行爲來定位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> 

如果你想從XAML做任何的母公司在託管您CombinedControl,你可以像這個(使用基本的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> 
+0

DerivedControl已經在CombinedControl的xaml中創建,這意味着它已經有一個DerivedClass的實例,所以我想訪問該DerivedClass對象屬性。答案是:這將創建一個新的對象,它不是UserControl本身使用的對象,因此它將值設置爲不是我的意圖的不同實例。感謝您的努力,但我已經嘗試過。 – Karolis

+0

@Carl Ahh陷入困境。請看看我的編輯,看看是否會幫助你。實際的XAML有點冗長,但我認爲這種行爲會讓你想要的地方。 – mvromer

+0

謝謝!我們也在考慮去反射方式,不幸的是MainControl來自第三方,因此它的小改動會在運行時中斷我們的代碼。再次感謝你的努力!如果我們在不久的將來不提供更堅實的東西,我可能會堅持使用這個解決方案。當我們將解決問題時,將其標記爲答案,因爲我希望這個問題仍然可以爲更清晰的解決方案開放:)週末愉快! – Karolis