如何编写此ItemsControl以便WPF使用绑定为输出网格生成列

如何编写此ItemsControl以便WPF使用绑定为输出网格生成列,wpf,binding,Wpf,Binding,下面的代码是一个主要工作的控件,可用于在具有两行的表中显示对象。第一行是标题行,第二行显示数据。正在显示的对象的属性可以定义为控件的项。每个项目在生成的表中显示为一列。我不想使用反射来实现此控件。这个问题不是关于反思 该控件有两个问题: 1.)它不是以“WPF形式”编写的(因为缺少更好的描述),因为我在代码中创建对象,而不是让绑定引擎来完成工作。我之所以用这种方式编码,是因为我不知道如何正确编码。注意,我正在为控件的ItemsPanel使用一个网格(应该是什么)。我希望使用网格,因为我希望输出是

下面的代码是一个主要工作的控件,可用于在具有两行的表中显示对象。第一行是标题行,第二行显示数据。正在显示的对象的属性可以定义为控件的项。每个项目在生成的表中显示为一列。我不想使用反射来实现此控件。这个问题不是关于反思

该控件有两个问题:

1.)它不是以“WPF形式”编写的(因为缺少更好的描述),因为我在代码中创建对象,而不是让绑定引擎来完成工作。我之所以用这种方式编码,是因为我不知道如何正确编码。注意,我正在为控件的ItemsPanel使用一个网格(应该是什么)。我希望使用网格,因为我希望输出是带有边框的表格形式。对于Items控件中的每个项,我需要绑定到网格第一行和第二行中的两个TextBlock。我还需要添加列,以便Items属性中的每个项都显示在一个新列中

2.)在BuildDataCell方法中创建的绑定不起作用。如果1.)已解决,则此问题最有可能得到解决。在不太可能的情况下,无法以WPF形式编写控件,如果能够使绑定正常工作,我希望使用它

下面的文章显示了我在研究这篇文章时遇到的几个StackOverflow问题。它要么没有回答我的问题,要么回答了我的问题,但我不知道为什么。 本文也是相关的,但我无法将其应用于此问题:

InfoTable.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
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.ComponentModel;
using System.Runtime.CompilerServices;

namespace InfoTableHost
{
public class InfoTableItem : DependencyObject
{
    public String Header
    {
        get { return (String)GetValue(HeaderProperty); }
        set { SetValue(HeaderProperty, value); }
    }

    public static readonly DependencyProperty HeaderProperty =
        DependencyProperty.Register("Header", typeof(String), typeof(InfoTableItem), new PropertyMetadata(String.Empty));



    public string Data
    {
        get { return (string)GetValue(DataProperty); }
        set { SetValue(DataProperty, value); }
    }

    public static readonly DependencyProperty DataProperty =
        DependencyProperty.Register("Data", typeof(string), typeof(InfoTableItem), new PropertyMetadata(String.Empty));


    #region INotifyPropertyChanged implementation
    public event PropertyChangedEventHandler PropertyChanged;

    public void RaisePropertyChanged([CallerMemberNameAttribute] string propertyName = "")
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
    #endregion
}


public class InfoTable : ItemsControl
{

    public enum ColumnSizeModes
    {
        AutoFitGrowLast,         // Shrink to fit except last column which expands to fill parent.
        UniformWidth,           // All Columns are the same width.  Table expands to fill parent
        AutoFit                // Shrink to fit.  Table does not expand to fill parent    
    }


    public ColumnSizeModes ColumnSizeMode
    {
        get { return (ColumnSizeModes)GetValue(ColumnSizeModeProperty); }
        set { SetValue(ColumnSizeModeProperty, value); }
    }

    public static readonly DependencyProperty ColumnSizeModeProperty =
        DependencyProperty.Register("ColumnSizeMode", typeof(ColumnSizeModes), typeof(InfoTable), new PropertyMetadata(ColumnSizeModes.AutoFitGrowLast));




    public Style HeaderCellStyle
    {
        get { return (Style)GetValue(HeaderCellStyleProperty); }
        set { SetValue(HeaderCellStyleProperty, value); }
    }

    public static readonly DependencyProperty HeaderCellStyleProperty =
        DependencyProperty.Register("HeaderCellStyle", typeof(Style), typeof(InfoTable), new PropertyMetadata(null));



    public Style HeaderTextStyle
    {
        get { return (Style)GetValue(HeaderTextStyleProperty); }
        set { SetValue(HeaderTextStyleProperty, value); }
    }

    public static readonly DependencyProperty HeaderTextStyleProperty =
        DependencyProperty.Register("HeaderTextStyle", typeof(Style), typeof(InfoTable), new PropertyMetadata(null));



    public Style DataCellStyle
    {
        get { return (Style)GetValue(DataCellStyleProperty); }
        set { SetValue(DataCellStyleProperty, value); }
    }

    public static readonly DependencyProperty DataCellStyleProperty =
        DependencyProperty.Register("DataCellStyle", typeof(Style), typeof(InfoTable), new PropertyMetadata(null));


    public Style DataTextStyle
    {
        get { return (Style)GetValue(DataTextStyleProperty); }
        set { SetValue(DataTextStyleProperty, value); }
    }

    public static readonly DependencyProperty DataTextStyleProperty =
        DependencyProperty.Register("DataTextStyle", typeof(Style), typeof(InfoTable), new PropertyMetadata(null));

    private bool isTemplateApplied;
    private Grid RootGrid;

    static InfoTable()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(InfoTable), new FrameworkPropertyMetadata(typeof(InfoTable)));
    }

    public InfoTable()
    {
        Loaded += InfoTable_Loaded;
    }

    void InfoTable_Loaded(object sender, RoutedEventArgs e)
    {
        if (!isTemplateApplied)
            return;

        Loaded -= InfoTable_Loaded;

        RootGrid = (Grid)GetTemplateChild("root");

        for (int i = 0; i < Items.Count; i++)
        {
            ColumnDefinition cd = new ColumnDefinition();
            if (ColumnSizeMode == ColumnSizeModes.UniformWidth || (ColumnSizeMode == ColumnSizeModes.AutoFitGrowLast && i == Items.Count - 1))
                cd.Width = new GridLength(1, GridUnitType.Star);
            else
                cd.Width = new GridLength(1, GridUnitType.Auto);

            RootGrid.ColumnDefinitions.Add(cd);
        }

        RootGrid.RowDefinitions.Add(new RowDefinition());
        RootGrid.RowDefinitions.Add(new RowDefinition());

        foreach (InfoTableItem item in Items.Cast<InfoTableItem>())
        {
            int index = Items.IndexOf(item);
            RootGrid.Children.Add(BuildHeaderCell(item, index));
            RootGrid.Children.Add(BuildDataCell(item, index));
        }
    }

    public override void OnApplyTemplate()
    {

        base.OnApplyTemplate();

        if (isTemplateApplied)
            return;

        isTemplateApplied = true;
    }

    private Border BuildHeaderCell(InfoTableItem item, int index)
    {
        Border b = new Border { Style = HeaderCellStyle };
        TextBlock t = new TextBlock { Style = HeaderTextStyle, Text = item.Header };
        b.SetValue(Grid.ColumnProperty, index);
        b.Child = t;
        return b;
    }

    private Border BuildDataCell(InfoTableItem item, int index)
    {
        Border b = new Border { Style = DataCellStyle };
        TextBlock t = new TextBlock { Style = DataTextStyle };
        Binding binding = new Binding { Source = Items[index], Path = new PropertyPath("Data"), UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged };
        t.SetBinding(TextBlock.TextProperty, binding);
        b.SetValue(Grid.ColumnProperty, index);
        b.SetValue(Grid.RowProperty, 1);
        b.Child = t;
        return b;
    }

}
}
使用系统;
使用System.Collections.Generic;
使用System.Linq;
使用系统文本;
使用System.Threading.Tasks;
使用System.Windows;
使用System.Windows.Controls;
使用System.Windows.Data;
使用System.Windows.Documents;
使用System.Windows.Input;
使用System.Windows.Media;
使用System.Windows.Media.Imaging;
使用System.Windows.Navigation;
使用System.Windows.Shapes;
使用系统组件模型;
使用System.Runtime.CompilerServices;
命名空间InfoTableHost
{
公共类InfoTableItem:DependencyObject
{
公共字符串头
{
get{return(String)GetValue(HeaderProperty);}
set{SetValue(HeaderProperty,value);}
}
公共静态只读从属属性HeaderProperty=
DependencyProperty.Register(“标头”、typeof(字符串)、typeof(InfoTableItem)、new PropertyMetadata(String.Empty));
公共字符串数据
{
获取{return(string)GetValue(DataProperty);}
set{SetValue(DataProperty,value);}
}
公共静态只读DependencyProperty DataProperty=
Register(“Data”、typeof(string)、typeof(InfoTableItem)、newpropertyMetadata(string.Empty));
#区域INotifyPropertyChanged实现
公共事件属性更改事件处理程序属性更改;
public void RaisePropertyChanged([CallerMemberNameAttribute]字符串propertyName=”“)
{
if(PropertyChanged!=null)
PropertyChanged(这是新的PropertyChangedEventArgs(propertyName));
}
#端区
}
公共类信息表:ItemsControl
{
公共枚举列SizeModes
{
AutoFitGrowLast,//收缩以适应,但最后一列扩展以填充父列除外。
UniformWidth,//所有列的宽度都相同。表展开以填充父列
自动调整//收缩以调整。表不展开以填充父表
}
公共ColumnSizeModes ColumnSizeMode
{
获取{return(ColumnSizeModes)GetValue(ColumnSizeModeProperty);}
set{SetValue(ColumnSizeModeProperty,value);}
}
public static readonly dependencProperty ColumnSizeModeProperty=
DependencyProperty.Register(“ColumnSizeMode”、typeof(ColumnSizeModes)、typeof(InfoTable)、new PropertyMetadata(ColumnSizeModes.AutoFitGrowtlast));
公共风格头套风格
{
获取{return(Style)GetValue(HeaderCellStyleProperty);}
set{SetValue(HeaderCellStyleProperty,value);}
}
公共静态只读从属属性HeaderCellStyleProperty=
DependencyProperty.Register(“HeaderCellStyle”、typeof(Style)、typeof(InfoTable)、newpropertyMetadata(null));
公共样式标题文本样式
{
获取{return(Style)GetValue(HeaderTextStyleProperty);}
set{SetValue(HeaderTextStyleProperty,value);}
}
公共静态只读从属属性HeaderTextStyleProperty=
Register(“HeaderTextStyle”、typeof(Style)、typeof(InfoTable)、newpropertyMetadata(null));
公共样式数据单元样式
{
获取{return(Style)GetValue(DataCellStyleProperty);}
set{SetValue(DataCellStyleProperty,value);}
}
公共静态只读从属属性DataCellStyleProperty=
Register(“DataCellStyle”、typeof(Style)、typeof(InfoTable)、newpropertyMetadata(null));
公共样式DataTextStyle
{
get{return(Style)GetValue(DataTextStyleProperty);}
set{SetValue(DataTextStyleProperty,value);}
}
公共静态只读DependencyProperty DataTextStyleProperty=
Register(“DataTextStyle”、typeof(Style)、typeof(InfoTable)、newpropertyMetadata(null));
应用私有bool-istemplate;
私有网格RootGrid;
静态信息表()
{
OverrideMetadata(typeof(InfoTable),new FrameworkPropertyMetadata(typeof(InfoTable));
}
公共信息表()
{
加载+=信息表_加载;
}
已加载void InfoTable_(对象发送方,路由目标)
{
如果(!isTemplateApplied)
返回;
已加载-=信息表_已加载;
RootGrid=(Grid)GetTemplateChild(“根”);
对于(int i=0;i<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:InfoTableHost">


    <Style TargetType="{x:Type local:InfoTable}">
        <Setter Property="BorderThickness" Value="0"/>
        <Setter Property="Margin" Value="0"/>
        <Setter Property="Padding" Value="0"/>
        <Setter Property="VerticalAlignment" Value="Top"/>
        <Setter Property="HeaderCellStyle">
            <Setter.Value>
                <Style TargetType="Border">
                    <Setter Property="Margin" Value="0" />
                    <Setter Property="Padding" Value="4" />
                    <Setter Property="Background" Value="Gray"/>
                    <Setter Property="BorderBrush" Value="Black"/>
                    <Setter Property="BorderThickness" Value=".5,.5,.5,.5"/>
                </Style>
            </Setter.Value>
        </Setter>
        <Setter Property="HeaderTextStyle">
            <Setter.Value>
                <Style TargetType="TextBlock">
                    <Setter Property="Foreground" Value="White"/>
                </Style>
            </Setter.Value>
        </Setter>

        <Setter Property="DataCellStyle">
            <Setter.Value>
                <Style TargetType="Border">
                    <Setter Property="Margin" Value="0" />
                    <Setter Property="Padding" Value="4" />
                    <Setter Property="Background" Value="DarkGray"/>
                    <Setter Property="BorderBrush" Value="Black"/>
                    <Setter Property="BorderThickness" Value=".5,0,.5,.5"/>
                </Style>
            </Setter.Value>
        </Setter>

        <Setter Property="DataTextStyle">
            <Setter.Value>
                <Style TargetType="TextBlock">
                    <Setter Property="Foreground" Value="White"/>
                </Style>
            </Setter.Value>
        </Setter>

        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type local:InfoTable}">
                    <Border Background="{TemplateBinding Background}" 
                            BorderBrush="{TemplateBinding BorderBrush}"
                            BorderThickness="{TemplateBinding BorderThickness}"
                            Padding="{TemplateBinding Padding}"
                            VerticalAlignment="{TemplateBinding VerticalAlignment}">

                        <Grid VerticalAlignment="Top" x:Name="root" Margin="0">

                        </Grid>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>
<Window x:Class="InfoTableHost.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:InfoTableHost"
        Title="MainWindow" Height="350" Width="525" Padding="0">
    <StackPanel DataContext="{Binding Observation}" >
        <StackPanel.Resources>
            <Style TargetType="TextBlock">
                <Setter Property="FontSize" Value="18"/>
                <Setter Property="Foreground" Value="Black"/>
            </Style>
        </StackPanel.Resources>
        <local:InfoTable>
            <local:InfoTableItem Header="Unbound Header" Data="Unbound Data"/>
            <local:InfoTableItem Header="Observation Date" Data="{Binding ObSDate}"/>
            <local:InfoTableItem Header="Close" Data="{Binding Close}"/>
        </local:InfoTable>
        <TextBlock>This TextBlock Binding Works: <TextBlock Text="{Binding ObsDate}" /></TextBlock>
    </StackPanel>
</Window>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
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.ComponentModel;
using System.Runtime.CompilerServices;

namespace InfoTableHost
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public Observation Observation { get; set; }

        public MainWindow()
        {

            InitializeComponent();
            DataContext = this;
            Observation = new Observation { ObsDate = DateTime.Now, Close = 2201.55m };
        }
    }

    public class Observation : INotifyPropertyChanged
    {
        private DateTime _ObsDate;
        public DateTime ObsDate 
        {
            get { return _ObsDate; }
            set
            {
                if (_ObsDate != value)
                {
                    _ObsDate = value;
                    RaisePropertyChanged();
                }
            }
        }


        private decimal _Close;
        public decimal Close
        {
            get { return _Close; }
            set
            {
                if (_Close != value)
                {
                    _Close = value;
                    RaisePropertyChanged();
                }
            }
        }


        #region INotifyPropertyChanged implementation
        public event PropertyChangedEventHandler PropertyChanged;

        public void RaisePropertyChanged([CallerMemberNameAttribute] string propertyName = "")
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
        #endregion


    }

}
public class InfoTableItem : FrameworkElement
{
   ...
}