C# 基于绑定集合创建控件组
因此,我希望有一个大致如下的数据结构:C# 基于绑定集合创建控件组,c#,wpf,C#,Wpf,因此,我希望有一个大致如下的数据结构: List<Question> questions 在我的WPF表单上,我希望能够将这个列表绑定到一个堆栈框,并让它为列表中的每个问题添加一个新的网格,该网格的确切布局在每个派生类的方法中定义。这些Question对象将基于JSON文件生成,以生成问题集 例如,OneTenQuestion将添加一个滑块和一个标签,而freecomentquestion将添加一个标签和一个文本框。还有其他几种类型的问题,但我认为这些例子应该足够了 我从哪里开始呢
List<Question> questions
在我的WPF表单上,我希望能够将这个列表
绑定到一个堆栈框,并让它为列表中的每个问题
添加一个新的网格
,该网格的确切布局在每个派生类的方法中定义。这些Question
对象将基于JSON文件生成,以生成问题集
例如,OneTenQuestion
将添加一个滑块和一个标签,而freecomentquestion
将添加一个标签和一个文本框。还有其他几种类型的问题,但我认为这些例子应该足够了
我从哪里开始呢?我正在从WinForms过渡到WPF,因此,如果有一个指针指向正确的概念或表明这不是最好的方法,我将不胜感激。在这种情况下,您通常使用数据模板(请参阅)。当您需要动态创建控件时,使用
DataTemplate
是一个非常强大的解决方案。不带键(
x:key
)的DataTemplate
是一个隐式模板,因为它将自动应用于与DataTemplate.DataType
匹配的类型,即不显式引用。您应该为每种类型的问题定义一个隐式数据模板
或者,如果选择DataTemplate
取决于更多的条件而不仅仅是数据类型,则可以使用
使用ItemsControl
而不是StackPanel
,如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));
}
}
公共类视图模型:INotifyPropertyChanged
{
公共视图模型()
{
this.Questions=新的ObservableCollection()
{
新一题(),
新问题
};
}
私人收集问题;
公开收集问题
{
get=>this.questions;
设置
{
这个问题=价值;
OnPropertyChanged();
}
}
公共事件属性更改事件处理程序属性更改;
受保护的虚拟void OnPropertyChanged([CallerMemberName]字符串propertyName=null)
{
this.PropertyChanged?.Invoke(this,newpropertychangedeventargs(propertyName));
}
}
main window.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>
<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>