Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>I ended up figuring how how to do this on my own. I'm posting the answer here so that others can see a solution that works, and maybe a WPF guru will come by and show me a better/more elegant way to do this.</p> <p>So, the answer ended up being #2. Exposing the inner properties turns out to be the right answer. Setting it up is actually pretty easy.. once you know how to do it. There aren't many complete examples of this (that I could find), so hopefully this one will help someone else that runs into this problem.</p> <p><strong>ComboBoxWithLabel.xaml.cs</strong></p> <p>The important thing in this file is the use of DependencyProperties. Note that all we're doing right now is just exposing the properties (LabelContent and ItemsSource). The XAML will take care of wiring the internal control's properties to these external properties.</p> <pre><code>using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; using System.Collections; namespace BoundComboBoxExample { /// &lt;summary&gt; /// Interaction logic for ComboBoxWithLabel.xaml /// &lt;/summary&gt; public partial class ComboBoxWithLabel : UserControl { // Declare ItemsSource and Register as an Owner of ComboBox.ItemsSource // the ComboBoxWithLabel.xaml will bind the ComboBox.ItemsSource to this // property public IEnumerable ItemsSource { get { return (IEnumerable)GetValue(ItemsSourceProperty); } set { SetValue(ItemsSourceProperty, value); } } public static readonly DependencyProperty ItemsSourceProperty = ComboBox.ItemsSourceProperty.AddOwner(typeof(ComboBoxWithLabel)); // Declare a new LabelContent property that can be bound as well // The ComboBoxWithLable.xaml will bind the Label's content to this public string LabelContent { get { return (string)GetValue(LabelContentProperty); } set { SetValue(LabelContentProperty, value); } } public static readonly DependencyProperty LabelContentProperty = DependencyProperty.Register("LabelContent", typeof(string), typeof(ComboBoxWithLabel)); public ComboBoxWithLabel() { InitializeComponent(); } } } </code></pre> <p><strong>ComboBoxWithLabel.xaml</strong></p> <p>The Xaml is pretty straightforward, with the exception of the bindings on the Label and the ComboBox ItemsSource. I found that the easiest way to get these bindings right is to declare the properties in the .cs file (as above) and then use the VS2010 designer to setup the binding source from the properties pane. Essentially, this is the only way I know of to bind an inner control's properties to the base control. If there's a better way to do it, please let me know.</p> <pre><code>&lt;UserControl x:Class="BoundComboBoxExample.ComboBoxWithLabel" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" mc:Ignorable="d" d:DesignHeight="28" d:DesignWidth="453" xmlns:my="clr-namespace:BoundComboBoxExample"&gt; &lt;Grid&gt; &lt;DockPanel LastChildFill="True"&gt; &lt;!-- This will bind the Content property on the label to the 'LabelContent' property on this control--&gt; &lt;Label Content="{Binding Path=LabelContent, RelativeSource={RelativeSource FindAncestor, AncestorType=my:ComboBoxWithLabel, AncestorLevel=1}}" Width="100" HorizontalAlignment="Left"/&gt; &lt;!-- This will bind the ItemsSource of the ComboBox to this control's ItemsSource property --&gt; &lt;ComboBox ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=my:ComboBoxWithLabel, AncestorLevel=1}, Path=ItemsSource}"&gt;&lt;/ComboBox&gt; &lt;!-- you can do the same thing with SelectedValuePath, DisplayMemberPath, etc, but this illustrates the technique --&gt; &lt;/DockPanel&gt; &lt;/Grid&gt; &lt;/UserControl&gt; </code></pre> <p><strong>MainWindow.xaml</strong></p> <p>The XAML to use this is not interesting at all.. which is exactly what I wanted. You can set the ItemsSource and the LabelContent via all the standard WPF techniques.</p> <pre><code>&lt;Window x:Class="BoundComboBoxExample.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="86" Width="464" xmlns:my="clr-namespace:BoundComboBoxExample" Loaded="Window_Loaded"&gt; &lt;Window.Resources&gt; &lt;ObjectDataProvider x:Key="LookupValues" /&gt; &lt;/Window.Resources&gt; &lt;Grid&gt; &lt;my:ComboBoxWithLabel LabelContent="Foo" ItemsSource="{Binding Source={StaticResource LookupValues}}" HorizontalAlignment="Left" Margin="12,12,0,0" x:Name="comboBoxWithLabel1" VerticalAlignment="Top" Height="23" Width="418" /&gt; &lt;/Grid&gt; &lt;/Window&gt; </code></pre> <p>For Completeness Sake, here is the MainWindow.xaml.cs</p> <pre><code>/// &lt;summary&gt; /// Interaction logic for MainWindow.xaml /// &lt;/summary&gt; public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } private void Window_Loaded(object sender, RoutedEventArgs e) { ((ObjectDataProvider)FindResource("LookupValues")).ObjectInstance = (from i in Enumerable.Range(0, 5) select string.Format("Bar {0}", i)).ToArray(); } } </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload