Свой контейнер компоновки
От: Аноним  
Дата: 07.07.10 10:00
Оценка:
Необходимо создать контейнер компоновки (SizeableStackPanel), который будет работать как стандартный StackPanel но кроме всего прочего будет автоматически добавлять GridSplitter между элементами контейнера. Соответственно элементам внутри контейнера добавляется прикреплённое свойство типа GridLength.
Представляю это как Custom Control производный от ItemsControl, внутри которого заключён Grid, в нечётных строках (или столбцах, в зависимости от Orientation) располагаются элементы контейнера, а в чётных — GridSplitter'ы. Количество строк (столбцов) рассчитывается автоматически в зависимости от количества элементов контейнера.

В XAML должно выглядеть примерно так:
<SizeableStackPanel Orientation="Vertical">
  <Control SizeableStackPanel.Size="Auto">Control 1</Control>
  <Control SizeableStackPanel.Size="1*">Control 2</Control>
  <Control SizeableStackPanel.Size="2*">Control 3</Control>
</SizeableStackPanel>


или так:
<SizeableStackPanel Orientation="Vertical" ItemsSource="{Binding Path=элементы}" Sizes="{Binding Path=размеры}" />


Прошу помочь с реализацией.
А может есть уже где нибудь такой контрол?
Re: Свой контейнер компоновки
От: notacat  
Дата: 07.07.10 23:57
Оценка:
это больше похоже не на StackPanel, а на Grid. Смотрите рефлектором код грида и, например, ColumnDefinitions, как они там размеры со звездочкой обрабатывают. А GridSplitter должен менять размеры? Тогда тем более — грид нужен, возможно даже просто от грида унаследоваться (если, конечно, речь про WPF/Silverlight). Хотя в Сильверлайте будут сложности с наследованием, там много методов, которые нужно бы по уму переопределить, а они зачем-то сделаны sealed.
Re[2]: Свой контейнер компоновки
От: Аноним  
Дата: 08.07.10 04:49
Оценка:
Здравствуйте, notacat, Вы писали:

N>это больше похоже не на StackPanel, а на Grid

Нет. По поведению должно быть похоже именно на StackPanel: Добавленные элементы стыкуются по принципу стека один за другим, а не вставляются в таблицу. А то, что реализацию я представляю именно на основе Grid я тоже написал.

N>возможно даже просто от грида унаследоваться

Унаследовавшись от грида придётся перекрывать доступ к многим ненужным свойствам и методам, например закрыть абсолютно ненужные RowDefinition и ColumnDefinition.

Что-то уже начало получаться. Наверняка есть куча косяков, но по крайней мере в основном работает.
Сделал так:
<Style TargetType="{x:Type l:SizeableStackPanel}">
  <Setter Property="Template">
    <Setter.Value>
      <ControlTemplate TargetType="{x:Type l:SizeableStackPanel}">
        <Border Background="{TemplateBinding Background}"
                BorderBrush="{TemplateBinding BorderBrush}"
                BorderThickness="{TemplateBinding BorderThickness}">
          <Grid x:Name="grid" />
        </Border>
      </ControlTemplate>
    </Setter.Value>
  </Setter>
</Style>


public class SizeableStackPanel : ItemsControl {
  // Определение прикреплённого SizeProperty
  // Определение OrientationProperty
  // Определение SplitterWidthProperty
  // Определение SplitterBrushProperty
    
  public override void OnApplyTemplate() {
    base.OnApplyTemplate();
    OnItemsChanged(null);
  }
  protected override void OnItemsChanged(NotifyCollectionChangedEventArgs e) {
    base.OnItemsChanged(e);
    switch(Orientation) {
      case Orientation.Vertical: {
        RowsUpdate();
        break;
      }
      case Orientation.Horizontal: {
        ColumnsUpdate();
        break;
      }
    }
  }
  private void RowsUpdate() {
    if(this.Template == null) return;
    Grid grid = (Grid)this.Template.FindName("grid", this);
    if(grid == null) return;
    grid.Children.Clear();
    grid.RowDefinitions.Clear();
    int i = 0;
    foreach(UIElement element in Items) {
      if(i > 0) {
        RowDefinition d2 = new RowDefinition();
        d2.Height = GridLength.Auto;
        grid.RowDefinitions.Add(d2);
        GridSplitter splitter = new GridSplitter();
        Binding b1 = new Binding("SplitterWidth");
        b1.Source = this;
        splitter.SetBinding(GridSplitter.HeightProperty, b1);
        Binding b2 = new Binding("SplitterBrush");
        b2.Source = this;
        splitter.SetBinding(GridSplitter.BackgroundProperty, b2);
        splitter.VerticalAlignment = VerticalAlignment.Center;
        splitter.HorizontalAlignment = HorizontalAlignment.Stretch;
        grid.Children.Add(splitter);
        Grid.SetRow(splitter, i++);
      }
      RowDefinition rd = new RowDefinition();
      rd.Height = GetSizeProperty(element);
      grid.RowDefinitions.Add(rd);
      this.RemoveLogicalChild(element);
      grid.Children.Add(element);
      Grid.SetRow(element, i++);
    }
  }
  // Определение ColumnsUpdate()
}


Возможно я что-то использую не так, как следует. Мне не нравятся следующие моменты:
1. this.RemoveLogicalChild(element); А правильно ли так удалять элемент?
2. Grid grid = (Grid)this.Template.FindName("grid", this); Может Grid следует объявить в коде?
Re: Свой контейнер компоновки
От: Codechanger Россия  
Дата: 08.07.10 05:43
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Необходимо создать контейнер компоновки (SizeableStackPanel), который будет работать как стандартный StackPanel но кроме всего прочего будет автоматически добавлять GridSplitter между элементами контейнера. Соответственно элементам внутри контейнера добавляется прикреплённое свойство типа GridLength.

А>Представляю это как Custom Control производный от ItemsControl, внутри которого заключён Grid, в нечётных строках (или столбцах, в зависимости от Orientation) располагаются элементы контейнера, а в чётных — GridSplitter'ы. Количество строк (столбцов) рассчитывается автоматически в зависимости от количества элементов контейнера.

А>В XAML должно выглядеть примерно так:

А>
А><SizeableStackPanel Orientation="Vertical">
А>  <Control SizeableStackPanel.Size="Auto">Control 1</Control>
А>  <Control SizeableStackPanel.Size="1*">Control 2</Control>
А>  <Control SizeableStackPanel.Size="2*">Control 3</Control>
А></SizeableStackPanel>
А>


А>или так:

А>
А><SizeableStackPanel Orientation="Vertical" ItemsSource="{Binding Path=элементы}" Sizes="{Binding Path=размеры}" />
А>


А>Прошу помочь с реализацией.

А>А может есть уже где нибудь такой контрол?

1.Пишем юзерконтрол,состоящий из грида.
2. Добавляем ObservableCollection для элементов.
3. Подписываемся на изменение коллекции элементов и изменение свойства, содержащего коллекцию.
4. В обработчике событий вышеуказанных вызываем метод, осуществляющий работу с гридом, т.е.:
— расставление сплиттеров, задание числа строк(или столбцов, в зависимости от ориентации).
5. Profit.

Это один из вариантов, который не предполагает наследования. Реализуется часов за несколько на живую нитку.
Re[2]: Свой контейнер компоновки
От: Аноним  
Дата: 08.07.10 06:31
Оценка:
Здравствуйте, Codechanger, Вы писали:

C>1.Пишем юзерконтрол,состоящий из грида.

C>2. Добавляем ObservableCollection для элементов.
C>3. Подписываемся на изменение коллекции элементов и изменение свойства, содержащего коллекцию.
C>4. В обработчике событий вышеуказанных вызываем метод, осуществляющий работу с гридом, т.е.:
C> — расставление сплиттеров, задание числа строк(или столбцов, в зависимости от ориентации).
C>5. Profit.

C>Это один из вариантов, который не предполагает наследования. Реализуется часов за несколько на живую нитку.


UserControl не подходит, т.к. он производный от ContentControl и не позволит в XAML конструкцию вида:
<SizeableStackPanel Orientation="Vertical">
  <Control SizeableStackPanel.Size="Auto">Control 1</Control>
  <Control SizeableStackPanel.Size="1*">Control 2</Control>
  <Control SizeableStackPanel.Size="2*">Control 3</Control>
</SizeableStackPanel>
Re[3]: Свой контейнер компоновки
От: notacat  
Дата: 08.07.10 08:51
Оценка: +1
Ну нет, если у вас ItemsControl, то сделайте нормально. Вы с ним работаете, как с панелью, а надо — как с ItemsControl'ом.
Т.е. пусть у вас Items будут Items, не надо никаких RemoveLogicalChild. Grid — не дочерний элемент, а ItemsPanel (наверное нужно запретить менять это свойство). Возможно имеет смысл сделать так, чтобы IsItemItsOwnContainerOverride возвращал true.

А>2. Grid grid = (Grid)this.Template.FindName("grid", this); Может Grid следует объявить в коде?

ItemsPanelTemplate MS обычно грузит из кода.
Re[3]: Свой контейнер компоновки
От: notacat  
Дата: 08.07.10 08:53
Оценка: 2 (1)
А>UserControl не подходит, т.к. он производный от ContentControl и не позволит в XAML конструкцию вида:
А>
А><SizeableStackPanel Orientation="Vertical">
А>  <Control SizeableStackPanel.Size="Auto">Control 1</Control>
А>  <Control SizeableStackPanel.Size="1*">Control 2</Control>
А>  <Control SizeableStackPanel.Size="2*">Control 3</Control>
А></SizeableStackPanel>
А>

Если у него будет свойство для Items, то будет просто еще один уровень вложенности в xaml'е:
<SizeableStackPanel Orientation="Vertical">
  <SizeableStackPanel.Items>
    <Control SizeableStackPanel.Size="Auto">Control 1</Control>
    <Control SizeableStackPanel.Size="1*">Control 2</Control>
    <Control SizeableStackPanel.Size="2*">Control 3</Control>
  </SizeableStackPanel.Items>
</SizeableStackPanel>
Re: Свой контейнер компоновки
От: vit_as Россия  
Дата: 08.07.10 09:09
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Необходимо создать контейнер компоновки (SizeableStackPanel), который будет работать как стандартный StackPanel но кроме всего прочего будет автоматически добавлять GridSplitter между элементами контейнера. Соответственно элементам внутри контейнера добавляется прикреплённое свойство типа GridLength.

А>Представляю это как Custom Control производный от ItemsControl, внутри которого заключён Grid, в нечётных строках (или столбцах, в зависимости от Orientation) располагаются элементы контейнера, а в чётных — GridSplitter'ы. Количество строк (столбцов) рассчитывается автоматически в зависимости от количества элементов контейнера.

А>В XAML должно выглядеть примерно так:

А>
А><SizeableStackPanel Orientation="Vertical">
А>  <Control SizeableStackPanel.Size="Auto">Control 1</Control>
А>  <Control SizeableStackPanel.Size="1*">Control 2</Control>
А>  <Control SizeableStackPanel.Size="2*">Control 3</Control>
А></SizeableStackPanel>
А>


А>или так:

А>
А><SizeableStackPanel Orientation="Vertical" ItemsSource="{Binding Path=элементы}" Sizes="{Binding Path=размеры}" />
А>


А>Прошу помочь с реализацией.

А>А может есть уже где нибудь такой контрол?

1. Наследуетесь от Panel
2. В OnVisualChildrenChanged отлавливаете событие добавления контрола и сами добавляете GridSplitter или свой контрол для ресайзинга
3. Переопределяете метод MeasureOverride
4. Переопределяете метод ArrangeOverride
Re: Свой контейнер компоновки
От: Vladek Россия Github
Дата: 08.07.10 09:19
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Необходимо создать контейнер компоновки (SizeableStackPanel), который будет работать как стандартный StackPanel но кроме всего прочего будет автоматически добавлять GridSplitter между элементами контейнера. Соответственно элементам внутри контейнера добавляется прикреплённое свойство типа GridLength.

А>Представляю это как Custom Control производный от ItemsControl, внутри которого заключён Grid, в нечётных строках (или столбцах, в зависимости от Orientation) располагаются элементы контейнера, а в чётных — GridSplitter'ы. Количество строк (столбцов) рассчитывается автоматически в зависимости от количества элементов контейнера.

Я бы просто заменил панель ItemsControl'а на AutoGrid (легко гуглится), а в шаблоне контейнера элементов добавлял снизу GridSplitter — и всё.

А>Прошу помочь с реализацией.

А>А может есть уже где нибудь такой контрол?

Это очень похоже на Accordion. В любом случаем, делать свой контрол надо по его образу и подобию, а не городить монстра из панелей.
Re[2]: Свой контейнер компоновки
От: Vladek Россия Github
Дата: 08.07.10 09:23
Оценка:
Здравствуйте, Vladek, Вы писали:

V>Я бы просто заменил панель ItemsControl'а на AutoGrid (легко гуглится), а в шаблоне контейнера элементов добавлял снизу GridSplitter — и всё.


Надо бы указать, на какие свойства обратить внимание: ItemsControl.ItemsPanel и ItemsControl.ItemContainerStyle.
Re[4]: Свой контейнер компоновки
От: dx.dash  
Дата: 08.07.10 09:47
Оценка:
Здравствуйте, notacat, Вы писали:

N>Если у него будет свойство для Items, то будет просто еще один уровень вложенности в xaml'е:

N>
N><SizeableStackPanel Orientation="Vertical">
N>  <SizeableStackPanel.Items>
N>    <Control SizeableStackPanel.Size="Auto">Control 1</Control>
N>    <Control SizeableStackPanel.Size="1*">Control 2</Control>
N>    <Control SizeableStackPanel.Size="2*">Control 3</Control>
N>  </SizeableStackPanel.Items>
N></SizeableStackPanel>
N>


Спасибо, это подойдёт. Так, наверное и сделаю.
Re[2]: Свой контейнер компоновки
От: dx.dash  
Дата: 09.07.10 05:27
Оценка:
Здравствуйте, Codechanger, Вы писали:

C>1.Пишем юзерконтрол,состоящий из грида.

C>2. Добавляем ObservableCollection для элементов.
C>3. Подписываемся на изменение коллекции элементов и изменение свойства, содержащего коллекцию.
C>4. В обработчике событий вышеуказанных вызываем метод, осуществляющий работу с гридом, т.е.:
C> — расставление сплиттеров, задание числа строк(или столбцов, в зависимости от ориентации).
C>5. Profit.

Сделал, всё работает, но только если использовать в одном экземпляре. Как только добавляю второй:
<SizeableStackPanel>
  <SizeableStackPanel.Items>
    <Button>Btn 1</Button>
  </SizeableStackPanel.Items>
</SizeableStackPanel>
<SizeableStackPanel>
  <SizeableStackPanel.Items>
    <Button>Btn 2</Button>
  </SizeableStackPanel.Items>
</SizeableStackPanel>

сразу начинает ругаться "Указанный элемент уже является логическим дочерним для другого элемента. Сначала отсоедините его." при вызове grid.Children.Add(element)
Такое ощущение, что вторая кнопка каким-то образом добавляется в логическое дерево первой панели, и при попытки добавить её во вторую панель выбрасывает исключение.
Re[3]: Свой контейнер компоновки
От: Codechanger Россия  
Дата: 09.07.10 08:04
Оценка:
Здравствуйте, dx.dash, Вы писали:

DD>Здравствуйте, Codechanger, Вы писали:


C>>1.Пишем юзерконтрол,состоящий из грида.

C>>2. Добавляем ObservableCollection для элементов.
C>>3. Подписываемся на изменение коллекции элементов и изменение свойства, содержащего коллекцию.
C>>4. В обработчике событий вышеуказанных вызываем метод, осуществляющий работу с гридом, т.е.:
C>> — расставление сплиттеров, задание числа строк(или столбцов, в зависимости от ориентации).
C>>5. Profit.

DD>Сделал, всё работает, но только если использовать в одном экземпляре. Как только добавляю второй:

DD>
DD><SizeableStackPanel>
DD>  <SizeableStackPanel.Items>
DD>    <Button>Btn 1</Button>
DD>  </SizeableStackPanel.Items>
DD></SizeableStackPanel>
DD><SizeableStackPanel>
DD>  <SizeableStackPanel.Items>
DD>    <Button>Btn 2</Button>
DD>  </SizeableStackPanel.Items>
DD></SizeableStackPanel>
DD>

DD>сразу начинает ругаться "Указанный элемент уже является логическим дочерним для другого элемента. Сначала отсоедините его." при вызове grid.Children.Add(element)
DD>Такое ощущение, что вторая кнопка каким-то образом добавляется в логическое дерево первой панели, и при попытки добавить её во вторую панель выбрасывает исключение.

Код в студию.
Re[4]: Свой контейнер компоновки
От: Аноним  
Дата: 09.07.10 08:38
Оценка:
Здравствуйте, Codechanger, Вы писали:

C>Код в студию.



    public partial class SizeableStackPanel : UserControl {
        public static readonly DependencyProperty ItemsProperty;
        public ObservableCollection<UIElement> Items {
            get { return (ObservableCollection<UIElement>)GetValue(ItemsProperty); }
            set { SetValue(ItemsProperty, value); }
        }

        public static readonly DependencyProperty SizeProperty;
        public static void SetSize(UIElement element, GridLength value) {
            element.SetValue(SizeProperty, value);
        }
        public static GridLength GetSize(UIElement element) {
            return (GridLength)element.GetValue(SizeProperty);
        }

        public static readonly DependencyProperty SplitterWidthProperty;
        public Double SplitterWidth {
            get { return (Double)GetValue(SplitterWidthProperty); }
            set { SetValue(SplitterWidthProperty, value); }
        }

        public static readonly DependencyProperty SplitterBrushProperty;
        public Brush SplitterBrush {
            get { return (Brush)GetValue(SplitterBrushProperty); }
            set { SetValue(SplitterBrushProperty, value); }
        }

        public static readonly DependencyProperty OrientationProperty;
        public Orientation Orientation {
            get { return (Orientation)GetValue(OrientationProperty); }
            set { SetValue(OrientationProperty, value); }
        }

        static SizeableStackPanel() {
            ItemsProperty = DependencyProperty.Register("Items", typeof(ObservableCollection<UIElement>), typeof(SizeableStackPanel), new PropertyMetadata(new ObservableCollection<UIElement>(), new PropertyChangedCallback(OnItemsPropertyChanged)));
            SizeProperty = DependencyProperty.RegisterAttached("Size", typeof(GridLength), typeof(SizeableStackPanel));
            SplitterWidthProperty = DependencyProperty.Register("SplitterWidth", typeof(Double), typeof(SizeableStackPanel), new PropertyMetadata(Double.NaN));
            SplitterBrushProperty = DependencyProperty.Register("SplitterBrush", typeof(Brush), typeof(SizeableStackPanel));
            OrientationProperty = DependencyProperty.Register("Orientation", typeof(Orientation), typeof(SizeableStackPanel), new PropertyMetadata(Orientation.Vertical, new PropertyChangedCallback(OnOrientationPropertyChanged)));
        }
        
        public SizeableStackPanel() {
            InitializeComponent();
            Items.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(Items_CollectionChanged);
        }

        void Items_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) {
            Update();
        }

        private static void OnOrientationPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
            SizeableStackPanel element = d as SizeableStackPanel;
            if(element != null) {
                element.Update();
            }
        }

        private static void OnItemsPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
            SizeableStackPanel element = d as SizeableStackPanel;
            if(element != null) {
                element.Update();
            }
        }

        private void Update() {
            grid.Children.Clear();
            grid.RowDefinitions.Clear();
            grid.ColumnDefinitions.Clear();
            int i = 0;
            if(Orientation == Orientation.Vertical) {
                foreach(UIElement element in Items) {
                    if(i > 0) {
                        RowDefinition d2 = new RowDefinition();
                        d2.Height = GridLength.Auto;
                        grid.RowDefinitions.Add(d2);
                        GridSplitter splitter = new GridSplitter();
                        Binding b1 = new Binding("SplitterWidth");
                        b1.Source = this;
                        splitter.SetBinding(GridSplitter.HeightProperty, b1);
                        Binding b2 = new Binding("SplitterBrush");
                        b2.Source = this;
                        splitter.SetBinding(GridSplitter.BackgroundProperty, b2);
                        splitter.VerticalAlignment = VerticalAlignment.Center;
                        splitter.HorizontalAlignment = HorizontalAlignment.Stretch;
                        grid.Children.Add(splitter);
                        Grid.SetRow(splitter, i++);
                    }
                    RowDefinition rd = new RowDefinition();
                    Binding b = new Binding();
                    b.Path = new PropertyPath(SizeableStackPanel.SizeProperty);
                    b.Source = element;
                    b.Mode = BindingMode.TwoWay;
                    BindingOperations.SetBinding(rd, RowDefinition.HeightProperty, b);
                    grid.RowDefinitions.Add(rd);
                    grid.Children.Add(element);
                    Grid.SetRow(element, i++);
                }
            } else {
                foreach(UIElement element in Items) {
                    if(i > 0) {
                        ColumnDefinition d2 = new ColumnDefinition();
                        d2.Width = GridLength.Auto;
                        grid.ColumnDefinitions.Add(d2);
                        GridSplitter splitter = new GridSplitter();
                        Binding b1 = new Binding("SplitterWidth");
                        b1.Source = this;
                        splitter.SetBinding(GridSplitter.WidthProperty, b1);
                        Binding b2 = new Binding("SplitterBrush");
                        b2.Source = this;
                        splitter.SetBinding(GridSplitter.BackgroundProperty, b2);
                        splitter.VerticalAlignment = VerticalAlignment.Stretch;
                        splitter.HorizontalAlignment = HorizontalAlignment.Center;
                        grid.Children.Add(splitter);
                        Grid.SetColumn(splitter, i++);
                    }
                    ColumnDefinition rd = new ColumnDefinition();
                    Binding b = new Binding();
                    b.Path = new PropertyPath(SizeableStackPanel.SizeProperty);
                    b.Source = element;
                    b.Mode = BindingMode.TwoWay;
                    BindingOperations.SetBinding(rd, ColumnDefinition.WidthProperty, b);
                    grid.ColumnDefinitions.Add(rd);
                    grid.Children.Add(element);
                    Grid.SetColumn(element, i++);
                }
            }
        }
    }
Re[5]: Свой контейнер компоновки
От: notacat  
Дата: 09.07.10 08:47
Оценка:
может просто у вас грид не тот нашелся, а какой-нибудь снаружи?
Как этот грид объявляется и где, про это в коде нет. А лучше бы полный сэмпл, чтобы поиграться
Re[2]: Свой контейнер компоновки
От: MxMsk Португалия  
Дата: 09.07.10 09:16
Оценка:
Здравствуйте, vit_as, Вы писали:

_>1. Наследуетесь от Panel

_>2. В OnVisualChildrenChanged отлавливаете событие добавления контрола и сами добавляете GridSplitter или свой контрол для ресайзинга
Здесь надо помнить, что такой сценарий обламается, если панель будут использовать в качестве ItemsPanel для ItemsControl.
_>3. Переопределяете метод MeasureOverride
_>4. Переопределяете метод ArrangeOverride
Re[6]: Свой контейнер компоновки
От: dx.dash  
Дата: 09.07.10 09:44
Оценка:
Здравствуйте, notacat, Вы писали:

N>может просто у вас грид не тот нашелся, а какой-нибудь снаружи?

N>Как этот грид объявляется и где, про это в коде нет. А лучше бы полный сэмпл, чтобы поиграться

Вот пример. Выложил на депозит, больше ничего в голову не пришло:
сэмпл
Re[7]: Свой контейнер компоновки
От: notacat  
Дата: 09.07.10 10:13
Оценка: 2 (1)
вот так сделайте:
static SizeableStackPanel() {
  ItemsProperty = DependencyProperty.Register("Items", typeof(ObservableCollection<UIElement>), typeof(SizeableStackPanel), new PropertyMetadata(null, new PropertyChangedCallback(OnItemsPropertyChanged)));
  SizeProperty = DependencyProperty.RegisterAttached("Size", typeof(GridLength), typeof(SizeableStackPanel));
  SplitterWidthProperty = DependencyProperty.Register("SplitterWidth", typeof(Double), typeof(SizeableStackPanel), new PropertyMetadata(Double.NaN));
  SplitterBrushProperty = DependencyProperty.Register("SplitterBrush", typeof(Brush), typeof(SizeableStackPanel));
  OrientationProperty = DependencyProperty.Register("Orientation", typeof(Orientation), typeof(SizeableStackPanel), new PropertyMetadata(Orientation.Vertical, new PropertyChangedCallback(OnOrientationPropertyChanged)));
}
        
public SizeableStackPanel() {
       Items = new ObservableCollection<UIElement>();
       InitializeComponent();
       Items.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(Items_CollectionChanged);
}
...
private void Update() {
       if (grid == null)
       {
           return;
       }

почему — сами догадайтесь. Ну и изменение свойства Items надо дорабатывать, именно там должна быть подписка/отписка от CollectionChanged.
Re[8]: Свой контейнер компоновки
От: dx.dash  
Дата: 09.07.10 10:43
Оценка:
Здравствуйте, notacat, Вы писали:

N>вот так сделайте:


Спасибо, выручили.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.