【问题标题】:How can I set the datacontext to property of a UserControl?如何将 datacontext 设置为 UserControl 的属性?
【发布时间】:2021-07-20 17:58:44
【问题描述】:

具有这种结构和组合框:

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”主控件的网格作为datacontext 看来,它将主控件作为数据上下文,但我需要用户控件作为数据上下文。

我该怎么做?

【问题讨论】:

  • 错误消息与您在此处显示的代码没有任何关系。除此之外,将 UserControl 作为数据项看起来很奇怪。 A 类不应派生自 UserControl。
  • 组合框抛出错误,并将网格作为数据上下文,这是继承自 A 的类的第一个控件,该类是用户控件。这是从用户控件和自定义类继承的独特方式。
  • 首先,使用名为“Name”的属性会导致我身边出现问题。因为,Name 属性存在于基础 FrameworkElement 上。第二组 cbMachines.IsEditable = true;有了这些,我没有任何问题显示所选项目。
  • 另外我忘了说你应该异步设置 SelectedIndex,像这样:cbMachines.Dispatcher.BeginInvoke(new Action(() => cbMachines.SelectedIndex = 0));
  • 同步分配所选索引作为异步工作,为什么我需要异步?其次,使其可编辑也对我有用,但我不想编辑它......“名称”不是我在问题中更改它的真实姓名,谢谢!

标签: c# wpf combobox binding


【解决方案1】:

默认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;您可以通过为 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;

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

【讨论】:

    猜你喜欢
    • 2018-03-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-20
    • 1970-01-01
    • 2010-11-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多