Добавить составную область WPF во время выполнения

Хорошо, вот мой простой сценарий. У меня есть набор строк, которые я привязываю к TabControl в качестве доказательства концепции. По мере добавления строк мне нужна новая вкладка с названием региона в качестве заголовка и ItemsControl в контейнере вкладок. Этот ItemsControl должен определять новый регион.

        <TabControl  x:Name="tabDemo" ItemsSource="{Binding DynamicRegions}" >
        <TabControl.ItemTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding}" />
            </DataTemplate>
        </TabControl.ItemTemplate>
        <TabControl.ContentTemplate>
            <DataTemplate>
                <ItemsControl cal:RegionManager.RegionName="{Binding}" ItemsSource="{x:Null}">

                </ItemsControl>
            </DataTemplate>
        </TabControl.ContentTemplate>
    </TabControl>

Оттуда я добавляю строки в коллекцию. Вкладки отображаются нормально, но когда я пытаюсь позвонить

   private void AddDynamicRegion(object arg)
  {
     var newRegionName = "Region" + (DynamicRegions.Count + 1).ToString();
     DynamicRegions.Add(newRegionName);
  }

  private void AddRandomRegionContent(object arg)
  {
     if (string.IsNullOrEmpty(SelectedRegion) )
        return; 

     Debug.WriteLine("Injected "  + RegionContent + " into " + SelectedRegion);

     var newContent = new TextBlock() { Text = RegionContent };
     _regionManager.RegisterViewWithRegion(SelectedRegion,() => newContent );

     _regionManager.Regions[SelectedRegion].Activate(newContent);
  }

Он либо генерирует исключение, что регион не существует, либо исключение, при котором создание региона завершилось неудачно и мой ItemsControl.ItemsSource уже установлен. Я действительно не ожидал, что это сработает из коробки, но есть ли способ создать динамические области и внедрить в них во время выполнения?

Обновление: вызов RegisterViewWithRegion фактически вводит мой текстовый блок ... но при этом возникает странное поведение между вкладками.

Я изменил его, чтобы я мог выбрать регион и текст, который хочу ввести. Это всегда работает для первой области, которую я создаю, но после этого переключение между вкладками просто показывает то, что я добавил в первую область. Использует ли элемент управления вкладками мою табличку данных на нескольких вкладках? Я включил весь свой код из ViewModel. DynamicRegions - это просто ObservableCollection


person Nick    schedule 22.09.2009    source источник


Ответы (3)


Вам нужно вызвать region.Activate (stuffIJustAddedToTabsControl) хотя бы для одной из вещей, которые вы добавляете в регион. Я получу синхронизацию вкладки и региона. В остальном все выглядит сумасшедшим и действует еще хуже.

person Anderson Imes    schedule 23.09.2009
comment
Я получаю исключение. Этот RegionManager не содержит региона с именем «Region1». Имя параметра: regionName - person Nick; 23.09.2009
comment
Когда я смотрю на свой RegionManager в режиме отладки, я не вижу ни одной из ожидаемых динамических областей. Насколько я понимаю, RegionManager был одноэлементным, поэтому установка присоединенного свойства имени региона должна создавать новые регионы. - person Nick; 23.09.2009
comment
О ... Я вижу, что вы делаете. Скорее всего, это не сработает так, как вы думаете ... Однако я могу придумать демо, которое сделает то, что вы хотите. Дай мне немного времени. - person Anderson Imes; 23.09.2009
comment
Я продолжу возиться, как я уже сказал, я действительно не ожидал, что это сработает, но я решил, что стоит попробовать. - person Nick; 23.09.2009

Подойдет ли вам создание TabControl в качестве региона? Таким образом, вы можете просто добавлять регионы к этому виду. Если этим представлениям нужна область, просто создайте вложенную / вложенную область и также добавьте в нее представление. Мне действительно никогда не нужно было динамически создавать регионы ...

     <TabControl cal:RegionManager.RegionName="TabRegion" x:Name="tabDemo" ItemsSource="{Binding Something}" >
        <TabControl.ItemTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding}" />
            </DataTemplate>
        </TabControl.ItemTemplate>
     </TabControl>

StockChartsRI в Prism показывает, как вы можете привязать заголовок вкладки прямо из вашей модели представления. Они используют подкласс TabPanel (AnimatedTabPanel), но настройка такая же.

person Jeremiah Morrill    schedule 24.09.2009
comment
В нашем случае у нас есть дискретные представления, которые нужно агрегировать на лету. Мы будем получать структуру агрегатов из базы данных. Таким образом, элемент управления вкладкой будет привязан к списку вкладок, а затем для каждой вкладки у нас будут метаданные, какие представления нужно вставить в этот сценарий. Я понимаю, откуда вы, но я думаю, что есть некоторые смягчающие обстоятельства, которые действительно делают динамические регионы более привлекательным вариантом. - person Nick; 24.09.2009
comment
Я думаю, вы слишком усложняете свою проблему. У меня такая же установка, как вы описали в моем заявлении SL. Настройки считываются через WCF, чтобы найти установленные плагины. Каждый установленный плагин получает свою собственную вкладку в элементе управления вкладками. Для каждого установленного плагина я создаю ViewModel и добавляю его View в область, принадлежащую TabControl. Элемент управления вкладкой привязывает свой заголовок к только что добавленной виртуальной машине. Каждое добавленное мной представление имеет собственные вложенные области. Единственная причина для создания региона во время выполнения должна быть для вложенных / вложенных регионов. - person Jeremiah Morrill; 26.09.2009

Хорошо, у меня есть кое-что, что работает, но я хотел бы посмотреть, что придумает Андерсон Аймс.

По сути, я устанавливаю весь регион в коде, когда мои tabItems генерируются с использованием привязки данных.

  private void AddDynamicRegion(object arg)
  {
     var newRegionName = "Region" + (DynamicRegions.Count + 1).ToString();
     DynamicRegions.Add(newRegionName);

     var tabItem = View.tabDemo.ItemContainerGenerator.ContainerFromIndex(DynamicRegions.Count - 1) as TabItem;
     var newRegionContainer = new ItemsControl();
     RegionManager.SetRegionName(newRegionContainer,newRegionName);
     RegionManager.SetRegionManager(newRegionContainer, _regionManager);
     tabItem.Content = newRegionContainer;


  }

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

  private void AddRandomRegionContent(object arg)
  {

     if (string.IsNullOrEmpty(SelectedRegion) )
        return; 

     Debug.WriteLine("Injected "  + RegionContent + " into " + SelectedRegion);

     var newContent = new TextBlock() { Text = RegionContent };
     var region = _regionManager.Regions[SelectedRegion];
     if (region == null)
     {
        Debug.WriteLine("Couldn't find region");
        return;
     }

     region.Add(newContent);
     region.Activate(newContent);

  }
person Nick    schedule 23.09.2009
comment
да ... вам обязательно нужно активировать его ... иначе он не будет правильно отображаться при любом элементе управления селектором. Это было очень близко к тому, что я собирался предложить. - person Anderson Imes; 23.09.2009