Создать группу элементов управления на основе связанной коллекции - PullRequest
0 голосов
/ 27 мая 2020

Итак, я хочу иметь структуру данных по строкам:

List<Question> questions

Где Question - это абстрактный класс, из которого происходят различные другие типы вопросов, например:

class OneTenQuestion: Question
class FreeCommentQuestion: Question
...

В моей форме WPF я затем хочу иметь возможность привязать этот List<Question> к стеку и добавить новые Grid элементов управления для каждого Question в списке с точным макетом этой сетки, определяемым в метод каждого производного класса. Эти Question объекты будут созданы на основе файла JSON для создания наборов вопросов.

Например, OneTenQuestion добавит ползунок и метку, а FreeCommentQuestion добавит метку и текстовое поле. Есть несколько других типов вопросов, но я думаю, что этих примеров должно хватить.

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

1 Ответ

1 голос
/ 27 мая 2020

Обычно в этом сценарии используются шаблоны данных (см. Microsoft Docs: Обзор шаблонов данных ). Использование DataTemplate - очень мощное решение, когда вам нужно динамически создавать элементы управления.
A DataTemplate без ключа (x:Key) - это неявный шаблон, так как он будет применяться автоматически, т.е. без явной ссылки, к типу что соответствует DataTEmplate.DataType. Вы должны определить неявный DataTemplate для каждого типа Question.
В качестве альтернативы вы можете использовать DataTemplateSelector, если выбор DataTemplate зависит от большего количества условий, чем только тип данных.

Вместо StackPanel вы используете ItemsControl например ListView.
Вы можете изменить ItemsControl.ItemsPanel, чтобы складывать элементы вертикально (по умолчанию) или горизонтально:

ViewModel.cs

public class ViewModel : INotifyPropertyChanged
{
  public ViewModel()
  {
    this.Questions = new ObservableCollection<Question>() 
    {
      new OneTenQuestion(), 
      new FreeCommentQuestion
    };
  }

  private ObservableCollection<Question> questions;
  public ObservableCollection<Question> Questions
  {
    get => this.questions;
    set
    {
      this.questions = value;
      OnPropertyChanged();
    }
  }

  public event PropertyChangedEventHandler PropertyChanged;
  protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
  {
    this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
  }
}

MainWindow.xaml

<Window>
  <Window.DataContext>
    <ViewModel />
  </Window.DataContext>
  <Window.Resources>
    <DataTemplate DataType="{x:Type OneTenQuestion}">

      <!-- The DataContext is the OneTenQuestion item. You can bind to it directly -->
      <Slider />
    </DataTemplate>

    <DataTemplate DataType="{x:Type FreeCommentQuestion}">
      <StackPanel>

        <!-- 
          The DataContext is the FreeCommentQuestion item.  
          You can bind to it directly.
          If FreeCommentQuestion had a property Comment, then you could bind the TextBox to it.
        -->
        <Label />
        <TextBox Text="{Binding Comment}" />
      </StackPanel>
    </DataTemplate>
  </Window.Resources>

  <ListView ItemsSource="{Binding Questions}" />
</Window>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...