如何将数据上下文设置为 UserControl 的 属性?

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

具有此结构和组合框:

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

如果我执行它,我会得到完美填充的组合框元素列表,但所选元素为空并引发绑定错误:

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')

好像是以“A”主控的grid作为datacontext 看来,它把主控件作为数据上下文,但我需要用户控件作为数据上下文。

我该怎么做?

默认的ComboBox模板对应的区域是这样的:

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

在此视觉对象中,您无法设置 SelectionBoxItemTemplate、SelectionBoxItem、SelectionBoxItemStringFormat,因为它们只读

根据 .NET Source code(Combobox.cs UpdateSelectionBoxItem 方法),它检查当前项目是否为 ContentControl。如果是这样,它将 Content 作为 SelectionBoxItem; ContentTemplate 作为 SelectionBoxItemTemplate,ContentStringFormat 作为 SelectionBoxItemStringFormat。

由于 UserControl 派生自 ContentControl;您可以通过为 class A 设置 ContentTemplate 来实现,如下所示:

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

或者您可以使用 ComboBox 的自定义模板来分配如下内容:

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

获取默认的组合框模板use this

或者您可以在后面的代码中完成:

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;

恐怕没有更简单的方法了。