Pregunta

tengo esto UserControl definido en XAML y me gustaría establecer el ItemsPanelTemplate dinámicamente en mi código detrás de clase (no en el XAML como en el ejemplo):

<UserControl>
    <ItemsControl x:Name="Items">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <Grid> <!-- I want to add this Grid definition in code behind -->
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition />
                    </Grid.ColumnDefinitions>
                    <Grid.RowDefinitions>
                        <RowDefinition />
                    </Grid.RowDefinitions>
                </Grid>
            </ItemsPanelTemplate>
       </ItemsControl.ItemsPanel>
    </ItemsControl>
</UserControl>

Intenté algo como

this.Items.ItemsPanel.Template = new Grid();

pero falló miserablemente. ¿Alguna ayuda?

Fondo:Solo sé el número de columnas y filas de cuadrícula en tiempo de ejecución.

¿Fue útil?

Solución

Necesitas crear un ItemsPanelTemplate Y establece que es VisualTree a un FrameworkElementFactory (desaprobado) que crea el Grid, o usar el XamlReader a analizar gramaticalmente Una cuerda XAML que especifica la plantilla.

Esta pregunta Contiene ejemplos de uso de ambos métodos (aunque para una propiedad de plantilla diferente).

Un método más fácil para manipular el panel en tiempo de ejecución se describe en esta pregunta.

Otros consejos

Puede hacer lo que desee creando MannualCode en código detrás como: 1. Cree un método que siga el que devolverá un elemento PanelTemplate

     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. Ahora agregue esta plantilla en su ListBox ElememsPanel como:

       MyListBox.ItemsPanel = GetItemsPanelTemplate();
    

Esto funciona bien para mí. Espero que esto ayude.

Sigue codificando .... :)

En caso de que aún tenga algo de trabajo que ver con los elementos, debe tomar el siguiente código (extendido):

Primero necesitamos un ayudante para obtener el elemento:

// --------------------------------------------------------------------
// 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);
}

Ahora creamos el panel (o algo):

// --------------------------------------------------------------------
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);
  };
}

Aquí hay un programa basado en XAML que utiliza ItemsPanelTemplate con un 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}";
        }
    }
}

Es un editor de texto simple con una barra de estado:

enter image description here

Aquí está el programa equivalente con el código en C# en lugar de 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);
            }
        }
    }
}

La versión C# es mucho más detallada. Sin embargo, con la ayuda de algunos métodos de extensión, se puede escribir en un estilo fluido, eliminando las variables intermedias:

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}";
                        }));
    }
}

Aquí están los métodos de extensión utilizados:

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;
    }

}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top