Silverlight UserControl 自定义属性绑定

Posted

技术标签:

【中文标题】Silverlight UserControl 自定义属性绑定【英文标题】:Silverlight UserControl Custom Property Binding 【发布时间】:2010-12-04 08:22:00 【问题描述】:

在 Silverlight 用户控件中实现自定义属性的正确方法是什么?

Silverlight 中的每个“页面”在技术上都是一个 UserControl(它们派生自 UserControl 类)。当我在这里说 UserControl 时,我的意思是一个自定义 UserControl,它将在许多不同场景中的许多不同页面中使用(类似于 ASP.NET UserControl)。

我希望自定义用户控件支持绑定,而不是依赖于它所绑定的属性的名称,以始终保持相同。相反,我希望 UserControl 本身具有 UserControl 内的控件绑定到的属性,并且 UserControl 外的 ViewModel 也绑定到。 (请看下面的例子)

UserControl 内的绑定有效,MainPage 内的绑定有效,我在 MainPage 和 UserControl 之间设置的绑定不起作用。特别是这一行:

<myUserControls:MyCustomUserControl x:Name="MyCustomControl2" 
    SelectedText="Binding MainPageSelectedText, Mode=TwoWay" 
    Width="200" Height="50" />

示例输出:

MainPage.xaml

<UserControl x:Class="SilverlightCustomUserControl.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    xmlns:myUserControls="clr-namespace:SilverlightCustomUserControl"
    mc:Ignorable="d" d:DesignWidth="640" d:DesignHeight="480"
    DataContext="Binding RelativeSource=RelativeSource Self">
  <Canvas x:Name="LayoutRoot">
    <StackPanel Orientation="Vertical">
      <TextBlock Text="UserControl Binding:" Width="200"></TextBlock>
      <myUserControls:MyCustomUserControl x:Name="MyCustomControl2" SelectedText="Binding MainPageSelectedText, Mode=TwoWay" Width="200" Height="50" />
      <TextBlock Text="MainPage Binding:" Width="200"></TextBlock>
      <TextBox Text="Binding MainPageSelectedText, Mode=TwoWay" Width="200"></TextBox>
      <Border BorderBrush="Black" BorderThickness="1">
        <TextBlock Text="Binding MainPageSelectedText" Width="200" Height="24"></TextBlock>
      </Border>
    </StackPanel>
  </Canvas>
</UserControl>

MainPage.xaml.cs

namespace SilverlightCustomUserControl

 public partial class MainPage : UserControl, INotifyPropertyChanged
 
  //NOTE: would probably be in a ViewModel
  public string MainPageSelectedText
  
   get  return _MainPageSelectedText; 
   set
   
    string myValue = value ?? String.Empty;
    if (_MainPageSelectedText != myValue)
    
     _MainPageSelectedText = value;
     OnPropertyChanged("MainPageSelectedText");
    
   
  
  private string _MainPageSelectedText;


  public MainPage()
  
   InitializeComponent();
  


  #region INotifyPropertyChanged Members

  public event PropertyChangedEventHandler PropertyChanged;

  protected virtual void OnPropertyChanged(string name)
  
   PropertyChangedEventHandler ph = this.PropertyChanged;

   if (ph != null)
    ph(this, new PropertyChangedEventArgs(name));
  

  #endregion
 

MyCustomUserControl.xaml

<UserControl
   x:Class="SilverlightCustomUserControl.MyCustomUserControl" 
   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
   xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
   DataContext="Binding RelativeSource=RelativeSource Self">
  <Grid>
    <StackPanel>
      <TextBox Text="Binding SelectedText, Mode=TwoWay" />
      <Border BorderBrush="Black" BorderThickness="1">
        <TextBlock Text="Binding SelectedText" Height="24"></TextBlock>
      </Border>
    </StackPanel>
  </Grid>
</UserControl>

MyCustomUserControl.xaml.cs

namespace SilverlightCustomUserControl

 public partial class MyCustomUserControl : UserControl
 
  public string SelectedText
  
   get  return (string)GetValue(SelectedTextProperty); 
   set  SetValue(SelectedTextProperty, value); 
  

  public static readonly DependencyProperty SelectedTextProperty =
    DependencyProperty.Register("SelectedText", typeof(string), typeof(MyCustomUserControl), new PropertyMetadata("", SelectedText_PropertyChangedCallback));


  public MyCustomUserControl()
  
   InitializeComponent();
  

  private static void SelectedText_PropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
  
   //empty
  
 

参考资料(我是如何做到这一点的):

使用依赖属性: http://geekswithblogs.net/thibbard/archive/2008/04/22/wpf-custom-control-dependency-property-gotcha.aspx

使用 DependencyPropertys,将 x:Name 添加到您的 UserControl - 添加与 ElementName 的绑定,在 PropertyChangedCallback 方法中再次设置自定义属性: Setting Custom Properties in UserControl via DataBinding

不要使用自定义属性,依赖底层数据上下文名称(我不喜欢这个解决方案): wpf trouble using dependency properties in a UserControl

【问题讨论】:

如果你还在寻找答案可以参考这篇文章Silverlight UserControl Custom Property Binding 【参考方案1】:

我将其理解为您的控件未从 maim 页面接收新值的原因是您正在设置控件的 DataContext。如果没有,那么控件的 DataContext 将从其父级继承,在本例中为主页。

为了让它工作,我删除了控件的 DataContext 设置,为每个控件添加了一个 x:Name 并使用 [name].SetBinding 方法在控件的构造函数中设置绑定。

我在 ctor 中进行了绑定,因为我无法找到将 xaml 中声明性绑定的 Source 属性设置为 Self 的方法。即 Binding SelectedText, Mode=TwoWay, Source=[Self here some how]。我确实尝试过使用RelativeSource=RelativeSource Self,但没有任何乐趣。

注意:所有这些都是 SL3。

【讨论】:

是的!自此发布以来,这些也是我的确切步骤!我会发布一些代码。谢谢您的帮助。 p.s. RelativeSource=Self 不起作用,因为 DataContext 变成了 TextBox,而不是 UserControl。 当然。这完全有道理。谢谢你告诉我。【参考方案2】:

问题是 UserControl 引发了 DataBinding 错误(调试时在输出窗口中可见)

因为 UserControl 的 DataContext 在其自己的 xaml 中设置为“Self”,所以它在其自己的上下文中寻找 MainPageSelectedText(它不是在“MainPage”中寻找 MainPageSelectedText,您可能认为它会在其中查找,因为当您实际编写/查看“上下文”中的代码时)

我可以通过在后面的代码中设置绑定来实现这个“工作”。在后面的代码中设置绑定是将 UserControl 本身设置为绑定的“源”的唯一方法。但这仅在 Binding 是 TwoWay 时才有效。 OneWay 绑定将破坏此代码。更好的解决方案是创建 Silverlight Control,而不是 UserControl

另见:

http://social.msdn.microsoft.com/Forums/en-US/silverlightcontrols/thread/052a2b67-20fc-4f6a-84db-07c85ceb3303

http://msdn.microsoft.com/en-us/library/cc278064%28VS.95%29.aspx

MyCustomUserControl.xaml

<UserControl
   x:Class="SilverlightCustomUserControl.MyCustomUserControl" 
 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006">
 <Grid>
  <StackPanel>
   <TextBox x:Name="UserControlTextBox" />
   <Border BorderBrush="Black" BorderThickness="1">
    <TextBlock x:Name="UserControlTextBlock" Height="24"></TextBlock>
   </Border>
  </StackPanel>
 </Grid>
</UserControl>

MyCustomUserControl.xaml.cs

namespace SilverlightCustomUserControl

 public partial class MyCustomUserControl : UserControl
 

  public string SelectedText
  
   get  return (string)GetValue(SelectedTextProperty); 
   set  SetValue(SelectedTextProperty, value); 
  

  public static readonly DependencyProperty SelectedTextProperty =
    DependencyProperty.Register("SelectedText", typeof(string), typeof(MyCustomUserControl), new PropertyMetadata("", SelectedText_PropertyChangedCallback));


  public MyCustomUserControl()
  
   InitializeComponent();

               //SEE HERE
   UserControlTextBox.SetBinding(TextBox.TextProperty, new Binding()  Source = this, Path = new PropertyPath("SelectedText"), Mode = BindingMode.TwoWay );
   UserControlTextBlock.SetBinding(TextBlock.TextProperty, new Binding()  Source = this, Path = new PropertyPath("SelectedText") );
               //SEE HERE
  

  private static void SelectedText_PropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
  
   //empty
  

 

【讨论】:

【参考方案3】:

您可以通过为用户控件添加x:Name,然后在用户控件xaml中绑定来设置xaml中的绑定,而不是绑定数据上下文:

<UserControl
  x:Class="SilverlightCustomUserControl.MyCustomUserControl" 
  x:Name="myUserControl
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
  xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006">
    <Grid>
        <StackPanel>
            <TextBox Text="Binding SelectedText, ElementName=myUserContol, Mode=TwoWay" />
            <Border BorderBrush="Black" BorderThickness="1">
                <TextBlock Text="Binding SelectedText,ElementName=myUserControl" Height="24"></TextBlock>
            </Border>
        </StackPanel>
     </Grid>
</UserControl>

【讨论】:

以上是关于Silverlight UserControl 自定义属性绑定的主要内容,如果未能解决你的问题,请参考以下文章

何时在 Silverlight 中使用 UserControl 与 Control?

Silverlight Popup UserControl - 工作一次,然后崩溃

x:如果元素包含在UserControl的内容中(Silverlight),则名称不起作用

Silverlight Xaml 覆盖控件的 IsEnabled 属性

TextBlock 不包装 Silverlight 应用程序

是否可以在 Silverlight DataTemplate 中绑定事件?