【问题标题】:How to bind a TabItem Header to a TextBox in FrameworkElementFactory?如何将 TabItem Header 绑定到 FrameworkElementFactory 中的 TextBox?
【发布时间】:2021-08-26 09:11:07
【问题描述】:

我尝试从this article 创建一个带有TextBoxTabItem

我发现 TabItem 标头未绑定到 TextBox

private void MenuItem_Click(object sender, RoutedEventArgs e)
{
    TabItem ti = new TabItem();
    DataTemplate tabItemTemplate = new DataTemplate();

    tabItemTemplate.DataType = typeof(TabItem);
    FrameworkElementFactory textBoxFactory = new FrameworkElementFactory(typeof(TextBox));
    textBoxFactory.SetBinding(TextBox.TextProperty, new Binding("."));
    textBoxFactory.SetValue(NameProperty, "textBox");
    textBoxFactory.SetValue(BorderThicknessProperty, new Thickness(0));
    //textBoxFactory.SetValue(IsEnabledProperty, false);
    tabItemTemplate.VisualTree = textBoxFactory;
    ti.Header = "Test!";
    ti.HeaderTemplate = tabItemTemplate;
    ti.MouseDoubleClick += TabItem_MouseDoubleClick;
    tabControl.Items.Add(ti);
}

private void TabItem_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
    MessageBox.Show((sender as TabItem).Header.ToString());
}

谁能教教我如何正确绑定?

非常感谢!

【问题讨论】:

  • 我必须说你做的不好。您应该编写 XAML 代码。不推荐使用 FrameworkElementFactory。它还使编写 UI 代码变得更加困难 - 难以编写和阅读。
  • @BionicCode 成功了!感谢万亿!能否请您如此友善并将其发布为答案,以便我将其标记为最佳答案?非常感谢!
  • @BionicCode 我是 WPF 新手,所以我真的不知道有什么区别!请你好心告诉我为什么它“不好”和“不推荐”?非常感谢!
  • docs.microsoft.com/en-us/dotnet/api/… : 备注 这个类是一种以编程方式创建模板的弃用方法,模板是 FrameworkTemplate 的子类,例如 ControlTemplate 或 DataTemplate;使用此类创建模板时,并非所有模板功能都可用。以编程方式创建模板的推荐方法是使用 XamlReader 类的 Load 方法从字符串或内存流加载 XAML。
  • 实现复杂的 UI 太复杂了,例如使用触发器、模板、VisualStateManager 等。XAML 为您提供有关元素树当前外观的视觉反馈:您可以立即看到父子关系等关系。它是可读的,C# 代码不是真正可读的,因此难以维护。您可以跨文件分发 XAML 代码,如模板。资源管理更容易。在设计 GUI 时,XAML 优于 C# 有很多优点。看看我的回答。我已对其进行了更新,以显示您的 C# 代码在 XAML 中的外观。

标签: c# wpf data-binding


【解决方案1】:

您的Binding 配置错误。

new Binding(".") 缺少Binding.Source
应该是:

var binding = new Binding("Header") { Source = ti };

使用 XAML 的示例

以下示例复制了您的 C# 代码

<TabControl>
  <TabItem Header="Test" MouseDoubleClick="TabItem_MouseDoubleClick" >
    <TabItem.HeaderTemplate>
      <DataTemplate>
        <TextBox x:Name="textBox" 
                 Text="{Binding RelativeSource={RelativeSource AncestorType=TabItem}, Path=Header}" />
       </DataTemplate>
     </TabItem.HeaderTemplate>
   </TabItem>
 </TabControl>

【讨论】:

    【解决方案2】:

    补充@BionicCode 的回答

    原始绑定的问题在于您指向当前的数据上下文。
    你的绑定相当于一个空的Binding“new Binding();”。
    因此,您获得的绑定不是属性,而是源(默认源是当前数据上下文)。
    但是绑定只能改变源的属性,不能改变源本身。
    Header 模板应用于 TabItem 的 Header 属性的内容。
    因此,要获取相同的值,但不是作为绑定的来源,而是作为绑定的 Path 中的属性,需要上到 TabItem 级别。
    @BionicCode 在他的回答中向您展示了此类绑定的示例。

    我将提供另一种集成到您的代码中的选项:

            private static readonly DataTemplate headerTemplate = (DataTemplate)XamlReader.Parse
                (@"
    <DataTemplate xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'
                  xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
        <TextBox x:Name='textBox'
                 Text='{Binding Header,
                                RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type TabItem}},
                                UpdateSourceTrigger=PropertyChanged}'
                 BorderThickness='0'/>
    </DataTemplate>
                ");
    
            private void MenuItem_Click(object sender, RoutedEventArgs e)
            {
                TabItem ti = new TabItem();
                ti.Header = "Test!";
                ti.HeaderTemplate = headerTemplate;
                ti.MouseDoubleClick += TabItem_MouseDoubleClick;
                tabControl.Items.Add(ti);
            }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-06-01
      • 2011-05-20
      • 2011-01-28
      • 1970-01-01
      • 2018-02-09
      • 1970-01-01
      • 2013-08-05
      相关资源
      最近更新 更多