Something is wrong with my binding. But I can't find it
I have a status type control (UserControl) that has an ItemsControl with binding that relies on a ViewModelBase object which provides list of BrokenRules, like so:
<ItemsControl ItemsSource="{Binding BrokenRules}" >
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock>
<Hyperlink Foreground="Red" >
<TextBlock Text="{Binding Description}" />
</Hyperlink>
</TextBlock>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
The binding works the way I want to, in the sense that any and all broken rules Descriptions are displayed. A rule is pretty much just a description and a delegate that is executed when the rule is told to validate itself.
Most rules have Descriptions that are known up front, before the rule is asked to validate itself. For example, "Name is not valued" is a fine description of what went wrong if the validation delegate !Name.IsNullOrEmptyAfterTrim() fails.
The problem comes with one particular rule, which checks for duplicate names. If the dup check fails, I want to be able to say what the duplicated value is, which is impossible to know up front. So the rule needs to update the Description when the validation delegate is executed.
When I unit test or leave a debug trace in the validation delegate, the broken rule description is updated. But when I run the app, the broken rule description is what is was before it was updated.
I am therefore guessing my binding is not correct. Can anyone suggest what the problem / fix is?
Cheers,
BerrylUPDATE ====================
This is code from my ViewModelBase class:
private readonly List<RuleBase> _rules = new List<RuleBase>();
// inheritors add rules as part of construction开发者_开发知识库
protected void _AddRule(RuleBase rule) { _rules.Add(rule); }
public ObservableCollection<RuleBase> BrokenRules { get { return _brokenRules; } }
protected ObservableCollection<RuleBase> _brokenRules;
public virtual IEnumerable<RuleBase> GetBrokenRules() {
return GetBrokenRules(string.Empty);
}
public virtual IEnumerable<RuleBase> GetBrokenRules(string property) {
property = property.CleanString();
_brokenRules = new ObservableCollection<RuleBase>();
foreach (var r in _rules) {
// Ensure we only validate this rule
if (r.PropertyName != property && property != string.Empty) continue;
var isRuleBroken = !r.ValidateRule(this);
if (isRuleBroken) _brokenRules.Add(r);
return _brokenRules;
}
You must ensure that the BrokenRules observable collection instance doesn't change, your code on the View Model should look something like:
public ObservableCollection<BrokenRule> BrokenRules
{
get;
set;
}
private void ValidateRules()
{
// Validation code
if (!rule.IsValid)
{
this.BrokenRules.Add(new BrokenRule { Description = "Duplicated name found" });
}
}
If for example, you do something like this instead:
this.BrokenRules = this.ValidateRules();
You would be changing the collection which is bound to the ItemsControl without notifying it and changes won't reflect on UI.
精彩评论