繁体   English   中英

WPF C# MVVM单选按钮加载列表内容

[英]WPF C# MVVM Radio Button load list content

大家好,我想制作一个单选按钮,如何从列表中获取参数。 我不明白如何创建列表以在单选按钮 + 文本框中实现所有参数,如下所示:

问题1:猫是什么?
答案 1:动物
答案 2:人类
答案 3:石头

如果我有这样的东西,我怎么能绑定:

<ListBox
    HorizontalAlignment="Left"
    Height="313"
    Margin="57,29,0,0"
    VerticalAlignment="Top"
    Width="681"
    SelectionMode="Single"
    IsSynchronizedWithCurrentItem="True"
>
    <ListBox.ItemTemplate>
        <DataTemplate>
            <StackPanel>
                <TextBlock Text="This is question 1!" Margin="25" FontSize="25" />
                <RadioButton GroupName="First Question" IsChecked="False" Margin="10" Content="{Binding LoadRadioContent}" />
            </StackPanel>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

您必须创建一个问题列表的结构,其中每个问题都有一个可能答案的列表。

以下示例使用 Microsoft Docs 提供的RelayCommand实现: Relaying Command Logic 它使用由QuestionAnswer组成的组合数据 model :

问题.cs

public class Question : INotifyPropertyChanged
{
  public Question(string summary, Answer answer)
  {
    this.Summary = summary;
    this.Answer = answer;
  }

  public string Summary { get; set; }
  public Answer Answer { get; set; }

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

答案.cs

public class Answer : INotifyPropertyChanged
{
  public Answer(IEnumerable<IChoice> choices)
  {
    this.Choices = choices;
  }

  // Evaluates the answer(s)
  public bool Validate()
  {
    this.IsCorrect = this.Choices.All(
      choice => choice.IsValidChoice && choice.IsSelected 
                || !choice.IsValidChoice && !choice.IsSelected);
    return this.IsCorrect;
  }

  public ICommand CheckAnswerCommand =>
    new RelayCommand(answer => Validate());
  
  public IEnumerable<IChoice> Choices { get; set; }

  private bool isCorrect;
  public bool IsCorrect
  {
    get => this.isCorrect;
    private set
    {
      this.isCorrect = value;
      OnPropertyChanged();
    }
  }

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

选择

public interface IChoice : INotifyPropertyChanged
{
  // Marks whether the choice is a valid answer
  bool IsValidChoice { get; }

  // Selects the choice as an answer
  bool IsSelected { get; set; }

  string Text { get; set; }
}

多选.cs

class MultiChoice : IChoice
{
  public MultiChoice(string text, bool isValidChoice)
  {
    this.Text = text;
    this.IsValidChoice = isValidChoice;
  }

  #region Implementation of IChoice

  public bool IsValidChoice { get; }

  private bool isSelected;    
  public bool IsSelected
  {
    get => this.isSelected;
    set
    {
      this.isSelected = value;
      OnPropertyChanged();
    }
  }

  private string text;    
  public string Text
  {
    get => this.text;
    set
    {
      this.text = value;
      OnPropertyChanged();
    }
  }

  #endregion

  #region Implementation of INotifyPropertyChanged

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

  #endregion
}

单选.cs

class SingleChoice : IChoice
{
  public SingleChoice(string text, bool isValidChoice)
  {
    this.Text = text;
    this.IsValidChoice = isValidChoice;
  }

  #region Implementation of IChoice

  public bool IsValidChoice { get; }    
  
  private bool isSelected;    
  public bool IsSelected
  {
    get => this.isSelected;
    set
    {
      this.isSelected = value;
      OnPropertyChanged();
    }
  }

  private string text;    
  public string Text
  {
    get => this.text;
    set
    {
      this.text = value;
      OnPropertyChanged();
    }
  }

  #endregion

  #region Implementation of INotifyPropertyChanged    

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

  #endregion
}

视图模型.cs

public class ViewModel : INotifyPropertyChanged
{
  public ObservableCollection<Question> Questions { get; set; }

  public ViewModel()
  {
    this.Questions = new ObservableCollection<Question>
    {
      new Question(
        "Which number follows '1'?",
        new Answer(
          new[]
          {
            new SingleChoice("3", false), 
            new SingleChoice("15", false), 
            new SingleChoice("2", true),
            new SingleChoice("7", false)
          })),
      new Question(
        "Which creature can fly?",
        new Answer(
          new[]
          {
            new MultiChoice("Bird", true),
            new MultiChoice("Elephant", false),
            new MultiChoice("Bee", true),
            new MultiChoice("Cat", false)
          }))
    };
  }

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

主窗口.xaml

<Window xmlns:system="clr-namespace:System;assembly=mscorlib">
  <Window.DataContext>
    <ViewModel />
  </Window.DataContext>

  <StackPanel>
    <CheckBox Content="Answer 1 is Correct?" IsChecked="{Binding Questions[0].Answer.IsCorrect, Mode=OneWay}" />
    <CheckBox Content="Answer 2 is Correct?" IsChecked="{Binding Questions[1].Answer.IsCorrect, Mode=OneWay}" />
    <ListBox ItemsSource="{Binding Questions}">
      <ListBox.ItemTemplate>
        <DataTemplate DataType="{x:Type viewModels:Question}">
          <StackPanel>
            <TextBlock Text="{Binding Summary}" />
            <ListBox ItemsSource="{Binding Answer.Choices}">
              <ListBox.Resources>
                <DataTemplate DataType="{x:Type viewModels:SingleChoice}">
                  <RadioButton Content="{Binding Text}" 
                               GroupName="Answer"
                               IsChecked="{Binding IsSelected}"
                               Command="{Binding RelativeSource={RelativeSource AncestorType=ListBox}, Path=DataContext.Answer.CheckAnswerCommand}" />
                </DataTemplate>
                <DataTemplate DataType="{x:Type viewModels:MultiChoice}">
                  <CheckBox Content="{Binding Text}" 
                            IsChecked="{Binding IsSelected}"
                            Command="{Binding RelativeSource={RelativeSource AncestorType=ListBox}, Path=DataContext.Answer.CheckAnswerCommand}" />
                </DataTemplate>
              </ListBox.Resources>
            </ListBox>
          </StackPanel>
        </DataTemplate>
      </ListBox.ItemTemplate>
    </ListBox>
  </StackPanel>
</Window>

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM