Silverlight UserControl自定义属性绑定

问题描述:

在Silverlight UserControls中实现自定义属性的正确方法是什么?Silverlight UserControl自定义属性绑定

Silverlight中的每个“页面”在技术上都是一个UserControl(它们是从UserControl类派生的)。当我在这里说UserControl时,我的意思是一个Custom 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" /> 

示例输出:
alt text

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

参考(我是如何走到这一步):

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

使用DependencyPropertys,添加X:命名你的用户控件 - 添加与ElementName绑定,再次在PropertyChangedCallback方法中设置Custom属性:

不使用自定义属性,依赖于底层的datacontext名字(我不喜欢这个解决方案): wpf trouble using dependency properties in a UserControl

+0

如果你还在寻找答案,你可以请参阅本文[Silverlight UserControl自定义属性绑定](http://www.dotnetspark.com/kb/4664-silverlight-usercontrol-custom-property.aspx) – 2011-08-08 18:13:31

我把它理解为你的控制没有收到新的值从残废页面是什么原因您正在设置控件的DataContext。如果你没有,那么控件的DataContext将从它的父级继承,在这种情况下是主页面。

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

我确实在构造函数的结合,因为我无法弄清楚设置声明性绑定的源属性在XAML到自我的一种方式。即{Binding SelectedText,Mode = TwoWay,Source = [Self here some how]}。我没有喜悦地尝试使用RelativeSource = {RelativeSource Self}。

注:这一切都是SL3。

+0

是的!这些都是我发布后的精确步骤!我会稍微发布一些代码。谢谢您的帮助。附: RelativeSource = Self不起作用,因为DataContext成为TextBox,而不是UserControl。 – 2009-10-12 13:39:18

+0

当然。这是完全合理的。谢谢你让我知道。 – voiddog 2009-10-13 12:09:09

的问题是用户控件被扔一个数据绑定错误(在输出窗口中可见的,而调试)

因为用户控件的DataContext的是在自己的XAML设置为“自动”,它在找内MainPageSelectedText其自己的上下文(它不是在“MainPage”中查找MainPageSelectedText,因为当你在物理上编写/查看在“上下文”中的代码时),而是在“MainPage”中查找MainPageSelectedText)

I通过在后面的代码中设置Binding,能够获得这个“工作”。在后面的代码中设置绑定是将UserControl本身设置为绑定的“源”的唯一方法。但是这只有在Binding是TwoWay时才有效。 OneWay绑定会破坏这段代码。更好的解决方案是创建Silverlight 控件,而不是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 
    } 

} 
} 

相反的数据上下文绑定到自己,你可以通过添加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>