Кнопка «Динамически создать со стилем»: указанный элемент уже является логическим дочерним элементом другого элемента. Сначала отключи - PullRequest
0 голосов
/ 15 марта 2012

Мое приложение может перемещаться по 3 различным страницам, которые все отображаются в 1 окне (по одной за раз).Все страницы, которые отображаются в одном и том же окне, являются пользовательскими элементами управления.

Всякий раз, когда я нажимаю кнопку «A», создается новая кнопка, которая добавляется в панель стека .Таким образом, в основном, если я нажимаю 5 раз, я получаю 5 кнопок, удобно расположенных рядом друг с другом.Приведенный ниже код перемещает экран со страницы B обратно на A (при условии, что я уже на странице B), здесь я вызываю метод, который выполняет итерацию по списку сохраненных кнопок.

ДляЕсли коротко, я хочу сохранить элементы, созданные в списке, или что-то еще, поэтому, когда это окно загружается снова, я могу просто загрузить значения (кнопки) обратно.

Страница B:

private void btnNoProduction_Click(object sender, RoutedEventArgs e)
{
    MainWindow main = new MainWindow();

    Switcher.Switch(main);       
    main.reloadDynamicRegistrationContent();
}

Страница A (главное окно), где я перебираю список с сохраненными кнопками.

public void reloadDynamicRegistrationContent()
{
    for (int i = 0; i < GlobalVar._listReg.Count; i++)
    {
        spHorizontal.Children.Add(GlobalVar._listReg[i]);  //ERROR Specified Element is already the logical.....
    }
}

Мне нужен какой-то способ сохранить эти кнопки (список, но я продолжаю получатьошибка Указанный элемент уже является логическим дочерним элементом другого элемента. Сначала отключите его. wpf . Не удается получить доступ к списку из статического класса.

Код для создания кнопкидинамически:

private void btnTestRegistration_Click(object sender, RoutedEventArgs e)
{
    Button newBtn = new Button();
    newBtn.Name = "btnRegistration" + registrationCount.ToString();
    newBtn.Width = 151;
    newBtn.Height = 73;
    newBtn.Click += new RoutedEventHandler(this.newBtn_Click);

    Thickness margin = newBtn.Margin;
    margin.Left = 10;
    margin.Right = 5;
    newBtn.Margin = margin;

    Style style = this.FindResource("ButtonStyleRegistration") as Style;
    newBtn.Style = style;

    //force build template
    newBtn.ApplyTemplate();

    var tb = VisualTreeNavigator.FindVisualChild<TextBlock>(newBtn, "tbRegistration1");
    tb.Text = "text cause 1 " + registrationCount.ToString();

    var tb2 = VisualTreeNavigator.FindVisualChild<TextBlock>(newBtn, "tbRegistration2");
    tb2.Text = "text cause 2 " + registrationCount.ToString();

    spHorizontal.Children.Add(newBtn);
    GlobalVar.AddButtonToList(newBtn); 
    registrationCount++;
}

Пока все добавлено правильно, но я не могу сохранить набор кнопок, которые были созданы всякий раз, когда я хочу вернуться к этому экрану позже.

GlobalVar - этостатический клзадница, где у меня есть список.Здесь я пытаюсь сохранить содержимое всех кнопок, которые создаются в списке.

 public class GlobalVar
{
    public static List<Button> _listReg = new List<Button>();

    public static void AddButtonToList(Button b)
    {
        _listReg.Add(b);
    }
}

1 Ответ

1 голос
/ 15 марта 2012

В WPF каждый элемент пользовательского интерфейса может участвовать только один раз в любом логическом дереве.Вы не можете иметь элемент

Похоже, что MainWindow не было удалено.Даже если вы утилизируете его (т.е. MainWindow выходит из области видимости, и вы закрываете его) - что я не уверен, что вы делаете из своего кода - он не обязательно удаляется, так как сборщик мусора не обязательно сразу удаляет элементы,Также существует вероятность того, что кнопки сохраняют ссылку на свое родительское окно (spHorizontally, а в конечном итоге и вплоть до MainWindow), и поскольку GlobalVar остается в живых - MainWindow вообще никогда не удаляется, и у вас действительно есть утечка.

Если вы вообще не закрываете главное окно и просто пытаетесь одновременно запустить несколько копий MainWindow, то то, что вы пытаетесь сделать, невозможно.Вам нужно будет как-то сериализовать список кнопок (в основном текст, который вы поместили в текстовые поля), а затем создать новые кнопки с тем же текстом.

Если вы закрываете MainWindow, то перед закрытиемВ окне обязательно удалите список кнопок из spHor Horizontal, используя spHorizont.Children.Remove

Скажем так, ваша программа имеет множество возможностей для улучшений.В частности - почему бы просто не скрыть главное окно (this.IsVisible = false), а затем снова показать его при необходимости?Или, почему бы вам не хранить spHor Horizontal в вашем синглтоне GlobalVar (после удаления его из дерева).

Кроме того, вам будет гораздо лучше, если все свойства будут установлены в методе btnTestRegistration_Click, который является частью стиля, которыйВы применяете к кнопке.Я не фанат анти-кода, но это место, где вы должны использовать XAML.

Черт, если бы это был мой код, я бы просто собрал ObservableCollection со списком элементов (каждый элементпредставляет собой кнопку), затем , привязанный к коллекции, и настройку ItemsPanelTemplate в качестве StackPanel.

<ItemsControl ItemsSource="...">
  <!-- Items Source above should point to the list of logical items representing the buttons. -->
  <ItemsControl.ItemsPanel>
    <ItemsPanelTemplate>
      <!-- this is the spHorizontal that you have -->
      <StackPanel Orientation="Vertical" />
    </ItemsPanelTemplate>
  </ItemsControl.ItemsPanel>
  <ItemsControl.ItemTemplate>
    <DataTemplate>
      <!-- this is a template for the button: -->
      <Button ... />
    </DataTemplate>
  </ItemsControl.ItemTemplate>
</ItemsControl>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...