Question

J'ai ce UserControl défini dans XAML et je voudrais définir dynamiquement le ItemsPanelTemplate dans mon code derrière la classe (pas dans le XAML comme dans l'exemple):

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

J'ai essayé quelque chose comme

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

mais a lamentablement échoué.Avez-vous de l'aide?

Contexte: Je ne connais que le nombre de colonnes et de lignes de la grille lors de l'exécution.

Était-ce utile?

La solution

Vous devez créer un ItemsPanelTemplate et définir son VisualTree sur FrameworkElementFactory (obsolète) qui crée le Grid, ou utilisez le XamlReader à analyser une chaîne XAML qui spécifie le modèle.

Cette question contient des exemples d'utilisation des deux méthodes (bien que pour une propriété de modèle différente).

Une méthode plus simple pour manipuler le panneau lors de l'exécution est décrite dans ce question .

Autres conseils

Vous pouvez faire ce que vous voulez en créant MannualCode dans le code derrière comme: 1. Créez une méthode comme suit qui renverra un 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. Maintenant, ajoutez ce modèle dans votre Listbox ItemsPanel en tant que:

       MyListBox.ItemsPanel = GetItemsPanelTemplate();
    

Cela fonctionne très bien pour moi.J'espère que cela aidera.

Continuez à coder .... :)

Dans le cas où vous auriez encore du travail à faire avec les éléments, vous devriez prendre le code (étendu) suivant:

Nous avons d'abord besoin d'un assistant pour obtenir l'élément:

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

Nous créons maintenant le panneau (ou quelque chose):

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

Voici un programme basé sur XAML qui utilise ItemsPanelTemplate avec 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}";
        }
    }
}

C'est un simple éditeur de texte avec une barre d'état:

 entrez la description de l'image ici

Voici le programme équivalent avec le code en C # au lieu 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 version C # est beaucoup plus verbeuse.Cependant, avec l'aide de certaines méthodes d'extension, il peut être écrit dans un style fluide, éliminant les variables intermédiaires:

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

Voici les méthodes d'extension utilisées:

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

}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top