简体   繁体   中英

How can I set the datacontext to property of a UserControl?

Having this structure and a combobox:

public abstract class A: UserControl
{
     public string MachineName { get; protected set; }
     ...
}

public partial class MainWindow : Window
{
     private List<A> m_listA = new List<A>();

     public MainPanel()
     {
        InitializeComponent();
        DataContext = this;
     
        cbMachines.ItemsSource = m_listA;
        cbMachines.SelectedIndex = 0;
        cbMachines.DisplayMemberPath = "MachineName";
     }
}

If I execute it I have the list of elements of the combobox perfectly filled but the selected one is empty and throws a binding error:

System.Windows.Data Error: 40 : BindingExpression path error: 'Name' property not found on 'object' 
''Grid' (Name='')'. BindingExpression:Path=Name; DataItem='Grid' (Name=''); target element is 
'TextBlock' (Name=''); target property is 'Text' (type 'String')

It seems that, it takes the grid of "A" main control as datacontext it seems that, it takes the main control as data context, but i need the usercontrol as datacontext.

How can i do this?

The corresponding area in default ComboBox template is this:

<ContentPresenter x:Name="contentPresenter" ContentTemplate="{TemplateBinding SelectionBoxItemTemplate}" ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}" Content="{TemplateBinding SelectionBoxItem}" ContentStringFormat="{TemplateBinding SelectionBoxItemStringFormat}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" IsHitTestVisible="false" Margin="{TemplateBinding Padding}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>

In this visual, you cannot set SelectionBoxItemTemplate, SelectionBoxItem, SelectionBoxItemStringFormat because they are read only .

According to .NET Source code (Combobox.cs UpdateSelectionBoxItem method) it checks if current item is ContentControl. If so, it gets Content as SelectionBoxItem; ContentTemplate as SelectionBoxItemTemplate and ContentStringFormat as SelectionBoxItemStringFormat.

As UserControl derives from ContentControl; you can make it possible by setting ContentTemplate for class A like this:

<UserControl.ContentTemplate>
    <DataTemplate>
        <TextBlock Text="{Binding Parent.MachineName}" />
    </DataTemplate>
</UserControl.ContentTemplate>

Or you can use a custom template for ComboBox to assign content like this:

Content="{Binding SelectedItem.MachineName, RelativeSource={RelativeSource Mode=TemplatedParent}}"

To get the default combobox template use this .

Or you can do it on code behind:

cbMachines.ApplyTemplate();
var contentPresenter = cbMachines.Template.FindName("contentPresenter", cbMachines) as ContentPresenter;
System.Windows.Data.BindingOperations.SetBinding(contentPresenter, ContentPresenter.ContentProperty, new Binding("SelectedItem.MachineName") { Source = cbMachines });
contentPresenter.ContentTemplateSelector = null;

There is no easier way, I'm afraid.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM