2016-05-24 3 views
0

Я разрабатываю внешнее приложение в C#/WPF, которое отображает информацию: Name, Details. Etc ...Раздел комментариев внутри каждого элемента списка ListBox

Я обрабатываю эту часть с помощью ListBox и простой привязки. Я заселить мою ListBox таким образом:

model.ClassAs.Add(new ClassA { Name = textBox1.Text, Detail = textBox2.Text }); 

Проблема подойдите теперь я должен реализовать Comment Section для пользователей, чтобы добавлять комментарии внутри каждого ListBoxItems отдельно. Очевидно, я не могу заполнить Comment Section, когда я заселяю Name и Details. Поэтому я создаю второй ListBox внутри ItemsTemplate первого, ListBoxSeption, если вы хотите. Я создаю другой класс ClassB и попытаюсь реализовать привязку, как в первый раз.

Очевидно, что это не сработало, потому что я был в DataContext ListBox1. Я пытаюсь настроить ObservableCollection с событием PropertyChanged, но я не могу заставить его работать. Я не очень хорошо понимаю этот процесс, поэтому не вижу, где моя ошибка.

Вот мой XAML:

<ListBox x:Name="listBox" MouseDoubleClick="ListBox_MouseDoubleClick" 
      ScrollViewer.HorizontalScrollBarVisibility="Disabled" HorizontalContentAlignment="Stretch" 
      ItemsSource="{Binding ClassAs, Mode=OneWay}" Grid.Column="1" > 
    <ListBox.ItemTemplate> 
     <DataTemplate> 
      <Grid x:Name="grd"> 
       <Grid.ColumnDefinitions> 
        <ColumnDefinition Width="100"/> 
       </Grid.ColumnDefinitions> 
       <Grid.RowDefinitions> 
        <RowDefinition Height="auto"/> 
       </Grid.RowDefinitions> 
       <TextBlock Name="Name" Text="{Binding Name, Mode=OneWay}" Grid.Column="2" Foreground="DarkGray" FontWeight="Bold" /> 
       <TextBlock Text="{Binding Detail, Mode=OneWay}" Grid.Column="2" Grid.Row="1" TextWrapping="Wrap" /> 
       <Grid x:Name="comSection" Visibility="{Binding RelativeSource={RelativeSource AncestorType={x:Type ListBoxItem}}, Path=IsSelected, Converter={StaticResource booleanVisibleConverter}}" 
         Grid.Column="2" Grid.Row="2"> 
        <Grid.ColumnDefinitions> 
         <ColumnDefinition Width="*"/> 
        </Grid.ColumnDefinitions> 
        <Grid.RowDefinitions> 
         <RowDefinition Height="*"/> 
        </Grid.RowDefinitions> 
        <AdornerDecorator> 
         <TextBox x:Name="textBoxCom" HorizontalAlignment="Stretch" 
        TextWrapping="Wrap" Grid.Column="0" Grid.Row="0"> 
          <controls:WatermarkService.Watermark> 
           <TextBlock>Type Comment Here...</TextBlock> 
          </controls:WatermarkService.Watermark> 
         </TextBox> 
        </AdornerDecorator> 
        <ListBox x:Name="listBoxCom" BorderThickness="0,0,0,0" Grid.Row="1" Grid.Column="0" 
          HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch" VerticalAlignment="Stretch" ScrollViewer.VerticalScrollBarVisibility="Visible" 
          ItemsSource="{Binding ClassBs.Commentary}"> 
         <ListBox.ItemTemplate> 
          <DataTemplate> 
           <Grid> 
            <Grid.RowDefinitions> 
             <RowDefinition Height="20"/> 
             <RowDefinition Height="20"/> 
            </Grid.RowDefinitions> 
            <TextBlock Name="TBCom" Text="{Binding}"></TextBlock> 
           </Grid> 
          </DataTemplate> 
         </ListBox.ItemTemplate> 
        </ListBox> 
       </Grid> 
       <Button x:Name="addComment" HorizontalAlignment="Center" VerticalAlignment="Top" Width="25" Height="25" 
         BorderThickness="0" Click="addComment_Click" Background="Transparent" Grid.Column="1" Grid.Row="2" 
         ToolTip="Comment"> 
        <Button.Content> 
         <Image Source="Assets\plus_orange.png" /> 
        </Button.Content> 
       </Button> 
      </Grid> 
     </DataTemplate> 
    </ListBox.ItemTemplate> 
</ListBox> 

Что я хочу: Пользователь заполнить textBoxCom и Нажмите кнопку addComment, чтобы добавить комментарий в выбранном ListBoxItem.

Мои Классы:

public sealed class ClassA : INotifyPropertyChanged 
{ 
    public string Name { get; set; } 
    public string Detail { get; set; } 

    public ObservableCollection<ClassB> ClassBs { get; set; } 
    public List<ClassB> ModifiedComments { get; set; } 

    public event PropertyChangedEventHandler PropertyChanged; 

    public class ClassB 
    { 
     string Commentary { get; set;} 
    } 
} 

Мои ViewModel:

public sealed class ViewModel 
{ 
    public ObservableCollection<ClassA> ClassAs { get; set; } 
    public ObservableCollection<ClassA.ClassB> ClassBs { get; set; } 

    List<ClassA.ClassB> ModifiedItems { get; set; } 

    public ViewModel() 
    { 
     ClassAs = new ObservableCollection<ClassA>(); 
     CLassBs = new ObservableCollection<ClassA.ClassB>(); 
     ModifiedItems = new List<ClassA.ClassB>(); 
     this.ClassBs.CollectionChanged += this.OnCollectionChanged; 
    } 

    void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) 
    { 
     try 
     { 
      if (e.NewItems != null) 
      { 
       foreach (ClassA.ClassB newItem in e.NewItems) 
       { 
        ModifiedItems.Add(newItem); 

        //Add listener for each item on PropertyChanged event 
        newItem.PropertyChanged += this.OnItemPropertyChanged; 
       } 
      } 

      if (e.OldItems != null) 
      { 
       foreach (ClassA.ClassB oldItem in e.OldItems) 
       { 
        ModifiedItems.Add(oldItem); 

        oldItem.PropertyChanged -= this.OnItemPropertyChanged; 
       } 
      } 
     } 
     catch(Exception ex) 
     { 
      MessageBox.Show("me : " + ex); 
     } 
     } 

    void OnItemPropertyChanged(object sender, PropertyChangedEventArgs e) 
    { 
     ClassA.ClassB item = sender as ClassA.ClassB; 
     if (item != null) 
      ModifiedItems.Add(item); 
    } 
} 

My Нажмите Event (AddComment)

private void addComment_Click(object sender, RoutedEventArgs e) 
{ 
    try 
    { 
     currentSelectedListBoxItem = this.listBox.ItemContainerGenerator.ContainerFromIndex(listBox.SelectedIndex) as ListBoxItem; 
     System.Windows.Controls.TextBox textBoxCom = Helper.FindDescendant<System.Windows.Controls.TextBox>(currentSelectedListBoxItem); 
     ListBox LBCom = Helper.FindDescendant<ListBox>(currentSelectedListBoxItem); 
     if (string.IsNullOrWhiteSpace(textBoxCom.Text)) 
      MessageBox.Show("Please fill the Comment Section"); 
     else 
     { 
      model.ClassBs.Add(new ClassA.ClassB { Commentary = textBoxCom.Text }); 
      textBoxCom.Clear(); 

     } 
    } 
    catch (Exception exp) 
    { 
     MessageBox.Show("exp = " + exp); 
    } 
} 

Извините за очень длинный пост, я надеюсь, что вы можете помочь моим на этом !

+0

Вам не нужно заполнять свойство комментария класса A, но вы все равно сможете его связать. Таким образом, когда пользователь заполнит поле комментария, ваш объект ClassA будет содержать всю необходимую информацию – Sidewinder94

+0

Вы имеете в виду без использования события PropertyChange? – SerpentSolide

+0

Вам не нужно событие «PropertyChanged», если связанный элемент управления является единственным, кто изменит свойство. Это событие используется, чтобы сообщить другим объектам, которые будут зависеть от этого свойства, которое оно изменило, и они могут захотеть снова обновить/вычислить то, что они сделали с ним. – Sidewinder94

ответ

0

Ну, это было проще, чем ожидалось, я просто копался в бесполезном коде! Я избавлюсь от всего кода около ObservableCollection и PropertyChange Событие.

Мой окончательный ClassA кодекс (более не ClassB):

public sealed class ClassA 
{ 


    public string Name { get; set; } 
    public string Detail { get; set; } 
    public List<string> Comments { get; set; } 

    public Issue() 
    { 
     Comments = new List<string>(); 
    } 
} 

И мой последний Нажмите Событие:

var selected = listBox.SelectedItem as ClassA; 
       selected.Comments.Add(textBoxCom.Text); 
       listBox.Items.Refresh(); 
       textBoxCom.Clear(); 

Спасибо @ Sidewinder94!

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