Добавете композитен WPF регион по време на изпълнение

Добре, ето моят прост сценарий. Имам колекция от низове, които обвързвам към TabControl като доказателство за концепцията. Докато добавям низове, искам нов раздел с името на региона като заглавка и ItemsControl в контейнера Tab. Този 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