2011-01-25 103 views
2

我想创建一个暴露名为InnerCaption的属性的WPF用户控件。代码如下WPF绑定问题

XAML代码

<UserControl x:Class="myControl.UserControl1" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> 
    <Grid> 
     <TextBlock Name="_innerCaption" > Hello</TextBlock> 
    </Grid> 
</UserControl> 

CS代码背后

namespace myControl 
{ 
    /// <summary> 
    /// Interaction logic for UserControl1.xaml 
    /// </summary> 
    public partial class UserControl1 : UserControl 
    { 
     public UserControl1() 
     { 
      InitializeComponent(); 
     } 

     public TextBlock InnerCaption 
     { 
     get { return (TextBlock)this.GetValue(InnerCaptionProperty); } 
     set { this.SetValue(InnerCaptionProperty, value); } 
     } 
     public static readonly DependencyProperty InnerCaptionProperty = DependencyProperty.Register(
     "InnerCaption", typeof(TextBlock), typeof(UserControl1),new PropertyMetadata(false)); 
     } 
} 

的问题是:我希望用户能够在设计时定制InnerCaption比如:修改它的颜色,字体样式......但我不知道我是如何使用某种绑定来感叹的。但它是徒劳的。据我所知,绑定只支持绑定到一个属性,对吧? 请给我一个方法! :(

回答

0

上述问题有一个简单的解决方案:如何使用ContentPresenter控件?只需要几行代码来声明属性(TextBlock,string,...),然后将控件绑定到属性。我尝试过,它的工作原理! :D

1

绑定如下所示:

XAML

<UserControl x:Class="myControl.UserControl1" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> 
    <Grid> 
     <TextBlock Name="_innerCaption" 
        Text="{Binding MyCaption}"/> 
    </Grid> 
</UserControl> 

现在你必须设置XAML文件的类的DataContext你想绑定到:

namespace myControl 
{ 
    /// <summary> 
    /// Interaction logic for UserControl1.xaml 
    /// </summary> 
    public partial class UserControl1 : UserControl 
    { 
     MyClassToBindTo bindingClass; 

     public UserControl1() 
     { 
      InitializeComponent(); 
      bindingClass = new MyClassToBindTo(); 
      DataContext = bindingClass; 
     } 
    } 
} 

而绑定类可能如下所示:

public class MyClassToBindTo : NotifyPropertyChangedBase 
{ 
     private string myCaptionString = "hello"; 

     public string MyCaption 
     { 
     get { return myCaptionString } 
     set { myCaptionString = value; OnPropertyChanged("MyCaptionString"); } 
     } 

     // Also implement the INotifyPropertyChanged interface here 
} 

希望这可以帮助你!

编辑:

我通常实现一个基类的INotifyPropertyChanged的东西“NotifyPropertyChangedBase:

public abstract class PropertyChangedBase : INotifyPropertyChanged 
    { 
     #region Member Variables 

     private static HashSet<string> alreadyCoveredProperties = new HashSet<string>(); 

     #endregion 

     #region INotifyPropertyChanged Members 

     /// <summary> 
     /// Occurs when a property value changes. 
     /// </summary> 
     public event PropertyChangedEventHandler PropertyChanged; 

     /// <summary> 
     /// Calls registered handlers when a property is changed. 
     /// </summary> 
     /// <param name="propertyName">Name of the property.</param> 
     protected void OnPropertyChanged(string propertyName) 
     { 
      PropertyChangedEventHandler handler = this.PropertyChanged; 
      if (handler != null) 
      { 
       handler(this, new PropertyChangedEventArgs(propertyName)); 
      } 
     } 

     /// <summary> 
     /// Removes all property changed subscription from the event handler. 
     /// </summary> 
     protected void RemovePropertyChangedSubscription() 
     { 
      if (this.PropertyChanged != null) 
      { 
       this.PropertyChanged -= new PropertyChangedEventHandler(PropertyChanged); 
       this.PropertyChanged = null; 
      } 
     } 

     /// <summary> 
     /// Determines whether the specified property name refers to a property defined for this object. 
     /// </summary> 
     /// <param name="propertyName">Name of the property.</param> 
     /// <returns> 
     /// Returns <c>true</c> if the provided name refers to a defined property; otherwise, <c>false</c>. 
     /// </returns> 
     /// <remarks>Uses reflection.</remarks> 
     protected bool IsDefinedPropertyName(string propertyName) 
     { 
      string propertyFullName = GetType().FullName + "." + propertyName; 
      if (alreadyCoveredProperties.Contains(propertyFullName)) 
      { 
       return true; 
      } 
      else 
      { 
       PropertyDescriptorCollection col = TypeDescriptor.GetProperties(this); 
       PropertyDescriptor propertyDescriptor = col[propertyName]; 

       // A property exists, if the propertyDescriptor is != null. 
       if (propertyDescriptor != null) 
       { 
        alreadyCoveredProperties.Add(propertyFullName); 
        return true; 
       } 
       else 
       { 
        return false; 
       } 
      } 
     } 
     #endregion 
    } 
+0

那么我会在一分钟内添加INotifyPropertyChanged接口......刚到工作时需要理清一些事情。 – Christian 2011-01-25 07:26:55

+0

这是一个很好的例子,说明如何使用实现INotifyPropertyChanged -pattern的适当模型进行简单的绑定,但它不能帮助如何根据请求绑定标题样式的问题“修改其颜色,字体风格“ – Almund 2011-01-25 07:32:36

1

我想你可能是以后可能是子类的行更多的东西TextBlock这将允许您轻松地利用该控件上的现有属性。

public class MyCaptionControl : TextBlock 
{ 
.... 
} 

这使您能够为你通常会绑定:

<MyCaptionControl FontSize="{Binding MyModelSize}" Text="{Binding MyModelCaption}" /> 

You're definatly在正确的方向上创建依赖属性,但如果你希望绑定到这些属性you'll需要每绑定一个价值财产。像

public static readonly DependencyProperty ForegroundColor = .... 
public static readonly DependencyProperty BackgroundColor = .... 

这些可以被直接映射到您的用户控件的任何内部文本块控制,但正如我所说,我认为你会是子类的TextBlock的更好。