2010-07-16 4 views
3

Что-то не так с моей привязкой. Но я не могу найти егоwpf databinding timing issue

У меня есть контроль типа состояния (UserControl), который имеет ItemsControl с креплениями, которая опирается на объект ViewModelBase который предоставляет список BrokenRules, например, так:

<ItemsControl ItemsSource="{Binding BrokenRules}" > 
    <ItemsControl.ItemTemplate> 
     <DataTemplate> 
      <TextBlock> 
       <Hyperlink Foreground="Red" > 
        <TextBlock Text="{Binding Description}" /> 
       </Hyperlink> 
      </TextBlock> 
     </DataTemplate> 
    </ItemsControl.ItemTemplate> 
</ItemsControl> 

Связывание работает так, как я хочу, в том смысле, что отображаются все и все нарушенные правила. Правило в значительной степени просто описание и делегат, который выполняется, когда правилу говорят, чтобы проверить себя.

Большинство правил имеют описания, которые известны спереди, прежде чем правило попросят подтвердить себя. Например, «Имя не оценено» - прекрасное описание того, что пошло не так, если делегат проверки правильности! Name.IsNullOrEmptyAfterTrim() терпит неудачу.

Проблема связана с одним конкретным правилом, которое проверяет наличие дубликатов имен. Если проверка дубликатов не удалась, я хочу иметь возможность сказать, что такое дублированное значение, что невозможно узнать заранее. Поэтому правилу необходимо обновить описание, когда выполняется делегирование валидации.

Когда я тестирую модуль или оставляю трассировку отладки в делетете проверки, обновленное описание правила обновляется. Но когда я запускаю приложение, сломанное описание правила - это то, что было до было обновлено.

Я поэтому предполагаю, что привязка неверна. Может ли кто-нибудь предложить проблему/исправить?

Cheers,
Berryl

UPDATE ====================

Это код из моего класса ViewModelBase:

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; 
    } 
+0

Включает ли ваш класс ViewModelBase INotifyPropertyChanged? то есть. Знает ли пользовательский интерфейс, когда свойство Description изменилось? –

+0

Вы добавляете элементы в коллекцию BrokenRules? это ObservableCollection? – Anero

+0

@ Matt. Да, VmBase реализует INPC. Что касается второй части вашего ответа, я думаю, что Aero близок к тому, что если я не буду воссоздавать экземпляр коллекции каждый раз, тогда пользовательский интерфейс останется синхронизированным с изменениями. Нужно работать с ним. Cheers – Berryl

ответ

1

Вы должны убедиться, что наблюдаемый экземпляр коллекции BrokenRules не изменяется, ваш код на View Model должна выглядеть примерно так:

public ObservableCollection<BrokenRule> BrokenRules 
{ 
    get; 
    set; 
} 

private void ValidateRules() 
{ 
    // Validation code 
    if (!rule.IsValid) 
    { 
    this.BrokenRules.Add(new BrokenRule { Description = "Duplicated name found" }); 
    } 
} 

Если, например, вы делаете что-то вроде этого: вместо

this.BrokenRules = this.ValidateRules(); 

Вы бы изменения коллекции, которая привязана к ItemsControl без уведомления его и изменения не отразятся на пользовательском интерфейсе.

+0

Я думаю, что вы близко к нему. Мой список нарушенных правил не был ObservableCollection И он создает новый экземпляр в каждом цикле. Я исправил тип коллекции, так как это было тривиально, и я посмотрю, как это сделать с тем же экземпляром коллекции.Вам нужно удалить правила, которые становятся несломанными, а также добавлять сломанные, поэтому это не так просто. Cheers – Berryl

+1

@Berryl: Вместо создания новой коллекции вы можете использовать '.Clear()'. Это не нарушит привязку данных. – Jens

+0

Сочетание всех комментариев здесь обеспечило правильную работу. Поскольку у Анеро было единственное, что я мог отметить как ответ, я отметил его как такового. Спасибо всем! – Berryl