How to set ItemsPanelTemplate to a dynamically created Grid in code behind

后端 未结 4 1088
我在风中等你
我在风中等你 2021-01-18 09:20

I\'ve got this UserControl defined in XAML and would like to set the ItemsPanelTemplate dynamically in my code behind class (not in th

4条回答
  •  孤城傲影
    2021-01-18 09:50

    Here's a XAML based program which uses ItemsPanelTemplate with a Grid:

    MainWindow.xaml:

    
    
        
    
            
    
                
    
                    
    
                        
    
                            
    
                                
                                
                                
                                
                                
    
                            
    
                        
    
                    
    
                
    
                
                    
                
    
                
    
                
                    
                
    
                
    
                
                    
                
    
            
    
            
    
        
    
    
    

    MainWindow.xaml.cs:

    using System.Windows;
    
    namespace WpfTutorialStatusBarGrid
    {
        /// 
        /// Interaction logic for MainWindow.xaml
        /// 
        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
            }
    
            private void TxtEditor_SelectionChanged(object sender, RoutedEventArgs e)
            {
                var row = txtEditor.GetLineIndexFromCharacterIndex(txtEditor.CaretIndex);
                var col = txtEditor.CaretIndex - txtEditor.GetCharacterIndexFromLineIndex(row);
    
                lblCursorPosition.Text = $"Line {row + 1}, Char {col + 1}";
            }
        }
    }
    

    It's a simple text editor with a status bar:

    Here's the equivalent program with the code in C# instead of XAML:

    MainWindow.xaml:

    
        
    
        
    
    

    MainWindow.xaml.cs:

    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Controls.Primitives;
    
    namespace WpfTutorialStatusBarGridCs
    {
        /// 
        /// Interaction logic for MainWindow.xaml
        /// 
        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
    
                var dock_panel = new DockPanel();
    
                Content = dock_panel;
    
    
                var status_bar = new StatusBar();
    
                dock_panel.Children.Add(status_bar);
    
                DockPanel.SetDock(status_bar, Dock.Bottom);
    
                var items_panel_template = new ItemsPanelTemplate();
    
                {
                    var grid_factory = new FrameworkElementFactory(typeof(Grid));
    
                    {
                        {
                            var col = new FrameworkElementFactory(typeof(ColumnDefinition));
    
                            col.SetValue(ColumnDefinition.WidthProperty, new GridLength(100));
    
                            grid_factory.AppendChild(col);
                        }
    
                        {
                            var col = new FrameworkElementFactory(typeof(ColumnDefinition));
    
                            col.SetValue(ColumnDefinition.WidthProperty, new GridLength(1, GridUnitType.Auto));
    
                            grid_factory.AppendChild(col);
                        }
    
                        {
                            var col = new FrameworkElementFactory(typeof(ColumnDefinition));
    
                            col.SetValue(ColumnDefinition.WidthProperty, new GridLength(1, GridUnitType.Star));
    
                            grid_factory.AppendChild(col);
                        }
    
                        {
                            var col = new FrameworkElementFactory(typeof(ColumnDefinition));
    
                            col.SetValue(ColumnDefinition.WidthProperty, new GridLength(1, GridUnitType.Auto));
    
                            grid_factory.AppendChild(col);
                        }
    
                        {
                            var col = new FrameworkElementFactory(typeof(ColumnDefinition));
    
                            col.SetValue(ColumnDefinition.WidthProperty, new GridLength(100));
    
                            grid_factory.AppendChild(col);
                        }
                    }
    
                    items_panel_template.VisualTree = grid_factory;
                }
    
                status_bar.ItemsPanel = items_panel_template;
    
    
    
                var text_block = new TextBlock();
    
    
                {
                    var status_bar_item = new StatusBarItem();
    
                    Grid.SetColumn(status_bar_item, 0);
    
                    status_bar_item.Content = text_block;
    
                    status_bar.Items.Add(status_bar_item);
                }
    
                {
                    var separator = new Separator();
    
                    Grid.SetColumn(separator, 1);
    
                    status_bar.Items.Add(separator);
                }
    
                {
                    var status_bar_item = new StatusBarItem();
    
                    Grid.SetColumn(status_bar_item, 2);
    
                    status_bar_item.Content = new TextBlock() { Text = "abc" };
    
                    status_bar.Items.Add(status_bar_item);
                }
    
                {
                    var separator = new Separator();
    
                    Grid.SetColumn(separator, 3);
    
                    status_bar.Items.Add(separator);
                }
    
                {
                    var status_bar_item = new StatusBarItem();
    
                    Grid.SetColumn(status_bar_item, 4);
    
                    status_bar_item.Content = new ProgressBar() { Value = 50, Width = 90, Height = 16 };
    
                    status_bar.Items.Add(status_bar_item);
                }
    
                {
                    var text_box = new TextBox() { AcceptsReturn = true };
    
                    text_box.SelectionChanged += (sender, e) => 
                    {
                        var row = text_box.GetLineIndexFromCharacterIndex(text_box.CaretIndex);
                        var col = text_box.CaretIndex - text_box.GetCharacterIndexFromLineIndex(row);
    
                        text_block.Text = $"Line {row + 1}, Char {col + 1}";
                    };
    
                    dock_panel.Children.Add(text_box);
                }
            }
        }
    }
    

    The C# version is much more verbose. However, with the help of some extension methods, it can be written in a fluent style, eliminating the intermediate variables:

    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
    
            var text_block = new TextBlock();
    
            Content = new DockPanel()
    
                .AddChildren(
    
                    new StatusBar()
                        .SetDock(Dock.Bottom)
                        .SetItemsPanel(
                            new ItemsPanelTemplate()
                                .SetVisualTree(
                                    new FrameworkElementFactory(typeof(Grid))
                                        .AppendChildren(
                                            new FrameworkElementFactory(typeof(ColumnDefinition))
                                                .SetValue_(ColumnDefinition.WidthProperty, new GridLength(100)),
                                            new FrameworkElementFactory(typeof(ColumnDefinition))
                                                .SetValue_(ColumnDefinition.WidthProperty, new GridLength(1, GridUnitType.Auto)),
                                            new FrameworkElementFactory(typeof(ColumnDefinition))
                                                .SetValue_(ColumnDefinition.WidthProperty, new GridLength(1, GridUnitType.Star)),
                                            new FrameworkElementFactory(typeof(ColumnDefinition))
                                                .SetValue_(ColumnDefinition.WidthProperty, new GridLength(1, GridUnitType.Auto)),
                                            new FrameworkElementFactory(typeof(ColumnDefinition))
                                                .SetValue_(ColumnDefinition.WidthProperty, new GridLength(100)))))
                        .AddItems(
                            new StatusBarItem() { Content = text_block }.SetColumn(0),
                            new Separator().SetColumn(1),
                            new StatusBarItem() { Content = new TextBlock() { Text = "abc" } }.SetColumn(2),
                            new Separator().SetColumn(3),
                            new StatusBarItem() { Content = new ProgressBar() { Value = 50, Width = 90, Height = 16 } }.SetColumn(4)),
    
                    new TextBox() { AcceptsReturn = true }
                        .AddSelectionChanged(
                            (sender, e) =>
                            {
                                var box = sender as TextBox;
    
                                var row = box.GetLineIndexFromCharacterIndex(box.CaretIndex);
                                var col = box.CaretIndex - box.GetCharacterIndexFromLineIndex(row);
    
                                text_block.Text = $"Line {row + 1}, Char {col + 1}";
                            }));
        }
    }
    

    Here are the extension methods used:

    public static class Extensions
    {
        public static T SetDock(this T element, Dock dock) where T : UIElement
        {
            DockPanel.SetDock(element, dock);
    
            return element;
        }
    
        public static T SetColumn(this T element, int value) where T : UIElement
        {
            Grid.SetColumn(element, value);
    
            return element;
        }
    
        public static T SetValue_(this T factory, DependencyProperty dp, object value) where T : FrameworkElementFactory
        {
            factory.SetValue(dp, value);
    
            return factory;
        }
    
        public static T AppendChildren(this T factory, params FrameworkElementFactory[] children) where T : FrameworkElementFactory
        {
            foreach (var child in children)
                factory.AppendChild(child);
    
            return factory;
        }
    
        public static T SetVisualTree(this T template, FrameworkElementFactory factory) where T : FrameworkTemplate
        {
            template.VisualTree = factory;
    
            return template;
        }
    
        public static T1 SetItemsPanel(this T1 control, T2 template) where T1 : ItemsControl where T2 : ItemsPanelTemplate
        {
            control.ItemsPanel = template;
    
            return control;
        }
    
        public static T AddItems(this T control, params object[] items) where T : ItemsControl
        {
            foreach (var item in items)
                control.Items.Add(item);
    
            return control;
        }
    
        public static T AddSelectionChanged(this T obj, RoutedEventHandler handler) where T : TextBoxBase
        {
            obj.SelectionChanged += handler;
    
            return obj;
        }
    
        public static T1 AddChildren(this T1 panel, params UIElement[] elements) where T1 : Panel
        {
            foreach (var elt in elements)
                panel.Children.Add(elt);
    
            return panel;
        }
    
    }
    

提交回复
热议问题