diff --git a/RazorEngineTest/ExHelper.cs b/RazorEngineTest/ExHelper.cs new file mode 100644 index 0000000..552cf9f --- /dev/null +++ b/RazorEngineTest/ExHelper.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Media; +using System.Windows; + +namespace RazorEngineTest +{ + public static class ExHelper + { + public static T? FindVisualChild(this DependencyObject parent, string name = "") where T : DependencyObject + { + for (int i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++) + { + var child = VisualTreeHelper.GetChild(parent, i); + if (child is T result) + { + if (string.IsNullOrEmpty(name)) return result; + else if (result is FrameworkElement element && element.Name == name) return result; + } + var descendant = child.FindVisualChild(name); + if (descendant != null) return descendant; + } + return null; + } + } +} diff --git a/RazorEngineTest/MainWindow.xaml b/RazorEngineTest/MainWindow.xaml index da82ba2..999899c 100644 --- a/RazorEngineTest/MainWindow.xaml +++ b/RazorEngineTest/MainWindow.xaml @@ -5,22 +5,37 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:RazorEngineTest" mc:Ignorable="d" - Title="MainWindow" Height="450" Width="800"> + Title="MainWindow" Height="500" Width="800"> - - + + + + + + + + + + + + + + diff --git a/RazorEngineTest/MainWindow.xaml.cs b/RazorEngineTest/MainWindow.xaml.cs index b0ac98a..06b908c 100644 --- a/RazorEngineTest/MainWindow.xaml.cs +++ b/RazorEngineTest/MainWindow.xaml.cs @@ -20,5 +20,13 @@ namespace RazorEngineTest { InitializeComponent(); } + + private void Button_Click(object sender, RoutedEventArgs e) + { + Button c1 = new Button() { Content = "Button", Background = Brushes.Red, HorizontalAlignment = HorizontalAlignment.Stretch, VerticalAlignment = VerticalAlignment.Stretch }; + Grid.SetColumn(c1, 1); + Grid.SetRow(c1, 1); + this.myGrid.Children.Add(c1); + } } } \ No newline at end of file diff --git a/RazorEngineTest/MyGrid.cs b/RazorEngineTest/MyGrid.cs new file mode 100644 index 0000000..dc34bf9 --- /dev/null +++ b/RazorEngineTest/MyGrid.cs @@ -0,0 +1,155 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.ComponentModel; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Reflection; +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.Markup; +using System.Windows.Media; +using System.Windows.Media.Animation; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace RazorEngineTest +{ + [ContentProperty("Children")] + [TemplatePart(Name = "PART_ChildrenContainer", Type = typeof(ItemsControl))] + public class MyGrid : Control + { + [AllowNull] + private ItemsControl PART_ChildrenContainer; + [AllowNull] + private Grid ChildrenContainer; + static MyGrid() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(MyGrid), new FrameworkPropertyMetadata(typeof(MyGrid))); + } + public MyGrid() + { + this.Children = new UICollection(); + this.RowDefinitions = new RowDefinitions(); + this.ColDefinitions = new ColDefinitions(); + } + public override void OnApplyTemplate() + { + base.OnApplyTemplate(); + this.PART_ChildrenContainer = this.GetTemplateChild("PART_ChildrenContainer") as ItemsControl; + if (this.PART_ChildrenContainer != null) + this.PART_ChildrenContainer.Loaded += PART_ChildrenContainer_Loaded; + else throw new ArgumentNullException($"「{nameof(MyGrid)}」模版必须定义名称为「PART_ChildrenContainer」的「ItemsControl」类型子元素容器..."); + } + + private void PART_ChildrenContainer_Loaded(object sender, RoutedEventArgs e) + { + this.ChildrenContainer = this.PART_ChildrenContainer.FindVisualChild("ChildrenContainer"); + if (this.ChildrenContainer != null) + { + this.ChildrenContainer.ShowGridLines = DesignerProperties.GetIsInDesignMode(this); + + this.ChildrenContainer.RowDefinitions.Clear(); + foreach (var row in this.RowDefinitions) this.ChildrenContainer.RowDefinitions.Add(row); + + this.ChildrenContainer.ColumnDefinitions.Clear(); + foreach (var col in this.ColDefinitions) this.ChildrenContainer.ColumnDefinitions.Add(col); + } + } + /// + /// 子元素集合 + /// + public UICollection Children + { + get { return (UICollection)GetValue(ChildrenProperty); } + set { SetValue(ChildrenProperty, value); } + } + public static readonly DependencyProperty ChildrenProperty = + DependencyProperty.Register("Children", typeof(UICollection), typeof(MyGrid), new PropertyMetadata(null, + (d, e) => (d as MyGrid)?.Children_PropertyChangedCallback(e))); + /// + /// 处理「MyGrid.Children」属性变更 + /// + protected virtual void Children_PropertyChangedCallback(DependencyPropertyChangedEventArgs e) + { + if (e.OldValue is UICollection oldUIColl) oldUIColl.CollectionChanged -= UICollection_CollectionChanged; + if (e.NewValue is UICollection newUIColl) newUIColl.CollectionChanged += UICollection_CollectionChanged; + } + + protected virtual void UICollection_CollectionChanged(object? sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) + { + //TODO:这里可以处理逻辑树的父子级关系 + } + /// + /// 行定义 + /// + public RowDefinitions RowDefinitions + { + get { return (RowDefinitions)GetValue(RowDefinitionsProperty); } + protected internal set { SetValue(RowDefinitionsPropertyKey, value); } + } + public static readonly DependencyPropertyKey RowDefinitionsPropertyKey = + DependencyProperty.RegisterReadOnly("RowDefinitions", typeof(RowDefinitions), typeof(MyGrid), new PropertyMetadata(null, + (d, e) => (d as MyGrid)?.RowDefinitions_PropertyChangedCallback(e))); + public static readonly DependencyProperty RowDefinitionsProperty = RowDefinitionsPropertyKey.DependencyProperty; + /// + /// 处理「MyGrid.RowDefinitions」属性变更 + /// + protected virtual void RowDefinitions_PropertyChangedCallback(DependencyPropertyChangedEventArgs e) + { + if (e.OldValue is RowDefinitions oldRows) oldRows.CollectionChanged -= Rows_CollectionChanged; + if (e.NewValue is RowDefinitions newRows) newRows.CollectionChanged += Rows_CollectionChanged; + } + + private void Rows_CollectionChanged(object? sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) + { + if (this.ChildrenContainer != null) + { + this.ChildrenContainer.RowDefinitions.Clear(); + foreach (var row in this.RowDefinitions) + this.ChildrenContainer.RowDefinitions.Add(row); + } + } + + /// + /// 列定义 + /// + public ColDefinitions ColDefinitions + { + get { return (ColDefinitions)GetValue(ColDefinitionsProperty); } + protected internal set { SetValue(ColDefinitionsPropertyKey, value); } + } + public static readonly DependencyPropertyKey ColDefinitionsPropertyKey = + DependencyProperty.RegisterReadOnly("ColDefinitions", typeof(ColDefinitions), typeof(MyGrid), new PropertyMetadata(null, + (d, e) => (d as MyGrid)?.ColDefinitions_PropertyChangedCallback(e))); + public static readonly DependencyProperty ColDefinitionsProperty = ColDefinitionsPropertyKey.DependencyProperty; + /// + /// 处理「MyGrid.ColDefinitions」属性变更 + /// + protected virtual void ColDefinitions_PropertyChangedCallback(DependencyPropertyChangedEventArgs e) + { + if (e.OldValue is ColDefinitions oldCols) oldCols.CollectionChanged -= Cols_CollectionChanged; + if (e.NewValue is ColDefinitions newCols) newCols.CollectionChanged += Cols_CollectionChanged; + } + + private void Cols_CollectionChanged(object? sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) + { + if (this.ChildrenContainer != null) + { + this.ChildrenContainer.ColumnDefinitions.Clear(); + foreach (var col in this.ColDefinitions) + this.ChildrenContainer.ColumnDefinitions.Add(col); + } + } + } + [DefaultMember("Items")] + public class RowDefinitions : ObservableCollection { public RowDefinitions() { } } + [DefaultMember("Items")] + public class ColDefinitions : ObservableCollection { public ColDefinitions() { } } +} diff --git a/RazorEngineTest/Themes/Generic.xaml b/RazorEngineTest/Themes/Generic.xaml index a860c72..7c9bd91 100644 --- a/RazorEngineTest/Themes/Generic.xaml +++ b/RazorEngineTest/Themes/Generic.xaml @@ -95,4 +95,24 @@ + + diff --git a/RazorEngineTest/UICollection.cs b/RazorEngineTest/UICollection.cs new file mode 100644 index 0000000..e1c452b --- /dev/null +++ b/RazorEngineTest/UICollection.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; + +namespace RazorEngineTest +{ + public class UICollection : ObservableCollection + { + public UICollection() { } + } +}