场景 :在 Silverlight 4 MVVM 项目中,我们有一个 ListBox
控件包含项目,所选项目是双向绑定(bind)到 ViewModel 中的相应属性。另一个控件(例如原因,我已将其简化为单个 TextBox
)是绑定(bind)到所选项目内容的数据。该值应在离开/失去焦点时更新。
问题 :当TextBox
中的值已更改,我们将其保留为 TextBox
通过按 Tab 键,一切都按预期工作 - 值被更新。但是,如果用户点击 ListBox
中的不同项目, ,然后在 TextBox
的内容之前触发 SelectedItem setter setter 被触发,没有机会处理用户输入。
您可以在调试器中看到,当向属性 setter 添加断点时,新的 ListView
首先应用选择,在 TextBox
之前更新被处理。
期望的行为 :我们需要知道当前选中的item在用户选择另一个item之前被修改过。不希望有一个自定义更新触发器,它会在每次按键时通知(我们知道这是可能的)。
你能帮我吗?
代码(一个非常简单的例子):
查看型号
public abstract class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
public class ItemViewModel : ViewModelBase
{
private string _content;
public ItemViewModel(string initContent)
{
_content = initContent;
}
public string Content
{
get
{
return _content;
}
set
{
if (_content != value)
{
_content = value;
OnPropertyChanged("Content");
}
}
}
}
public class MainViewModel : ViewModelBase
{
private ObservableCollection<ItemViewModel> _items =
new ObservableCollection<ItemViewModel>();
private ItemViewModel _selectedViewModel;
public ObservableCollection<ItemViewModel> Items
{
get
{
return _items;
}
}
public ItemViewModel SelectedItem
{
get
{
return _selectedViewModel;
}
set
{
if (_selectedViewModel != value)
{
_selectedViewModel = value;
OnPropertyChanged("SelectedItem");
}
}
}
}
XAML
<Grid x:Name="LayoutRoot" Background="White">
<ListBox Height="100"
HorizontalAlignment="Left"
Margin="12,12,0,0"
VerticalAlignment="Top"
ItemsSource="{Binding Items}"
SelectedItem="{Binding SelectedItem, Mode=TwoWay}"
DisplayMemberPath="Content"
Width="220" />
<TextBox Height="23"
HorizontalAlignment="Left"
Margin="12,118,0,0"
Text="{Binding SelectedItem.Content, Mode=TwoWay}"
VerticalAlignment="Top"
Width="220" />
</Grid>
后面的 XAML 代码
public MvvmTestView()
{
InitializeComponent();
Loaded += new RoutedEventHandler(MvvmTestView_Loaded);
}
void MvvmTestView_Loaded(object sender, RoutedEventArgs e)
{
MainViewModel viewModel = new MainViewModel();
viewModel.Items.Add(new ItemViewModel("Hello StackOverflow"));
viewModel.Items.Add(new ItemViewModel("Thanks to Community"));
DataContext = viewModel;
}
更新 1
我提出 a self designed solution供您检查,这可能是被接受的,我仍然想鼓励您发表评论并给出提示。谢谢。
最佳答案
每次在文本框中更改文本时,您可以向文本框添加一个行为以更新绑定(bind)。也许这解决了你的问题。
这是 Behavior 类的代码:
public class UpdateTextBindingOnPropertyChanged : Behavior<TextBox> {
// Fields
private BindingExpression expression;
// Methods
protected override void OnAttached() {
base.OnAttached();
this.expression = base.AssociatedObject.GetBindingExpression(TextBox.TextProperty);
base.AssociatedObject.TextChanged+= OnTextChanged;
}
protected override void OnDetaching() {
base.OnDetaching();
base.AssociatedObject.TextChanged-= OnTextChanged;
this.expression = null;
}
private void OnTextChanged(object sender, EventArgs args) {
this.expression.UpdateSource();
}
}
这是 XAML:
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:local="Namespace of the class where UpdateTextBindingOnPropertyChanged is defined"
<TextBox Text="{Binding SelectedItem.Content, Mode=TwoWay}">
<i:Interaction.Behaviors>
<local:UpdateTextBindingOnPropertyChanged />
</i:Interaction.Behaviors>
</TextBox >
关于Silverlight MVVM 绑定(bind)更新以不希望的顺序触发,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5338546/