下面的代码是一个主要工作的控件,可用于在包含两行的表中显示对象。第一行是标题行,第二行显示数据。可以将显示的对象的属性定义为控件的项目。每个项目在生成的表格中显示为一列。我不想使用反射来实现此控件。这个问题与反思无关。
控件有两个问题:
1。)它不是用“WPF格式”编写的(因为没有更好的描述),因为我在代码中创建对象而不是让绑定引擎完成工作。我之所以编码的原因是因为我不知道如何正确编码。注意我正在为控件的ItemsPanel使用一个网格(应该是什么)。我想使用网格,因为我希望输出是带有边框的表格形式。对于Items控件中的每个Item,我需要绑定到网格的第一行和第二行中的两个TextBlock。我还需要添加列,以便Items属性中的每个Item都显示在一个新列中。
2。)BuildDataCell方法中创建的绑定不起作用。如果1.)已解决,则很可能会解决此问题。在不太可能的情况下,控件不能以WPF形式编写,我想按原样使用它,如果我可以使绑定工作。
下面的文章显示了我在研究这个问题时遇到的几个StackOverflow问题。它要么不回答我的问题,要么回答它,但我不知道为什么。 http://drwpf.com/blog/2009/05/12/itemscontrol-l-is-for-lookless/#TemplatingAnItemsControl 这篇文章也很相关,但我不能将它应用于这个问题: http://blog.scottlogic.com/2010/11/15/using-a-grid-as-the-panel-for-an-itemscontrol.html
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;
}
}
}
Generic.xaml
<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>
MainWindow.xaml(主页)
<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>
MainWindow.xaml.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
{
/// <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
}
}
答案 0 :(得分:1)
事实证明问题在于InfoTableItem类。显然,DependencyObject不继承父控件的DataContext,因此绑定没有DataContext。要解决此问题,请使InfoTableItem继承自FrameworkElement并且您正在开展业务:
public class InfoTableItem : FrameworkElement
{
...
}