navigation
 Saturday, July 12, 2008

So, let's say you've got a UserControl in a project that you would like to reference using interfaces without a direct reference to the UserControl's project. Now say you want to bind to a DependencyProperty in the UserControl. An interface to the UserControl doesn't help with the DependencyProperty. When I tackled this issue, I was unable to find any example of it anywhere on the Internet.

In the main project, we have the following XAML code to display a button for adding our UserControl to a StackPanel and a TextBox to test our Binding:

<Window x:Class="WpfBindingToExternal.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Window1" Height="300" Width="466"> <Grid Width="431"> <TextBox Margin="127,12.02,16,0" Name="textBox1" Text="Test" Height="22.98" VerticalAlignment="Top" /> <Button Height="24" HorizontalAlignment="Left" Margin="12,11,0,0" Name="button1" VerticalAlignment="Top" Width="109" Click="button1_Click">Add UserControl</Button> <StackPanel Margin="12,54,16,12" Name="stackPanel1" /> <Button Height="28" Visibility="Hidden" HorizontalAlignment="Right" Margin="0,38,16,0" Name="button2" VerticalAlignment="Top" Width="58" Click="button2_Click">Button</Button> </Grid> </Window>

Now for our UserControl project. For this example, it is a simple Rectangle with a TextBox.

<UserControl x:Class="WpfControlLibrary1.UserControl1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Height="60" Width="197"> <Grid> <Rectangle Name="rectangle1" Stroke="Black" Fill="Cyan" /> <TextBox Margin="20,20,20,20" Name="textBox1" /> </Grid> </UserControl>

In the code behind, we need to add a DependencyProperty to bind to.

public readonly static DependencyProperty MyTextProperty = DependencyProperty.Register( "MyText", typeof(string), typeof(UserControl1), new PropertyMetadata("My Default Text")); public string MyText { get { return (string)GetValue(MyTextProperty); } set { SetValue(MyTextProperty, value); } }

In the constructor we will bind our DependencyProperty to the TextBox.

public UserControl1() { InitializeComponent(); Binding myBinding = new Binding("MyText"); myBinding.Source = this; myBinding.Mode = BindingMode.TwoWay; BindingOperations.SetBinding(textBox1, TextBox.TextProperty, myBinding); }

Now we go back to the main project. We need to add some code to load an instance of our UserControl and add it to the StackPanel.

private UserControl AddNewUserControl() { object ob = Application.LoadComponent(new Uri( "WpfControlLibrary1;component\\UserControl1.xaml", System.UriKind.RelativeOrAbsolute)); //Set a unique name to the UserControl string name = String.Format("userControl{0}", stackPanel1.Children.Count); UserControl userControl = ob as UserControl; userControl.Name = name; //Add the new control to the StackPanel stackPanel1.Children.Add(userControl); stackPanel1.RegisterName(name, userControl); return userControl; }

Now the meat of the code. We first create a binding pointing to textBox1.Text.

private void BindNewUserControl(UserControl userControl) { //Create new binding sourced from textBox1.Text Binding myBinding = new Binding("Text"); myBinding.Source = textBox1; myBinding.Mode = BindingMode.TwoWay;

Then we see if the UserControl is a DependencyObject.

//See if the new UserControl is a DependencyObject //and return if it is not DependencyObject dobj = (userControl as DependencyObject); if (dobj == null) return;

Now that we have the DependencyObject, we get a list of the properties.

//Get the list of properties to the new UserControl PropertyDescriptorCollection props = TypeDescriptor.GetProperties(dobj);

Now we look for the DependencyProperty we are interested in.

//Get the 'MyText' DependencyProperty DependencyPropertyDescriptor depProp = DependencyPropertyDescriptor.FromProperty(props["MyText"]); if (depProp == null) return;

Once we have the DependencyProperty, the binding can be completed.

//Set the binding BindingOperations.SetBinding(dobj, depProp.DependencyProperty, myBinding); }

Just add the event handler for the button and run.

private void button1_Click(object sender, RoutedEventArgs e) { UserControl userControl = AddNewUserControl(); BindNewUserControl(userControl); }

When we run this example and hit the button a couple of times, we get the following:

AcessingDP1

Note: You need to make sure that the dll of the UserControl project is in the main project directory otherwise the LoadComponent call will fail. For the example you can also reference the UserControl project in your main project, but the idea is that you don't have to.

Now try typing in any of the text boxes. You will see that the TwoWay bindings are working.

AcessingDP2

Notice that we did not use an interface to do any of this. We just need to know that the remote UserControl is a DependencyObject and what the name of a DependencyProperty is. You can still implement and use an interface, but you don't need it for hooking up binding.

 |  | 
Name
E-mail
Home page

Comment (Some html is allowed: a@href@title, i, strike, u) where the @ means "attribute." For example, you can use <a href="" title=""> or <blockquote cite="Scott">.  

Enter the code shown (prevents robots):

Live Comment Preview