2016-09-08 2 views
0

У меня есть TabControl в моем приложении. Я хотел бы иметь столько TabItems, сколько записей в моем словаре.TabItem DataTemplate с привязкой

Вот мой словарь:

public Dictionary<string , ObservableCollection<PerformanceCounter>> Counters 
{ 
    get { return _Counters; } 
} 
Dictionary<string, ObservableCollection<PerformanceCounter>> _Counters = new Dictionary<string , ObservableCollection<PerformanceCounter>>(); 

Каждая запись имеет строковый ключ и ObservableCollection объектов PerformanceCounter. Важным является то, что каждый объект PerformanceCounter обладает свойствами: CounterName и InstanceName - мне нужны эти два, чтобы отображать их.

Теперь, к моему XAML:

<TabItem Header="Memory"> 
    <Grid Name="RAMGrid"> 
     <Grid.ColumnDefinitions> 
      <ColumnDefinition Width="*"/> 
      <ColumnDefinition Width="*"/> 
     </Grid.ColumnDefinitions> 
     <Grid.RowDefinitions> 
      <RowDefinition Height="1*"/> 
      <RowDefinition Height="Auto"/> 
     </Grid.RowDefinitions> 
     <ListBox Name="RAMListBox" Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="0" ItemsSource="{Binding Memory, Mode=OneWay}" SelectionMode="Multiple" BorderThickness="1" BorderBrush="#FF8B8B8B" SelectionChanged="RAMListBox_SelectionChanged"> 
      <ListBox.ItemTemplate> 
       <DataTemplate> 
        <TextBlock> 
         <Run Text="{Binding CounterName, Mode=OneWay}" /> 
         <Run Text="{Binding InstanceName, Mode=OneWay}" /> 
        </TextBlock> 
       </DataTemplate> 
      </ListBox.ItemTemplate> 
     </ListBox>           
     <Button Name="RAMSelectAllButton" Margin="0,10,0,0" Grid.Column="0" Grid.Row="1" Click="RAMSelectAllButton_Click" > 
      <TextBlock Text="SELECT ALL"/> 
     </Button> 
     <Button Name="RAMUnSelectAllButton" Margin="0,10,0,0" Grid.Column="1" Grid.Row="1" Click="RAMUnSelectAllButton_Click" > 
      <TextBlock Text="UNSELECT ALL"/> 
     </Button> 
    </Grid> 
</TabItem> 

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

В моем коде я поставил DataContext:

this.DataContext = appData.Counters; 

appData.Counters что словарь я представил в начале.

Вот что я хотел бы достичь: Независимо от того, сколько записей в моем словаре, мой TabControl отобразит TabItem для каждого из них. Каждый TabItem имеет ListBox и 2 кнопки. Мне также нужно иметь доступ к ним (чтобы очистить список и щелкнуть событие для каждой кнопки).

Я действительно не знаю, как это сделать, надеюсь, вы сможете мне помочь.

+0

Является ли количество элементов в вашем словаре изменяться во время выполнения? – Arie

+0

Нет, это не изменится – Loreno

+0

, затем проверьте это: https://stackoverflow.com/questions/2981046/wpf-binding-to-items-within-a-dictionary-by-key – Arie

ответ

1

Привязка TabControl к элементам в Словаре:

<Window.Resources> 

    <DataTemplate x:Key="templateForTheContent" > 
     <StackPanel> 
      <ListBox Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="0" 
        ItemsSource="{Binding Value, Mode=OneWay}" 
        SelectionMode="Multiple" 
         BorderThickness="1" BorderBrush="#FF8B8B8B"> 
       <ListBox.ItemTemplate> 
        <DataTemplate> 
         <TextBlock> 
            <Run Text="{Binding CounterName, Mode=OneWay}" /> 
            <Run Text="{Binding InstanceName, Mode=OneWay}" /> 
         </TextBlock> 
        </DataTemplate> 
       </ListBox.ItemTemplate> 
      </ListBox> 
     </StackPanel> 
    </DataTemplate> 

    <DataTemplate x:Key="templateForTheHeader" > 
     <TextBlock Text="{Binding Key}"/> 
    </DataTemplate> 

</Window.Resources> 
<Grid> 
    <TabControl TabStripPlacement="Left" VerticalAlignment="Stretch" HorizontalContentAlignment="Stretch" 
     ItemsSource="{Binding Counters}" 
     ContentTemplate="{StaticResource templateForTheContent}" 
     ItemTemplate="{StaticResource templateForTheHeader}"> 
    </TabControl> 
</Grid> 

Теперь словарь не наблюдается, так что если будут добавлены элементы/удалены во время выполнения, вы можете рассмотреть возможность использования что-то вроде ObservableDictionary вместо

+0

Есть ли альтернатива использованию ObservableDictionary? Я попытался использовать его, но получаю исключение, которое приводит к коду класса ObservableDictionary. Может быть, есть возможность вручную инициировать уведомление об изменении каждый раз, когда я добавляю что-то в словарь? – Loreno

+0

Конечно, вам просто нужно реализовать интерфейс INotifyCollectionChanged. Это можно сделать наследующим, скажем, списком . Хороший побочный эффект: в итоге у вас будут все прекрасные LINQ-расширения, которых нет у основного ObservableCollection. –

+0

@ Loreno Вы уверены, что вам нужно использовать словарь? Иногда проще просто использовать ObservableCollection или что-то еще, что реализует INotifyCollectionChanged – Arie

0

Создать ViewModel -класс, содержащий:

  1. ваш словарь
  2. два ICommand-реализация про ЦИИ для кнопок

затем

  1. установить ViewModel-класс как DataContext из TabControl
  2. набор СЧЕТЧИКИ как ItemSource из TabControl
  3. повторное использование вашего XAML-кода, определенного в e TabItem и используйте его как Tabcontrol. СодержаниеОбъект
  4. Bind .Команда ваших кнопок к ICommands в вашей ViewModel с помощью RelativeSource

см для образцов:

  1. ContentTemplate: https://wpf.2000things.com/tag/tabcontrol/
  2. ICommand https://stackoverflow.com/a/1468830/4919708
  3. RelativeSource: https://stackoverflow.com/a/84317/4919708
+0

Я не использую MVVM - Я даже не знаю, что это такое, но я вижу такие предложения везде, поэтому в итоге мне придется кое-что прочитать. – Loreno

0

Как я сказал в одном из комментариев выше, я изменил мой словарь к этому:

//list of all counters 
     public ObservableCollection<ObservableCollection<PerformanceCounter>> Counters 
     { 
      get { return _Counters; } 
     } 
     ObservableCollection<ObservableCollection<PerformanceCounter>> _Counters = new ObservableCollection<ObservableCollection<PerformanceCounter>>();  

я использовал @ решения Арье, чтобы написать этот код XAML:

  <DataTemplate x:Key="templateForTheContent" > 
      <Grid> 
       <Grid.ColumnDefinitions> 
        <ColumnDefinition Width="*"/> 
        <ColumnDefinition Width="*"/> 
       </Grid.ColumnDefinitions> 
       <Grid.RowDefinitions> 
        <RowDefinition Height="1*"/> 
        <RowDefinition Height="Auto"/> 
       </Grid.RowDefinitions> 
       <ListBox Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="0" 
         ItemsSource="{Binding}" 
         SelectionMode="Multiple" 
          BorderThickness="1" BorderBrush="#FF8B8B8B"> 
        <ListBox.ItemTemplate> 
         <DataTemplate> 
          <TextBlock> 
             <Run Text="{Binding CounterName, Mode=OneWay}" /> 
             <Run Text="{Binding InstanceName, Mode=OneWay}" /> 
          </TextBlock> 
         </DataTemplate> 
        </ListBox.ItemTemplate> 
       </ListBox> 
       <Button Name="RAMSelectAllButton" Margin="0,10,0,0" Grid.Column="0" Grid.Row="1" > 
        <TextBlock Text="SELECT ALL"/> 
       </Button> 
       <Button Name="RAMUnSelectAllButton" Margin="0,10,0,0" Grid.Column="1" Grid.Row="1" > 
        <TextBlock Text="UNSELECT ALL"/> 
       </Button> 
      </Grid> 
     </DataTemplate> 

      <DataTemplate x:Key="templateForTheHeader" > 
       <TextBlock Text="{Binding CategoryName}"/> 
      </DataTemplate> 

     </Window.Resources> 

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

Теперь у меня есть новая проблема: я не знаю, как получить доступ к каждому listBox из каждой вкладки. Мне нужно уметь читать список выбранных объектов.

Смежные вопросы