绑定到嵌套在具有实际数据上下文设置的选项卡控件中的数据网格时存在问题
本文关键字:数据 控件 选项 数据网 问题 存在 网格 设置 嵌套 上下文 绑定 | 更新日期: 2023-09-27 18:12:01
我对WPF和MVVM比较陌生,我不明白为什么我的绑定不起作用。如果你有任何建议,我将不胜感激!
提前感谢!
<视图/strong>
<UserControl x:Class="TestEval.View.BuilderView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d" Height="400" Width="300"
xmlns:vm="clr-namespace:TestEval.ViewModel">
<Grid>
<TabControl ItemsSource="{Binding Tabs}" SelectedIndex="{Binding SelectedIndex}" HorizontalAlignment="Left" Height="319" Margin="0,81,0,0" VerticalAlignment="Top" Width="300">
<TabControl.ContentTemplate>
<DataTemplate>
<DataGrid AutoGenerateColumns="False" ItemsSource="{Binding Path=SelectedEvaluation.Groups}">
<DataGrid.Columns>
<DataGridTextColumn Header="Group" Binding="{Binding Name}" />
</DataGrid.Columns>
<DataGrid.RowDetailsTemplate>
<DataTemplate>
<StackPanel>
<DataGrid ItemsSource="{Binding SelectedEvaluation.Groups.Questions}" SelectedItem="{Binding Selected}">
<DataGrid.RowDetailsTemplate>
<DataTemplate>
<StackPanel>
<Label Content="{Binding Content}"></Label>
<Label Content="*" IsEnabled="{Binding IsRequired}" ></Label>
<Label Content="Answer Type:"></Label>
</StackPanel>
</DataTemplate>
</DataGrid.RowDetailsTemplate>
</DataGrid>
</StackPanel>
</DataTemplate>
</DataGrid.RowDetailsTemplate>
</DataGrid>
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
<Button Content="[+] Group" Command="{Binding AddGroupCommand}" HorizontalAlignment="Left" Margin="215,56,0,0" VerticalAlignment="Top" Width="75"/>
</Grid>
<
视图模型/strong>
这是保存选项卡并为它们设置数据上下文的视图模型
namespace TestEval.ViewModel
{
class BuilderViewModel: ViewModelBase
{
private ObservableCollection<TabItem> tabs = new ObservableCollection<TabItem>();
public ObservableCollection<TabItem> Tabs
{
get { return tabs; }
set
{
tabs = value;
OnPropertyChanged("Tabs");
}
}
private int selectedIndex;
public int SelectedIndex
{
get { return selectedIndex; }
set
{
selectedIndex = value;
SelectedEvaluation = Tabs[selectedIndex].DataContext as EvaluationViewModel;
OnPropertyChanged("SelectedIndex");
}
}
private EvaluationViewModel selectedEvaluation;
public EvaluationViewModel SelectedEvaluation
{
get
{
return selectedEvaluation;
}
set
{
selectedEvaluation = value;
OnPropertyChanged("SelectedEvaluation");
}
}
private object selected;
public object Selected
{
get { return selected; }
set
{
if (value == null)
{
return;
}
selected = value;
if (selected is Group)
{
selected = selected as Group;
}
else
{
selected = selected as Question;
}
}
}
private RelayCommand addGroupCommand;
public ICommand AddGroupCommand
{
get
{
if (addGroupCommand == null)
{
addGroupCommand = new RelayCommand(p => this.AddGroup(), p => this.CanAddGroup);
}
return addGroupCommand;
}
}
public BuilderViewModel()
{
Tabs.Add(new TabItem{ Header = "Company Evaluation", DataContext = new EvaluationViewModel("Company") });
Tabs.Add(new TabItem { Header = "Customer Evaluation", DataContext = new EvaluationViewModel("Customer") });
SelectedIndex = 0;
}
public bool CanAddGroup
{
get
{
return SelectedEvaluation != null;
}
}
void AddGroup()
{
SelectedEvaluation.Groups.Add(new Group(){Name = "GroupTest"});
}
}
}
评价ViewModelnamespace TestEval.ViewModel
{
public class EvaluationViewModel : ViewModelBase
{
private ObservableCollection<Group> groups = new ObservableCollection<Group>();
public ObservableCollection<Group> Groups
{
get { return groups; }
set
{
groups = value;
OnPropertyChanged("Groups");
}
}
private string name;
public string Name
{
get { return name; }
set
{
name = value;
OnPropertyChanged("Name");
}
}
public EvaluationViewModel(string name)
{
this.Name = name;
}
}
}
组模型
namespace TestEval.Model
{
public class Group : ObservableObject
{
private ObservableCollection<Question> questions = new ObservableCollection<Question>();
public ObservableCollection<Question> Questions
{
get { return questions; }
set
{
questions = value;
OnPropertyChanged("Questions");
}
}
private string name;
public string Name
{
get { return name; }
set
{
name = value;
OnPropertyChanged("Name");
}
}
}
}
问题模型
public class Question : ObservableObject
{
private Guid id;
private string content;
private string answerType;
private string answers;
private bool isRequired;
private string group;
private bool showAnswers = false;
public Guid Id
{
get { return id; }
set { id = value; }
}
public string Content
{
get { return content; }
set
{
content = value;
OnPropertyChanged("Content");
}
}
public string AnswerType
{
get { return answerType; }
set
{
answerType = value;
if (answerType == "SingleChoice" || answerType == "MultipleChoice")
{
ShowAnswers = true;
}
else
{
ShowAnswers = false;
}
OnPropertyChanged("AnswerType");
}
}
public string Answers
{
get { return answers; }
set
{
answers = value;
OnPropertyChanged("Answers");
}
}
public string Group
{
get { return group; }
set
{
group = value;
OnPropertyChanged("Group");
}
}
public bool IsRequired
{
get { return isRequired; }
set
{
isRequired = value;
OnPropertyChanged("IsRequired");
}
}
public bool ShowAnswers
{
get { return showAnswers; }
set
{
showAnswers = value;
OnPropertyChanged("ShowAnswers");
}
}
public Question()
{
}
public Question(string content, string answerType, string answers, bool isRequired)
{
this.Id = new Guid();
this.Content = content;
this.AnswerType = answerType;
this.Answers = answers;
this.IsRequired = isRequired;
}
}
你其实离得不远,我认为你只是错过了关于MVVM中数据绑定如何工作的几个关键点。
最严重的问题是视图模型中有一个TabItem数组。这样做不是正确的MVVM,事实上,它根本不应该这样做。TabItem是一个控件元素,因此只属于视图,你应该为你的选项卡创建一个视图模型,将这些元素的集合添加到你的父视图模型中,然后在TabControl中绑定到它。为了说明为什么这是错误的,试着这样做:将你的网格放在StackPanel中,方向设置为垂直,然后尝试添加一个重复的TabControl绑定到相同的TabItem集合。当你四处点击时,选项卡会从一个控件中消失,因为TabItem只能有一个父元素,而你现在正试图将它绑定到两个。要解决这个问题,请在EvaluationViewModel中添加一个头字段,并调整构造函数以接受头字段:
private string _Header;
public string Header
{
get { return this._Header; }
set { this._Header = value; RaisePropertyChanged(() => this.Header); }
}
现在将你的tabs属性改为ObservableCollection<EvaluationViewModel>
,你现在应该这样设置:
Tabs.Add(new EvaluationViewModel("Company Evaluation", "Company"));
Tabs.Add(new EvaluationViewModel("Customer Evaluation", "Customer"));
SelectedEvaluation = Tabs.First(); // you'll see why I'm doing this in a moment
回到你的选项卡控件,你的TabsItems将被自动创建,它们的DataContext将被设置为相应的EvaluationViewModel,所以设置DisplayMemberPath来指示哪个字段是标题,去掉视图模型中的SelectedIndex绑定和相应的SelectedIndex属性(你不需要它),并将SelectedItem直接绑定到你的selecte贬值属性。你的TabControl XAML现在看起来应该是这样的:
<TabControl ItemsSource="{Binding Tabs}" DisplayMemberPath="Header" SelectedItem="{Binding SelectedEvaluation}" HorizontalAlignment="Left" ... etc...
现在,当您的TabControl.ContentTemplate
实例化时,它的DataContext被设置为与其相应选项卡的DataContext相同。在模板中有两个地方,你显式绑定到selecte贬值,即SelectedEvaluation.Groups
和SelectedEvaluation.Groups.Questions
。修改为Groups
和Groups.Questions
。
最后,您没有初始化您的Groups集合,但我相信您最终会发现自己:
private ObservableCollection<Group> _Groups = new ObservableCollection<Group>();
这将达到你想要做的。如果你有任何需要澄清的地方,请回到这里。