using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
namespace WpfApp4
{
/*例子:
<ScrollViewer>
<local:DataBindGrid x:Name="grid">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"></ColumnDefinition>
<ColumnDefinition Width="100"></ColumnDefinition>
<ColumnDefinition Width="auto"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="22"></RowDefinition>
</Grid.RowDefinitions>
<TextBlock Text="Header1" Margin="10,0,0,0" Grid.Column="0"></TextBlock>
<TextBlock Text="Header2" Margin="10,0,0,0" Grid.Column="1"></TextBlock>
<TextBlock Text="Header3" Margin="10,0,0,0" Grid.Column="2"></TextBlock>
<local:DataBindGrid.ItemTemplate>
<ControlTemplate>
<Grid Height="30">
<!-- 这里设置了Height等于设置了DataBindGrid的行高 -->
<TextBlock Text="{Binding Name0}" Margin="10,0,0,0" Grid.Column="0" MouseDown="AddDataClick"></TextBlock>
<TextBlock Text="{Binding Name1}" Margin="10,0,0,0" Grid.Column="1" MouseDown="DeleteDataClick"></TextBlock>
<TextBlock Text="{Binding Name2}" Margin="10,0,0,0" Grid.Column="2"></TextBlock>
<TextBlock Text="{Binding Name3}" Margin="10,0,0,0" Grid.Column="3"></TextBlock>
</Grid>
</ControlTemplate>
</local:DataBindGrid.ItemTemplate>
</local:DataBindGrid>
</ScrollViewer>
*/
public class DataBindGrid:Grid
{
public static readonly DependencyProperty ItemTemplateProperty= DependencyProperty.Register("ItemTemplate", typeof(ControlTemplate), typeof(DataBindGrid), null);
public ControlTemplate ItemTemplate
{
get
{
return (ControlTemplate)GetValue(ItemTemplateProperty);
}
set
{
SetValue(ItemTemplateProperty, value);
}
}
public static readonly DependencyProperty ItemsSourceProperty = DependencyProperty.Register("ItemsSource", typeof(System.Collections.IEnumerable), typeof(DataBindGrid), new PropertyMetadata(OnItemsSourcePropertyValueChanged));
private static void OnItemsSourcePropertyValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
DataBindGrid grid = (DataBindGrid)d;
if (e.OldValue != null && e.OldValue is INotifyCollectionChanged data)
{
data.CollectionChanged -= grid._notifyCollectionChanged_CollectionChanged;
}
grid._notifyCollectionChanged = e.NewValue as INotifyCollectionChanged;
if (grid._notifyCollectionChanged != null && grid._notifyCollectionChanged is INotifyCollectionChanged data2)
{
data2.CollectionChanged += grid._notifyCollectionChanged_CollectionChanged;
}
grid.Bind();
}
public System.Collections.IEnumerable ItemsSource
{
get
{
return (System.Collections.IEnumerable)GetValue(ItemsSourceProperty);
}
set
{
SetValue(ItemsSourceProperty, value);
}
}
public delegate void CreateRowDefinitionHandler(object sender, RowDefinition row, int rowIndex);
INotifyCollectionChanged _notifyCollectionChanged;
public event CreateRowDefinitionHandler CreateRowDefinition;
ConcurrentDictionary<object, int> _dataContextDict = new ConcurrentDictionary<object, int>();
List<FrameworkElement> _headerChildren = new List<FrameworkElement>();
public DataBindGrid()
{
}
private void _notifyCollectionChanged_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
this.Dispatcher.Invoke(() =>
{
if (e.Action == NotifyCollectionChangedAction.Remove)
{
foreach (var data in e.OldItems)
{
var index = _dataContextDict[data];
_dataContextDict.TryRemove(data, out int o);
removeRow(index);
}
}
else if (e.Action == NotifyCollectionChangedAction.Reset)
{
this.Bind();
}
else if (e.Action == NotifyCollectionChangedAction.Add)
{
var newStartIndex = e.NewStartingIndex;
if (_headerChildren.Count > 0)
newStartIndex++;
for (int i = 0; i < e.NewItems.Count; i++)
{
var row = new RowDefinition();
if (this.CreateRowDefinition != null)
{
this.CreateRowDefinition(this, row, i + newStartIndex);
}
this.RowDefinitions.Insert(i + newStartIndex, row);
}
foreach (var pair in _dataContextDict)
{
if (pair.Value >= newStartIndex)
{
var index = pair.Value + e.NewItems.Count;
_dataContextDict[pair.Key] = index;
for (int i = 0; i < this.Children.Count; i++)
{
var ctrl = (FrameworkElement)this.Children[i];
if (ctrl.DataContext == pair.Key)
{
ctrl.SetValue(Grid.RowProperty, index);
}
}
}
}
var rowIndex = newStartIndex;
foreach (var data in e.NewItems)
{
_dataContextDict[data] = rowIndex;
createRowControls(data, rowIndex);
rowIndex++;
}
}
});
}
void removeRow(int rowIndex)
{
for (int i = 0; i < this.Children.Count; i++)
{
var ctrl = this.Children[i];
var rowvalue = ctrl.GetValue(Grid.RowProperty);
if (rowvalue != null && rowvalue.Equals(rowIndex))
{
this.Children.RemoveAt(i);
i--;
}
}
this.RowDefinitions.RemoveAt(rowIndex);
foreach (var pair in _dataContextDict)
{
if (pair.Value >= rowIndex)
{
var index = pair.Value - 1;
_dataContextDict[pair.Key] = index;
for (int i = 0; i < this.Children.Count; i++)
{
var ctrl = (FrameworkElement)this.Children[i];
if (ctrl.DataContext == pair.Key)
{
ctrl.SetValue(Grid.RowProperty, index);
}
}
}
}
}
/// <summary>
/// 创建行的子控件
/// </summary>
/// <param name="data"></param>
/// <param name="rowIndex"></param>
void createRowControls(object data, int rowIndex)
{
var rowDef = this.RowDefinitions[rowIndex];
var templateContainer = this.ItemTemplate.LoadContent() as Panel;
if (templateContainer == null)
throw new Exception("ItemTemplate的根元素必须是Panel");
if (double.IsNaN(templateContainer.Height) == false)
rowDef.Height = new GridLength(templateContainer.Height);
rowDef.MinHeight = templateContainer.MinHeight;
rowDef.MaxHeight = templateContainer.MaxHeight;
while (templateContainer.Children.Count > 0)
{
var ctrl = (FrameworkElement)templateContainer.Children[0];
templateContainer.Children.RemoveAt(0);
ctrl.DataContext = data;
ctrl.SetValue(Grid.RowProperty, rowIndex);
this.Children.Add(ctrl);
}
templateContainer = null;
}
void Bind()
{
if (_headerChildren.Count == 0)
{
foreach (FrameworkElement ctrl in this.Children)
{
_headerChildren.Add(ctrl);
}
}
_dataContextDict.Clear();
for (int i = 0; i < this.Children.Count; i++)
{
var ctrl = this.Children[i];
if (_headerChildren.Contains(ctrl) == false)
{
this.Children.RemoveAt(i);
i--;
}
}
var rowIndex = 0;
if (_headerChildren.Count > 0)
{
if (rowIndex >= this.RowDefinitions.Count)
{
var row = new RowDefinition();
if (this.CreateRowDefinition != null)
{
this.CreateRowDefinition(this, row, rowIndex);
}
this.RowDefinitions.Add(row);
}
rowIndex++;
}
if (this.ItemTemplate == null)
return;
var list = (System.Collections.IEnumerable)_notifyCollectionChanged;
foreach (var dataitem in list)
{
_dataContextDict[dataitem] = rowIndex;
if (rowIndex >= this.RowDefinitions.Count)
{
var row = new RowDefinition();
if (this.CreateRowDefinition != null)
{
this.CreateRowDefinition(this, row, rowIndex);
}
this.RowDefinitions.Add(row);
}
createRowControls(dataitem, rowIndex);
rowIndex++;
}
}
}
}