WPF 组合框不更新 ViewModel
我在 WPF 中的组合框上遇到了一个非常奇怪的问题。我之前在一个更简单的实现中使用过它,并认为我知道它是如何工作的,但显然不知道。场景如下...我有三个具有父/子关系的类,我有一个类型为 AnswerViewModel 的列表,我将其填充在组合框中。我希望类的 IsSelected 属性是在组合框中获取/设置的值。下面是一些代码,希望足以了解我所指的内容。
这些是模型。
public class Quiz
{
public string QuizName {get;set;}
public List<Question> Questions {get;set;}
}
public class Question
{
public int QuestionId {get;set;}
public string QuestionText {get;set;}
public List<Answer> {get;set;}
}
public class Answer
{
public int AnswerId {get;set;}
public string AnswerText {get;set;}
public bool IsSelected {get;set;}
}
这些是 ViewModel
QuizViewModel.cs
// This will create QuestionViewModel for each question.
ObservableCollection<QuestionViewModel> Questions {get;set;}
QuestionViewModel.cs
// This will create AnswerViewModel for each answer
ObservableCollection<AnswerViewModel> Answers {get;set;}
AnswerViewModel.cs
Answer answer;
// ctor
public AnswerViewModel(Answer answer...)
{
this.answer = answer;
...
}
public string AnswerText
{
get { return answer.AnswerText; }
set
{
answer.AnswerText = value;
NotifyPropertyChanged("AnswerText");
}
}
public bool IsSelected
{
get { return _answer.IsSelected; }
set
{
answer.IsSelected = value;
NotifyPropertyChanged("IsSelected"); // <--- Breakpoint
}
}
这些是 XAML
Quiz.xaml
<ItemsControl ItemsSource="{Binding Questions}" />
Question.xaml
<ComboBox x:Name="answerCombo"
ItemsSource="{Binding Answers}"
DisplayMemberPath="AnswerText"
SelectedValue="{Binding Path=IsSelected}"
SelectedValuePath="IsSelected"/>
组合框已正确填充(它绑定到 AnswerViewModel 的集合),但是当我做出选择时,我期望的是在断点处看到有两个事件。一种表示不再选择的项目为 false,另一种表示选择的新项目。但它却永远不会被击中。
因此,我在网络上搜索寻求帮助,发现了一些有趣的信息并尝试了很多事情,但到目前为止似乎一切都不完整。例如:
<ComboBox x:Name="answerCombo"
ItemsSource="{Binding Answers}"
DisplayMemberPath="AnswerText"
SelectedValue="{Binding Path=IsSelected}"
SelectedValuePath="IsSelected">
<ComboBox.ItemContainerStyle>
<Style TargetType="{x:Type ComboBoxItem}">
<Setter Property="IsSelected" Value="{Binding Path=IsSelected, Mode=TwoWay}"/>
</Style>
</ComboBox.ItemContainerStyle>
</Combobox>
但这只会在下拉时选择组合框中的正确项目。我理解这个标记是正确的。
因此,简而言之,当我在组合框中选择一个项目时,我希望更新 AnswerViewModel 上的 IsSelected 属性。任何帮助将不胜感激。
如果需要更多信息,请告诉我。
谢谢你, 模糊
**更新**
好吧,我想我实际上解决了它,但仍然如果有人对此有建议或想法,我仍然想听听他们。
这就是我所做的,我只更改了 Combobox xaml,如下所示:
<ComboBox x:Name="answerCombo"
ItemsSource="{Binding Answers}"
DisplayMemberPath="AnswerText"
SelectedValue="{Binding Path=ItemsSource/, RelativeSource={RelativeSource Self}}">
<ComboBox.ItemContainerStyle>
<Style TargetType="{x:Type ComboBoxItem}">
<Setter Property="IsSelected" Value="{Binding Path=IsSelected, Mode=TwoWay}"/>
</Style>
</ComboBox.ItemContainerStyle>
</Combobox>
基本上,这将 selectedvalue 设置为当前项目,并且由于 itemcontainerstyle 处理下拉列表时的情况,因此它将组合框的 IsSelected 属性绑定到我的 IsSelected 属性视图模型。这似乎奏效了。
I have a really weird issue with Combobox in WPF. I have used it before in a simpler implementation and thought I knew how it works, but apparently not. The scenario is as follows... I have three classes which are in a parent/child relationship, I have a list of a type AnswerViewModel which I populate in a Combobox. I want the IsSelected property on the class to be the value that is get/set in the Combobox. Below is some of the code, hopefully enough to see what I am referring to.
These are the models.
public class Quiz
{
public string QuizName {get;set;}
public List<Question> Questions {get;set;}
}
public class Question
{
public int QuestionId {get;set;}
public string QuestionText {get;set;}
public List<Answer> {get;set;}
}
public class Answer
{
public int AnswerId {get;set;}
public string AnswerText {get;set;}
public bool IsSelected {get;set;}
}
These are the ViewModels
QuizViewModel.cs
// This will create QuestionViewModel for each question.
ObservableCollection<QuestionViewModel> Questions {get;set;}
QuestionViewModel.cs
// This will create AnswerViewModel for each answer
ObservableCollection<AnswerViewModel> Answers {get;set;}
AnswerViewModel.cs
Answer answer;
// ctor
public AnswerViewModel(Answer answer...)
{
this.answer = answer;
...
}
public string AnswerText
{
get { return answer.AnswerText; }
set
{
answer.AnswerText = value;
NotifyPropertyChanged("AnswerText");
}
}
public bool IsSelected
{
get { return _answer.IsSelected; }
set
{
answer.IsSelected = value;
NotifyPropertyChanged("IsSelected"); // <--- Breakpoint
}
}
These are the XAMLs
Quiz.xaml
<ItemsControl ItemsSource="{Binding Questions}" />
Question.xaml
<ComboBox x:Name="answerCombo"
ItemsSource="{Binding Answers}"
DisplayMemberPath="AnswerText"
SelectedValue="{Binding Path=IsSelected}"
SelectedValuePath="IsSelected"/>
The Combobox is populated correctly (It is bound to the Collection of AnswerViewModel), but when I make a selection what I expect is to see at the breakpoint is two events. One for the false on the item no longer selected, and true for the new item selected. But instead it never gets hit.
So I scour the web looking for help and found some interesting information and tried a number of things but, so far nothing seems to be complete. For example:
<ComboBox x:Name="answerCombo"
ItemsSource="{Binding Answers}"
DisplayMemberPath="AnswerText"
SelectedValue="{Binding Path=IsSelected}"
SelectedValuePath="IsSelected">
<ComboBox.ItemContainerStyle>
<Style TargetType="{x:Type ComboBoxItem}">
<Setter Property="IsSelected" Value="{Binding Path=IsSelected, Mode=TwoWay}"/>
</Style>
</ComboBox.ItemContainerStyle>
</Combobox>
But this only selects the correct item in the Combobox when drop-down. Which I understand is correct for this markup.
So, in short, I would like to have the IsSelected Property on the AnswerViewModel updated when I select an item in the Combobox. Any help would be greatly appreciated.
If more information is required just let me know.
Thank you,
Obscured
** Update **
Ok, I think I actually resolved it, but still If anyone has suggestions, or thoughts on this, I would still like to hear them.
Here is what I did, I only changed the Combobox xaml as follows:
<ComboBox x:Name="answerCombo"
ItemsSource="{Binding Answers}"
DisplayMemberPath="AnswerText"
SelectedValue="{Binding Path=ItemsSource/, RelativeSource={RelativeSource Self}}">
<ComboBox.ItemContainerStyle>
<Style TargetType="{x:Type ComboBoxItem}">
<Setter Property="IsSelected" Value="{Binding Path=IsSelected, Mode=TwoWay}"/>
</Style>
</ComboBox.ItemContainerStyle>
</Combobox>
Basically this sets the selectedvalue to the current item, and since the itemcontainerstyle handles the case when drop-down it binds the IsSelected property of the combobox to the IsSelected property of my ViewModel. And this appears to do the trick.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
只需删除
SelectedValue
和SelectedValuePath
属性即可,这不是它们的工作方式。SelectedValuePath
指示所选项目的哪个属性将作为ComboBox
的SelectedValue
;如果您说SelectedValuePath
是“IsSelected”,则SelectedValue
将是SelectedItem.IsSelected
,这显然不是您想要的......并且您对SelectedValue
的绑定引用了一个不存在的属性 (QuestionViewModel.IsSelected
)这应该适合您:
Just remove the
SelectedValue
andSelectedValuePath
properties, it's not how they work.SelectedValuePath
indicates which property of the selected item will be theSelectedValue
of theComboBox
; if you say that theSelectedValuePath
is "IsSelected", theSelectedValue
will beSelectedItem.IsSelected
, which is clearly not what you want... And your binding forSelectedValue
refers to a property that doesn't exist (QuestionViewModel.IsSelected
)This should work for you:
你尝试过吗:
have you try: