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

后端 未结 4 1001
我在风中等你
我在风中等你 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:45

    You can do as you want by creating MannualCode in code behind as: 1. Create a Method as following which will return a ItemsPanelTemplate

         private ItemsPanelTemplate GetItemsPanelTemplate()
        {
            string xaml = @"<ItemsPanelTemplate   xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation' xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
                                <Grid>
                                    <Grid.ColumnDefinitions>
                                        <ColumnDefinition />
                                    </Grid.ColumnDefinitions>
                                    <Grid.RowDefinitions>
                                        <RowDefinition />
                                    </Grid.RowDefinitions>
                                </Grid>
                        </ItemsPanelTemplate>";
            return XamlReader.Parse(xaml) as ItemsPanelTemplate;
        }
    
    1. Now add this template in your Listbox ItemsPanel as:

         MyListBox.ItemsPanel = GetItemsPanelTemplate();
      

    This is working fine for me. Hope this will help.

    Keep Coding....:)

    0 讨论(0)
  • 2021-01-18 09:47

    In case that you still have some work to do with the elements, you should take the following (extended) code:

    First we need a helper in order to get the element:

    // --------------------------------------------------------------------
    // This function fetches the WrapPanel from oVisual.
    private WrapPanel m_FetchWrapPanel (Visual oVisual)
    {
      // WrapPanel to be returned
      WrapPanel oWrapPanel = null;
      // number of childs of oVisual
      int iNumberChilds = VisualTreeHelper.GetChildrenCount (oVisual);
      // and running through the childs
      int i = 0;
      while ( ( i < iNumberChilds ) && ( oWrapPanel == null ) )
      { // fetching visual
        Visual oVisualChild = 
          ( VisualTreeHelper.GetChild (oVisual, i) as Visual );
        if ( ( oVisualChild is WrapPanel ) is true )
        { // found
           oWrapPanel = ( oVisualChild as WrapPanel );
        }
        else
        { // checking the childs of oVisualChild 
          oWrapPanel = m_FetchWrapPanel (oVisualChild);
        };
        // checking next child
        i++;
      };
      // returning WrapPanel
      return (oWrapPanel);
    }
    

    Now we create the Panel (or something):

    // --------------------------------------------------------------------
    private void m_SettingTemplate ()
    {
      // the online doc recommends to parse the template
      string xaml = 
        @"<ItemsPanelTemplate
              xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'
              xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
            <WrapPanel ItemWidth=""150"" MaxWidth=""150""/>
          </ItemsPanelTemplate>";
      // assigning the template
      oMyListView.ItemsPanel = ( System.Windows.Markup.XamlReader.Parse (xaml) as ItemsPanelTemplate );
      // fetching the WrapPanel
      WrapPanel oWrapPanel = m_WrapPanelAusVisualHolen (oMyListView);
      Debug.Assert (oWrapPanel != null);
      if ( oWrapPanel != null )
      { // adjusting the size of the WrapPanel to the ListView
        Binding oBinding = new Binding ("ActualWidth");
        oBinding.Source = oMyListView;
        oWrapPanel.SetBinding (WrapPanel.MaxWidthProperty, oBinding);
      };
    }
    
    0 讨论(0)
  • 2021-01-18 09:50

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

    MainWindow.xaml:

    <Window x:Class="WpfTutorialStatusBarGrid.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:WpfTutorialStatusBarGrid"
            mc:Ignorable="d"
            Title="MainWindow" Height="450" Width="800">
    
        <DockPanel>
    
            <StatusBar DockPanel.Dock="Bottom">
    
                <StatusBar.ItemsPanel>
    
                    <ItemsPanelTemplate>
    
                        <Grid>
    
                            <Grid.ColumnDefinitions>
    
                                <ColumnDefinition Width="100" />
                                <ColumnDefinition Width="Auto" />
                                <ColumnDefinition Width="*" />
                                <ColumnDefinition Width="Auto" />
                                <ColumnDefinition Width="100" />
    
                            </Grid.ColumnDefinitions>
    
                        </Grid>
    
                    </ItemsPanelTemplate>
    
                </StatusBar.ItemsPanel>
    
                <StatusBarItem Grid.Column="0">
                    <TextBlock Name="lblCursorPosition" />
                </StatusBarItem>
    
                <Separator Grid.Column="1"/>
    
                <StatusBarItem Grid.Column="2">
                    <TextBlock Text="c:\temp\abc.txt"/>
                </StatusBarItem>
    
                <Separator Grid.Column="3"/>
    
                <StatusBarItem Grid.Column="4">
                    <ProgressBar Value="50" Width="90" Height="16"/>
                </StatusBarItem>
    
            </StatusBar>
    
            <TextBox AcceptsReturn="True" Name="txtEditor" SelectionChanged="TxtEditor_SelectionChanged"/>
    
        </DockPanel>
    
    </Window>
    

    MainWindow.xaml.cs:

    using System.Windows;
    
    namespace WpfTutorialStatusBarGrid
    {
        /// <summary>
        /// Interaction logic for MainWindow.xaml
        /// </summary>
        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:

    <Window x:Class="WpfTutorialStatusBarGridCs.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:WpfTutorialStatusBarGridCs"
            mc:Ignorable="d"
            Title="MainWindow" Height="450" Width="800">
        <Grid>
    
        </Grid>
    </Window>
    

    MainWindow.xaml.cs:

    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Controls.Primitives;
    
    namespace WpfTutorialStatusBarGridCs
    {
        /// <summary>
        /// Interaction logic for MainWindow.xaml
        /// </summary>
        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<T>(this T element, Dock dock) where T : UIElement
        {
            DockPanel.SetDock(element, dock);
    
            return element;
        }
    
        public static T SetColumn<T>(this T element, int value) where T : UIElement
        {
            Grid.SetColumn(element, value);
    
            return element;
        }
    
        public static T SetValue_<T>(this T factory, DependencyProperty dp, object value) where T : FrameworkElementFactory
        {
            factory.SetValue(dp, value);
    
            return factory;
        }
    
        public static T AppendChildren<T>(this T factory, params FrameworkElementFactory[] children) where T : FrameworkElementFactory
        {
            foreach (var child in children)
                factory.AppendChild(child);
    
            return factory;
        }
    
        public static T SetVisualTree<T>(this T template, FrameworkElementFactory factory) where T : FrameworkTemplate
        {
            template.VisualTree = factory;
    
            return template;
        }
    
        public static T1 SetItemsPanel<T1,T2>(this T1 control, T2 template) where T1 : ItemsControl where T2 : ItemsPanelTemplate
        {
            control.ItemsPanel = template;
    
            return control;
        }
    
        public static T AddItems<T>(this T control, params object[] items) where T : ItemsControl
        {
            foreach (var item in items)
                control.Items.Add(item);
    
            return control;
        }
    
        public static T AddSelectionChanged<T>(this T obj, RoutedEventHandler handler) where T : TextBoxBase
        {
            obj.SelectionChanged += handler;
    
            return obj;
        }
    
        public static T1 AddChildren<T1>(this T1 panel, params UIElement[] elements) where T1 : Panel
        {
            foreach (var elt in elements)
                panel.Children.Add(elt);
    
            return panel;
        }
    
    }
    
    0 讨论(0)
  • 2021-01-18 09:51

    You need to create an ItemsPanelTemplate and set it's VisualTree to a FrameworkElementFactory (deprecated) which creates the Grid, or use the XamlReader to parse a XAML-string which specifies the template.

    This question contains usage examples of both methods (albeit for a different template property).

    An easier method to manipulate the panel at runtime is outlined in this question.

    0 讨论(0)
提交回复
热议问题