usuario - Silverlight UserControl Custom Property Binding
crear usuario c# (3)
El problema fue que el UserControl estaba lanzando un error de enlace de datos (visible en la ventana de salida al depurar)
Debido a que el DataContext de UserControl se configuró en "Self" en su propio xaml, estaba buscando MainPageSelectedText dentro de su propio contexto (no estaba buscando MainPageSelectedText dentro de la "MainPage", que es donde podría pensar que se vería, porque cuando físicamente estás escribiendo / mirando el código que es lo que está en "contexto")
Pude hacer que este "trabajo" estableciera el enlace en el código que está detrás. Establecer la vinculación en el código subyacente es la única forma de configurar el UserControl como la "Fuente" de la vinculación. Pero esto solo funciona si el enlace es de dos vías. El enlace de OneWay romperá este código. Una solución mejor en conjunto sería crear un control de Silverlight, no un UserControl .
Ver también:
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
}
}
}
¿Cuál es la forma correcta de implementar propiedades personalizadas en los controles de usuario de Silverlight?
Cada "Página" en Silverlight es técnicamente un UserControl (se derivan de la clase UserControl). Cuando digo UserControl aquí, me refiero a un UserControl personalizado que se usará dentro de muchas páginas diferentes en muchos escenarios diferentes (similar a un UserControl ASP.NET).
Me gustaría que el UserControl personalizado admita el enlace y no confíe en el nombre de la propiedad a la que está vinculado, para que siempre sea el mismo. En su lugar, me gustaría que el propio UserControl tenga una propiedad a la que se vinculen los Controles dentro del UserControl, y los ViewModels fuera del UserControl también. (por favor vea el ejemplo a continuación)
El enlace dentro de UserControl funciona, el enlace dentro de MainPage funciona, El enlace I configurado entre MainPage y UserControl no funciona. Específicamente esta línea:
<myUserControls:MyCustomUserControl x:Name="MyCustomControl2"
SelectedText="{Binding MainPageSelectedText, Mode=TwoWay}"
Width="200" Height="50" />
salida de ejemplo:
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
}
}
}
Referencias (como llegué hasta aquí):
use DependencyPropertys: http://geekswithblogs.net/thibbard/archive/2008/04/22/wpf-custom-control-dependency-property-gotcha.aspx
use DependencyPropertys, agregue x: Nombre a su UserControl - agregue Binding con ElementName, establezca nuevamente la propiedad personalizada en el método PropertyChangedCallback: configuración de propiedades personalizadas en UserControl a través de DataBinding
no use propiedades personalizadas, confíe en los nombres de datos de datos subyacentes (no me gusta esta solución): wpf problem utilizando propiedades de dependencia en un UserControl
En lugar de enlazar el contexto de los datos a uno mismo, puede establecer el enlace en xaml agregando un x:Name
para el control de usuario y luego enlazar en el control de usuario que sigue a 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>
Entiendo que la razón por la que su control no está recibiendo el nuevo valor de la página principal es que está configurando el DataContext del control. Si no lo hizo, entonces el DataContext del control se heredará de su padre, la página principal en este caso.
Para que esto funcione, eliminé la configuración de DataContext del control, agregué un x: Nombre a cada control y establecí el enlace en el constructor del control usando el método [name] .SetBinding.
Hice el enlace en el ctor ya que no pude encontrar una manera de establecer la propiedad Source del enlace declarativo en el xaml a Self. es decir, {Binding SelectedText, Mode = TwoWay, Source = [Self en algunas formas]}. Intenté usar RelativeSource = {RelativeSource Self} sin alegría.
NOTA: Todo esto es SL3.