IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Windows Presentation Foundation Discussion :

[UWP] binder Grid.Row et Grid.Column


Sujet :

Windows Presentation Foundation

  1. #1
    Expert éminent sénior Avatar de Pol63
    Homme Profil pro
    .NET / SQL SERVER
    Inscrit en
    Avril 2007
    Messages
    14 154
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : .NET / SQL SERVER

    Informations forums :
    Inscription : Avril 2007
    Messages : 14 154
    Points : 25 072
    Points
    25 072
    Par défaut [UWP] binder Grid.Row et Grid.Column
    bonjour,

    j'ai un contentpresenter qui recoit une instance d'objet ayant en propriété un List<machin>
    machin ayant X et Y (int) en propriété (entre autre)

    ce contentpresenter a un datatemplate
    je voudrais un affichage en grille, et que chaque élément se trouve dans la bonne cas via X et Y

    j'étais parti sur un ItemsControl (pour le List<machin>) ayant un ItemsPanel = Grid
    et un ItemTemplate ayant button avec Grid.Row et Grid.Column = {Binding X}

    mais ca ne fonctionne pas, j'ai bien vu quelques workarround sur le net mais qui ne vont pas dans mon cas
    (dont un avec un style, mais qui n'est pas pris en charge par UWP)

    c'est le grid qui est pas codé pour qu'on bind ca ? le button qui trouve pas le grid au dessus ? y a un element au milieu qui fait que grid.row n'est pas atteignable ?
    une autre possibilité que grid pour faire ca ?

    merci
    Cours complets, tutos et autres FAQ ici : C# - VB.NET

  2. #2
    Expert confirmé
    Inscrit en
    Avril 2008
    Messages
    2 564
    Détails du profil
    Informations personnelles :
    Âge : 64

    Informations forums :
    Inscription : Avril 2008
    Messages : 2 564
    Points : 4 441
    Points
    4 441
    Par défaut
    bonjour

    Si ,si le Grid possede bien 2 props attaches Grid.Row et Grid.Column bindables comme le Canvas ,mais il faut passer par l'ItemContanerStyle du ItemsControl ...!!!
    Ce qui est embêtant avec le Grid contrairement au Canvas c'est que les Rows et les Colums doivent etre ajoutés au Grid préalablement !!!
    L'autre embêtement c'est que une fois surmonté ce premier obstacle , comment faire pour fixer le nbre de Rows et Columns en passant d'une liste plate liée à ItemsControl...

    voici le plus simple code possible que j'ai trouvé face à ce sacré grid....
    code behind .cs du class data :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
     
     
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Collections.ObjectModel;
    using System.ComponentModel;
     
    namespace WpfApplication1
    {
        public class MonItem : INotifyPropertyChanged
        {
            private string nom;
            public string Nom
            {
                get { return nom; }
                set { nom = value; RaisePropertyChanged("Nom"); }
            }
     
            private int x;
            public int X
            {
                get { return x; }
                set { x = value; RaisePropertyChanged("X"); }
            }
            private int y;
            public int Y
            {
                get { return y; }
                set { y = value; RaisePropertyChanged("Y"); }
            }
     
            public event PropertyChangedEventHandler PropertyChanged;
            private void RaisePropertyChanged(string propName)
            {
                PropertyChangedEventHandler h = PropertyChanged;
                if (h != null)
                    h(this, new PropertyChangedEventArgs(propName));
            }
        }
        public class MesItems : ObservableCollection<MonItem>
        {
            private MonItem item;
            public MesItems()
            {
     
                for (int i = 0; i < 4; i++)
                {
                    for (int j = 0; j < 6; j++)
                    {
                        string s = (j + 1).ToString() + (i + 1).ToString();
                        item = new MonItem()
                        {
                            Nom = "Item" + s,
                            X = j,
                            Y = i
                        };
                        this.Add(item);
                    }
                }
            }
        }
    }
    code xaml du form :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
     
     
    <Window x:Class="WpfApplication1.Window2"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:WpfApplication1" 
            Title="Window2" Height="300" Width="300">
        <Window.Resources>
            <DataTemplate x:Key="dt"
                          DataType="{x:Type local:Item}">
                <Button Margin="5" Content="{Binding Nom}"
                       Click="Button_Click"
                        />
            </DataTemplate>
        </Window.Resources>
        <Grid DataContext="{Binding }">
            <ItemsControl ItemsSource="{Binding }"
                          ItemTemplate="{StaticResource dt}">
                <ItemsControl.ItemsPanel>
                    <ItemsPanelTemplate>
                        <Grid
                            Margin="10"
                            IsItemsHost="true"
                            ShowGridLines="True" 
                            Loaded="Grid_Loaded"
                          >
                        </Grid>
                    </ItemsPanelTemplate>
                </ItemsControl.ItemsPanel>
                <ItemsControl.ItemContainerStyle>
                    <Style TargetType="ContentPresenter">
                        <Setter Property="Grid.Column" Value="{Binding X}"/>
                        <Setter Property="Grid.Row" Value="{Binding Y}"/>
                    </Style>
                </ItemsControl.ItemContainerStyle>
            </ItemsControl>
        </Grid>
    </Window>
    et son code behind .cs du class data :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
     
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Media;
     
    namespace WpfApplication1
    {
        /// <summary>
        /// Logique d'interaction pour Window2.xaml
        /// </summary>
        public partial class Window2 : Window
        {
            private MesItems liste = null;
     
            public Window2()
            {
                InitializeComponent();
                liste = new MesItems();
                this.DataContext = liste;
            }
     
     
            // on trappe le grid pour l'ajout des lignes et colonnes
            private void Grid_Loaded(object sender, RoutedEventArgs e)
            {
                Grid grd = sender as Grid;
     
                // colonnes
                int cols = liste.Max(o => o.X);
                for (int i = 0; i < cols; i++)
                {
                    ColumnDefinition colDef = new ColumnDefinition();
                    colDef.Width = new GridLength(1.0, GridUnitType.Star);
                    grd.ColumnDefinitions.Add(colDef);
                }
     
                // lignes
     
                int rows = liste.Max(o => o.Y);
     
                for (int i = 0; i < rows; i++)
                {
                    RowDefinition rowDef = new RowDefinition();
                    rowDef.Height = new GridLength(1.0, GridUnitType.Star);
                    grd.RowDefinitions.Add(rowDef);
                }
            }
            public int Count { get {return liste.Count  ;} }
     
            private void Button_Click(object sender, RoutedEventArgs e)
            {
                Button btn = sender as Button;
                btn.Background = br;
            }
            private Random rnd = new Random();
            private SolidColorBrush br
            {
                get { 
                    byte[] b=new byte[3]; 
                    rnd.NextBytes (b);
                    return new SolidColorBrush(
                        Color.FromArgb(255,b[0],b[1],b[2]));
                } 
     
     
            }
     
        }
    }
    ton code dependra du besoin fonctionnel souhaité ...
    bon code ....

  3. #3
    Expert éminent sénior Avatar de Pol63
    Homme Profil pro
    .NET / SQL SERVER
    Inscrit en
    Avril 2007
    Messages
    14 154
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : .NET / SQL SERVER

    Informations forums :
    Inscription : Avril 2007
    Messages : 14 154
    Points : 25 072
    Points
    25 072
    Par défaut
    merci bien pour tout ce code mais ...
    le problème est bien que je suis sur UWP, qui ressemble à WPF mais qui est reparti sur d'autres bases (c'est à la mode en ce moment chez MS)
    et donc il n'y a pas tout pareil

    j'ai du retirer ca :
    Code XAML : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
       IsItemsHost="true"
       ShowGridLines="True"

    et transformer ca
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    <DataTemplate x:Key="dt"
                          x:DataType="local:MonItem">
    (datatype n'existe pas et {x:Type} n'a pas l'air d'être apprécié)

    et au final il me reste une erreur irrémédiable E_UNEXPECTED sur la ligne <Setter Property="Grid.Column" Value="{Binding X}"/>

    ca compile quand même et ca se lance, mais je n'ai qu'un bouton de visible en haut à gauche
    Cours complets, tutos et autres FAQ ici : C# - VB.NET

  4. #4
    Expert confirmé
    Inscrit en
    Avril 2008
    Messages
    2 564
    Détails du profil
    Informations personnelles :
    Âge : 64

    Informations forums :
    Inscription : Avril 2008
    Messages : 2 564
    Points : 4 441
    Points
    4 441
    Par défaut
    bonjour

    Pour DataTemplate la syntaxe XAML a subi une circonvolution sur la page officielle MSDN ainsi (copier-coller) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
     
    <DataTemplate x:DataType="local:Recording">
                            <StackPanel Orientation="Horizontal" Margin="6">
                                <SymbolIcon Symbol="Audio" Margin="0,0,12,0"/>
                                <StackPanel>
                                    <TextBlock Text="{x:Bind ArtistName}" FontWeight="Bold"/>
                                    <TextBlock Text="{x:Bind CompositionName}"/>
                                </StackPanel>
                            </StackPanel>
                        </DataTemplate>
     
                    </ListView.ItemTemplate>
    Nouveaute c'est ce x:Bind mais selon la même page MSDN la syntaxe Binding est aussi admise ....

    lien MSDN fr :

    https://www.google.fr/url?sa=t&rct=j...246,bs.1,d.d2s

    Pour le ItemContainerStyle c'est dramatique selon le forum StackOverflow car il ne supporte plus le binding dans les Setters de Props ,uniquement des valeurs en dur ...
    Pour contourner ce problème un class Helper est requis avec des props attaches qui se charger d'assigner les valeurs aux Grid.Column et Grid.Row...Vraiment bizarre comme solution....
    sur ce lien est fourni leur solution :
    http://www.google.fr/url?sa=t&rct=j&...37132246,d.d2s

    bon code....

  5. #5
    Expert éminent sénior Avatar de Pol63
    Homme Profil pro
    .NET / SQL SERVER
    Inscrit en
    Avril 2007
    Messages
    14 154
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : .NET / SQL SERVER

    Informations forums :
    Inscription : Avril 2007
    Messages : 14 154
    Points : 25 072
    Points
    25 072
    Par défaut
    je vais regarder le lien

    sinon oui il y a x:Bind en plus de Binding
    ca permet moins de choses, mais ce sont des bindings compilés donc plus performants
    Cours complets, tutos et autres FAQ ici : C# - VB.NET

  6. #6
    Expert éminent sénior Avatar de Pol63
    Homme Profil pro
    .NET / SQL SERVER
    Inscrit en
    Avril 2007
    Messages
    14 154
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : .NET / SQL SERVER

    Informations forums :
    Inscription : Avril 2007
    Messages : 14 154
    Points : 25 072
    Points
    25 072
    Par défaut
    ayant créé un panel custom pour faire l'effet du grid comme je le souhaite je viens de voir que le problème n'est pas là où je pensais

    mon datatemplate fait que mes items sont "transformés" en button
    le button a bien une propriété attachée bindée, avec la bonne valeur
    par contre au moment de l'Arrange (placement) les children pour le grid ne sont pas les boutons, mais des contentpresenter contenant un item
    et donc le GetValue sur la propriété attachée ne trouve pas de valeur settée pour ce content presenter

    du coup je comprends pourquoi en wpf on passait par le style, pour que ca soit le contentpresenter qui récupère les valeurs pour les propriétés attachées

    je vais continuer de creuser ...
    Cours complets, tutos et autres FAQ ici : C# - VB.NET

  7. #7
    Expert confirmé
    Inscrit en
    Avril 2008
    Messages
    2 564
    Détails du profil
    Informations personnelles :
    Âge : 64

    Informations forums :
    Inscription : Avril 2008
    Messages : 2 564
    Points : 4 441
    Points
    4 441
    Par défaut
    re

    le button a bien une propriété attachée bindée, avec la bonne valeur
    par contre au moment de l'Arrange (placement) les children pour le grid ne sont pas les boutons, mais des contentpresenter contenant un item
    et donc le GetValue sur la propriété attachée ne trouve pas de valeur settée pour ce content presenter
    Pas bien compris sans le code du custom panel ....
    Mais avec un Grid normal voici un bouton custom qui court-circuite le ItemContainerStyle et se charge de setter lui-même le grid.row et grid.col du ContentPrésenter ( qui se trouve dans la prop VisualParent du bouton)...
    La fonction du ItemContainerStyle est ainsi reporté sur le bouton

    code .cs item data:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
     
     
    namespace WpfApplication4
    {
        public class Item : INotifyPropertyChanged
        {
            private string nom;
            public string Nom
     
            {
                get { return nom; }
                set { nom = value; RaisePropertyChanged("Nom"); }
            }
     
            private int x;
            public int X
            {
                get { return x; }
                set { x = value; RaisePropertyChanged("X"); }
            }
            private int y;
            public int Y
            {
                get { return y; }
                set { y = value; RaisePropertyChanged("Y"); }
            }
     
            public event PropertyChangedEventHandler PropertyChanged;
            private void RaisePropertyChanged(string propName)
            {
                PropertyChangedEventHandler h = PropertyChanged;
                if (h != null)
                    h(this, new PropertyChangedEventArgs(propName));
            }
        }
        public class Items : ObservableCollection<Item>
        {
            private Item item;
            public Items()
            {
     
                int NY = 4;
                int NX = 6;
                for (int i = 0; i < NY; i++)
                {
                    for (int j = 0; j < NX; j++)
                    {
                        string s = i.ToString() + j.ToString();
                        item = new Item()
                        {
                            Nom = "Item" + s,
                            X = j,
                            Y = i
                        };
                        this.Add(item);
                    }
                }
     
            }
        }
    }
    code behind.cs du button custom MyButton:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
     
     
    namespace WpfApplication4
    {
        public class MyButton : Button    
        {
            static MyButton()
            {
                //DefaultStyleKeyProperty.OverrideMetadata(typeof(MyControl), new FrameworkPropertyMetadata(typeof(MyControl)));
            }
            public MyButton()
            { }
     
     
            public int Row
            {
                get { return (int)GetValue(RowProperty); }
                set { SetValue(RowProperty, value); }
            }
     
            // Using a DependencyProperty as the backing store for Row.  This enables animation, styling, binding, etc...
            public static readonly DependencyProperty RowProperty =
                DependencyProperty.Register("Row", 
                typeof(int), typeof(MyButton), 
                new FrameworkPropertyMetadata (0,
                    FrameworkPropertyMetadataOptions.AffectsRender ,OnRowChanged ));
     
            private static void OnRowChanged(DependencyObject d,DependencyPropertyChangedEventArgs args)
            {
                MyButton ct = d as MyButton;
                int row = (int)args.NewValue;
     
     
                ContentPresenter cp = ct.VisualParent as ContentPresenter;
                if (cp != null)
                    Grid.SetRow(cp, row);
                else  //comportement normal s'il est ajoute directement à grid
                    Grid.SetRow(ct, row);
            }
     
     
            public int Col
            {
                get { return (int)GetValue(ColProperty); }
                set { SetValue(ColProperty, value); }
            }
     
            // Using a DependencyProperty as the backing store for Col.  This enables animation, styling, binding, etc...
            public static readonly DependencyProperty ColProperty =
                DependencyProperty.Register("Col", typeof(int),
                typeof(MyButton),
                  new FrameworkPropertyMetadata(0,
                    FrameworkPropertyMetadataOptions.AffectsRender, OnColChanged));
     
            private static void OnColChanged(DependencyObject d, DependencyPropertyChangedEventArgs args)
            {
                MyButton ct = d as MyButton;
                int col = (int)args.NewValue;
                ContentPresenter cp = ct.VisualParent as ContentPresenter;
                if (cp != null) 
                    Grid.SetColumn(cp, col);
                else
                    Grid.SetColumn(ct, col);
     
     
     
     
            }  
        }
    }
    code xaml du form:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
     
    <Window x:Class="WpfApplication4.Window1"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:local="clr-namespace:WpfApplication4"
            Title="Window1" Height="350" Width="525">
        <Window.Resources>
            <!--le click pour recolorier les boutons aleatoirement -->
            <DataTemplate x:Key="dt"
                          DataType="{x:Type local:Item}">
                <local:MyButton 
                    Background="AntiqueWhite"
                    Margin="5" Content="{Binding Nom}"
                       Col="{Binding X}"
                       Row="{Binding Y}"
                       Click="MyControl_Click"          />
            </DataTemplate>
        </Window.Resources>
        <Grid DataContext="{Binding }">
            <ItemsControl ItemsSource="{Binding }"
                          ItemTemplate="{StaticResource dt}">
                <ItemsControl.ItemsPanel>
                    <ItemsPanelTemplate>
                        <Grid
                            Margin="10"
                            ShowGridLines="True" 
                            Loaded="Grid_Loaded"
                          >
                        </Grid>
                    </ItemsPanelTemplate>
                </ItemsControl.ItemsPanel>
                                <!--OUT -->
                <!--<ItemsControl.ItemContainerStyle>
                    <Style TargetType="ContentPresenter">
                        <Setter Property="Grid.Column" Value="{Binding X}"/>
                        <Setter Property="Grid.Row" Value="{Binding Y}"/>
                    </Style>
                </ItemsControl.ItemContainerStyle>-->
            </ItemsControl>
        </Grid>
    </Window>
    et son code behind.cs :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
     
    namespace WpfApplication4
    {
        /// <summary>
        /// Logique d'interaction pour MainWindow.xaml
        /// </summary>
        public partial class Window1 : Window
        {
            private Items liste = null;
            public Window1()
            {
                InitializeComponent();
                liste = new Items();
                this.DataContext = liste;
            }
     
            private void Grid_Loaded(object sender, RoutedEventArgs e)
            {
                Grid grd = sender as Grid;
     
                // colonnes
                int cols = liste.Max(o => o.X);
                for (int i = 0; i < cols; i++)
                {
                    ColumnDefinition colDef = new ColumnDefinition();
                    colDef.Width = new GridLength(1.0, GridUnitType.Star);
                    grd.ColumnDefinitions.Add(colDef);
                }
     
                // lignes
     
                int rows = liste.Max(o => o.Y);
     
                for (int i = 0; i < rows; i++)
                {
                    RowDefinition rowDef = new RowDefinition();
                    rowDef.Height = new GridLength(1.0, GridUnitType.Star);
                    grd.RowDefinitions.Add(rowDef);
                }
            }
            private void MyButton_Click(object sender, RoutedEventArgs e)
            {
                Button btn = sender as Button;
                btn.Background = br;
            }
     
            private Random rnd = new Random();
            private SolidColorBrush br
            {
                get
                {
                    byte[] b = new byte[3];
                    rnd.NextBytes(b);
                    return new SolidColorBrush(
                        Color.FromArgb(255, b[0], b[1], b[2]));
                }
     
     
            }
     
     
        }
    }
    Le precedent code permet de surmonter le handicap du ItemsContainerStyle....


    Pour le custom panel qui est galère entre nous il faut observer:
    Dans l'itération sur la collection InternalChildren du Custom Panel il suffit de caster en ContentPresenter chaque UIElement.
    Sa prop Content contient l'item data avec ses coords X,Y
    Ensuite faire l'arrange nécessaire pour positionner le ContentPresenter....
    On ne peut positionner le bouton car il est contenu dans le DataTemplate qui est injecté dans chaque CP ( le DataTemplate peut etre complexe)..
    Le positionnement du CP entraine le positionnement de tout le contenu du DataTemplate en bloc...
    Le bouton utilisé est un bouton ordinaire ....
    code .cs du panel MyPanel:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
     
    namespace WpfApplication4
    {
        public class MyPanel :Panel 
        {
            static MyPanel()
            {
                //DefaultStyleKeyProperty.OverrideMetadata(typeof(UnGrid), new FrameworkPropertyMetadata(typeof(UnGrid)));
            }
            public MyPanel()
            {
     
     
            }
            protected override Size MeasureOverride(Size constraint)
            {
                if (InternalChildren.Count != 0) SetColumnRow();
     
                foreach (UIElement  child in InternalChildren)
                {
                    child.Measure(constraint);
                }
                return constraint;
     
            }
     
     
            protected override Size ArrangeOverride(Size arrangeSize)
            {
                if (InternalChildren.Count != 0) SetColumnRow();
     
                foreach (UIElement child in InternalChildren)
                {
                    ContentPresenter cp = child as ContentPresenter;
                    Item item = cp.Content  as Item ;
                    Rect rectChild = new Rect(
                        new Point(item.X * child.DesiredSize.Width, item.Y * child.DesiredSize.Height),
                            child.DesiredSize );
                    child.Arrange(rectChild);
                }
                return arrangeSize;
            }
     
            private int Columns = 1;
            private int Rows = 1;
            private void SetColumnRow()
            {
     
                List<Item> l = new List<Item>();
                foreach (UIElement child in InternalChildren)
                {
                    ContentPresenter cp = child as ContentPresenter;
                    l.Add(cp.Content as Item);
                }
                Columns = l.Max(o => o.X);
                Rows = l.Max(o => o.Y);
            }
     
     
     
     
        }
    }
    code xaml du form :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
     
    <Window x:Class="WpfApplication4.Window2"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:WpfApplication4"
            Title="Window2" Height="300" Width="300">
        <Window.Resources>
            <!--le click pour recolorier les boutons aleatoirement -->
            <DataTemplate x:Key="dt"
                          DataType="{x:Type local:Item}">
                <Button 
                   Background="AntiqueWhite"
                    Margin="5"
                    Content="{Binding Nom}"
                    Click="Button_Click"   
                              />
            </DataTemplate>
        </Window.Resources>
        <Grid DataContext="{Binding }">
            <ItemsControl
                ItemsSource="{Binding }"
                ItemTemplate="{StaticResource dt}">
                <ItemsControl.ItemsPanel>
                    <ItemsPanelTemplate>
                        <local:MyPanel
                            Background="Aquamarine"
                            ClipToBounds="True"
                            Margin="10"
                           >
                        </local:MyPanel>
                    </ItemsPanelTemplate>
                </ItemsControl.ItemsPanel>
            </ItemsControl>
        </Grid>
    </Window>
    et son code behind.cs :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
     
    namespace WpfApplication4
    {
        /// <summary>
        /// Logique d'interaction pour Window2.xaml
        /// </summary>
        public partial class Window2 : Window
        {
            private Items liste = null;
            public Window2()
            {
                InitializeComponent();
                liste = new Items();
                this.DataContext = liste;
            }
            private void Button_Click(object sender, RoutedEventArgs e)
            {
                Button btn = sender as Button;
                btn.Background = br;
            }
            private Random rnd = new Random();
            private SolidColorBrush br
            {
                get
                {
                    byte[] b = new byte[3];
                    rnd.NextBytes(b);
                    return new SolidColorBrush(
                        Color.FromArgb(255, b[0], b[1], b[2]));
                }
     
     
            }
     
     
     
     
     
        }
    }
    bon code...........

  8. #8
    Expert éminent sénior Avatar de Pol63
    Homme Profil pro
    .NET / SQL SERVER
    Inscrit en
    Avril 2007
    Messages
    14 154
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : .NET / SQL SERVER

    Informations forums :
    Inscription : Avril 2007
    Messages : 14 154
    Points : 25 072
    Points
    25 072
    Par défaut
    j'avais aussi pensé à faire un bouton qui set col et row sur son parent visuel
    j'hésitais avec trafiquer mon custom panel pour qu'il cherche les attached properties

    sinon mon custom panel c'est un peu comme le grid je pense, ou plutot le uniformgrid, sur measure je donne la size d'une cell en fonction de propriétés ColCount et Rowcount
    et sur arrange je donne la position en fonction de propriétés attachées Col et Row
    mais c'est avec un point d’arrêt par là que j'ai vu que children ne contenait pas les boutons demandés par le template
    Cours complets, tutos et autres FAQ ici : C# - VB.NET

  9. #9
    Expert confirmé
    Inscrit en
    Avril 2008
    Messages
    2 564
    Détails du profil
    Informations personnelles :
    Âge : 64

    Informations forums :
    Inscription : Avril 2008
    Messages : 2 564
    Points : 4 441
    Points
    4 441
    Par défaut
    re

    Mais à part que ton custom panel doit rester simple et dériver de Grid avec simplement 2 props :
    -MaxColumn (nombre de colonnes max gérées)
    -MaxRow (idem)

    L'astuce WPF m'est revenu à l'esprit plus tard car j'avais fait quelque chose de semblable avec un canevas chart : c'est que WPF permet de "layerer" ou superposer des canevas et également des grids à l'infini...mais dans le DataTemplate ...
    Si en plus le Panel Host est un Grid qui va les etirer (stretcher) ,l'illusion est parfaite car il faut les prévoir sans Background pour la simple visibilité et le HitTest....


    le code behind.cs des items data est le meme (déjà donne array(6,4):



    code behind.cs du simplistic Customgrid:


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
     
     
    namespace WpfApplication5
    {
        public class CustomGrid:Grid
        {
            public CustomGrid()
            {
     
            }
     
     
            public int MaxRow
            {
                get { return (int)GetValue(MaxRowProperty); }
                set { SetValue(MaxRowProperty, value); }
            }
     
            // Using a DependencyProperty as the backing store for MxRow.  This enables animation, styling, binding, etc...
            public static readonly DependencyProperty MaxRowProperty =
                DependencyProperty.Register("MaxRow", typeof(int),
                typeof(CustomGrid), new FrameworkPropertyMetadata(1, FrameworkPropertyMetadataOptions.AffectsRender, OnMaxRowChanged));
     
            private static void OnMaxRowChanged(DependencyObject d, DependencyPropertyChangedEventArgs args)
            {
                CustomGrid grd = d as CustomGrid;
                int n = (int)args.NewValue;
                grd.RowDefinitions.Clear();
     
                for (int i = 0; i < n; i++)
                {
                   RowDefinition row = new RowDefinition ();
                    grd.RowDefinitions.Add(row);
                }
            }
     
     
     
            public int MaxColumn     
            {
                get { return (int)GetValue(MaxColumnProperty); }
                set { SetValue(MaxColumnProperty, value); }
            }
     
            // Using a DependencyProperty as the backing store for MaxColum.  This enables animation, styling, binding, etc...
            public static readonly DependencyProperty MaxColumnProperty =
                DependencyProperty.Register("MaxColumn", typeof(int),
                 typeof(CustomGrid), 
                 new FrameworkPropertyMetadata(1,
                     FrameworkPropertyMetadataOptions.AffectsRender, OnMaxColumnChanged));
     
            private static void OnMaxColumnChanged(DependencyObject d, DependencyPropertyChangedEventArgs args)
            {
                CustomGrid grd = d as CustomGrid;
                int n = (int)args.NewValue;
                grd.ColumnDefinitions.Clear();
     
                for (int i = 0; i < n; i++)
                {
                    ColumnDefinition col = new ColumnDefinition();
                    grd.ColumnDefinitions.Add(col);
                }
            }
     
        }
    }
    code xaml du form utilisateur ;
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
     
    <Window x:Class="WpfApplication5.WinCustomGrid"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:local="clr-namespace:WpfApplication5" 
            Title="CustomGrid" Height="350" Width="525">
        <Window.Resources>
            <local:Items x:Key="data"></local:Items>
            <DataTemplate x:Key="dt"
                          DataType="{x:Type local:Item}">
                <!--a dessein j'ai mis les props MaxColumn et MaxRow inferieures aux -->
                <!--dimensions de l'array de la liste source -->
                <!--ne pas specfifier de background sinon  IsHitTestVisible passe à false-->
                <local:CustomGrid  
                        IsHitTestVisible="True"
                        MaxRow="2" MaxColumn="3" 
                       >
                        <Button 
                           Background="PaleGoldenrod"
                            Margin="5" Content="{Binding Nom}"
                            Grid.Column="{Binding X}"
                            Grid.Row="{Binding Y}"
                            Click="Button_Click"    />
                </local:CustomGrid>
            </DataTemplate>
        </Window.Resources>
        <Grid 
            x:Name="mainGrid"
            DataContext="{Binding Source={StaticResource data}}">
            <ItemsControl
                ItemsSource="{Binding }"
                ItemTemplate="{StaticResource dt}">
                <ItemsControl.ItemsPanel>
                    <!--le panel host doit etre Transparent-->
                    <ItemsPanelTemplate>
                        <Grid Background="Transparent"    ></Grid> 
                    </ItemsPanelTemplate>
                </ItemsControl.ItemsPanel>
            </ItemsControl>
     
        </Grid>
    </Window>
    La particularité de cet etrange Grid comme Panel Host c'est de stretcher ses cousins grids custom superposés dans le DataTemplate qui ,eux, se charge de la disposition sans passer par le ItemContainerStyle....
    Seule l'exigence de spécifier le nombre de colonnes et ligne subsiste ,ce que tu as fait ....
    Autre étrange particularité des cousins grids customs superposés :si une des coordonnées (X ou Y ) des data items spécifié dans le binding du ItemsControl ne se trouve pas dans la plage requise (MaxRow ou MaxColum) ,l'item data est simplement ignore et n'est pas affiché (mais subsiste dans la liste source Items et la prop ItemsSource )....


    Autre facon d'aborder ce problème :utiliser simplement un grid ordinaire dans le DataTemplate pour le "layering" dont il faut spécifier ,bien sur, en xaml les nombres de Rows et Columns, le Panel Host restant un Grid.....

    en espérant que le code réponde au souci...

  10. #10
    Expert éminent sénior Avatar de Pol63
    Homme Profil pro
    .NET / SQL SERVER
    Inscrit en
    Avril 2007
    Messages
    14 154
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : .NET / SQL SERVER

    Informations forums :
    Inscription : Avril 2007
    Messages : 14 154
    Points : 25 072
    Points
    25 072
    Par défaut
    J'ai fini par trouver une solution qui me convient sachant que je ne veux pas trop de code behind, encore moins spécifique, et pareil en xaml :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
     public class MyItemsControl : ItemsControl
        {
            protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
            {
                var viewModel = item as IPlacableOnGrid;
     
     
                element.SetValue(Grid.ColumnProperty, viewModel.Column);
                element.SetValue(Grid.RowProperty, viewModel.Row);
                element.SetValue(Grid.ColumnSpanProperty, viewModel.ColumnSpan);          
                element.SetValue(Grid.RowSpanProperty, viewModel.RowSpan);
     
                base.PrepareContainerForItemOverride(element, item);
            }
     
        }
    (faire l'interface qui va avec)

    il me reste à faire un grid perso dans lequel on défini nbcol et nbrow
    Cours complets, tutos et autres FAQ ici : C# - VB.NET

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [UWP] binder Grid.Row et Grid.Column
    Par Pol63 dans le forum Windows Workflow Foundation
    Réponses: 1
    Dernier message: 26/08/2019, 15h04
  2. Row Editor Grid Example
    Par TsunamiDream dans le forum Ext JS / Sencha
    Réponses: 4
    Dernier message: 20/07/2010, 15h51
  3. Alternative à Grid.Row et Grid.Column ?
    Par zax-tfh dans le forum Silverlight
    Réponses: 5
    Dernier message: 07/05/2010, 02h18
  4. Question bête : 4 zones précises (Grid.row ?)
    Par vincentDec dans le forum Silverlight
    Réponses: 3
    Dernier message: 25/04/2010, 14h05
  5. BackGround + grid.row/column x variable
    Par cKmel dans le forum Windows Presentation Foundation
    Réponses: 10
    Dernier message: 15/11/2009, 18h56

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo