ListBox - CollectionViewSource - многопоточность - таймеры - не обновляются - PullRequest
0 голосов
/ 18 марта 2011

У меня проблемы с обновлением списка.Parts od Window.xaml

DataContext="{Binding Link, Source={StaticResource Computer}}">
<Window.Resources>
        <CollectionViewSource Source="{Binding GetLinkInfo}" x:Key="compLink">
                <CollectionViewSource.SortDescriptions>
                        <scm:SortDescription PropertyName="Grupa" />
                        <scm:SortDescription PropertyName="Host" />
                </CollectionViewSource.SortDescriptions>
                <CollectionViewSource.GroupDescriptions>
                        <PropertyGroupDescription PropertyName="Grupa" />
                </CollectionViewSource.GroupDescriptions>
        </CollectionViewSource>
</Window.Resources>
<ListBox x:Name="_lbLink" ItemsSource="{Binding Source={StaticResource compLink}}">
</ListBox>

И Window.xaml.cs

private void InitializedTimers()
{
    _timer = new System.Timers.Timer();
    _timer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
    _timer.Interval = 10 * 1000;
    _timer.Enabled = true;
}

private void OnTimedEvent(object source, ElapsedEventArgs e)
{
    MainViewModelLocator mvm = Application.Current.Resources["Computer"] as MainViewModelLocator;
    LinkViewModel lvm = mvm.Link;
    if (lvm != null)
    {
        if ((from t in lvm.GetLinkInfo
             where t.State == MRPLink.Link.StateLink.NOTCHECK
             select t).Count() > 0)
        {
            int id = (from t in lvm.GetLinkInfo
                where t.State == MRPLink.Link.StateLink.NOTCHECK
                select t).First().ID;
            lvm.UpdateStatus(id, MRPLink.Link.StateLink.CZECKOK, "xxxx");
        }
    }
}

Детали ViewModel.cs

 public void UpdateStatus(int id, StateLink aState, string aIp)
{
    _localinfo.Where(t => t.ID == id).ToList().ForEach(t =>
    {
        t.State = aState;
        if (!String.IsNullOrEmpty(aIp))
        {
            t.LastIp = aIp;
            t.LastSea = DateTime.Now;
        }
    });
    RaisePropertyChanged("GetLinkInfo");
}

Свойства вызывается, но ListBoxне обновляется.
Мне кажется, что это связано с таймером.Но я не знаю, как обойти.

Спасибо за помощь.

ДОБАВЛЕНО
- Я исправляю знак (выберите t) .Count ()> 0) из ==
- Когда я меняю таймер на DispatcherTimer, я получаю доступ к DataContent, но не обновляюсь автоматически.

LinkViewModel lvm = this.DataContext as LinkViewModel;

Я могу использовать _lbLink.Items.Refresh ();после любого изменения: (

ADDED2
После воспроизведения Stave B Я думаю о DispatcherHelper
Я использую его таким образом
Модульное тестирование с MVVM Light & DispatcherHelper

DispatcherHelper.CheckBeginInvokeOnUI(() =>
{
    lvm.UpdateStatus(id, MRPLink.Link.StateLink.CZECKOK, "xxx");
    //_lbLink.Items.Refresh();
});

Но не обновляет порог.

ADDED3:
После этого изменения я вижу, что выполняются свойства GetLinkInfo, но в ListBox не обновляется: (

ДОБАВЛЕНО 4:

После комментария blindmeis Мое приложение исправлено. Спасибо всем за помощь.

Ответы [ 2 ]

0 голосов
/ 18 марта 2011

Я не вижу, где определен ваш GetLinkInfo, поэтому я предполагаю следующее.

в вашем текстовом тексте окна у вас есть свойство, и вы просто запускаете коллекцию один раз и просто добавляете, удаляете элементы редактирования, если вам нужно.

 public ObservableCollection<LinkInfo> GetLinkInfo
 {get; set;}

в вашей ветке таймера или любом другом методе, который вы хотите обновить в своем состоянии, просто сделайте это

 Application.Current.Dispatcher.BeginInvoke(new Action(() =>lvm.UpdateStatus(id, MRPLink.Link.StateLink.CZECKOK, "xxxx");));

теперь важная вещь, если вы добавите или удалите элемент в свою коллекцию, наблюдаемая коллекция вызовет INotifyPropertyChanged и ваш пользовательский интерфейс будет обновлен. если вы обновляете существующий элемент в вашей коллекции, ваш элемент (класс) для обновления должен реализовывать INotifyPropertyChanged. мне интересно, что показывает ваш список, потому что я не вижу никакой DataTemplate, но я думаю, что у вас есть один.

0 голосов
/ 18 марта 2011

Замените код UpdateStatus следующим:

public void UpdateStatus(int id, StateLink aState, string aIp)
{
    _localinfo.Where(t => t.ID == id).ToList().ForEach(t =>
    {
        t.State = aState;
        if (!String.IsNullOrEmpty(aIp))
        {
            t.LastIp = aIp;
            t.LastSea = DateTime.Now;
        }
    });
    Dispatcher.Invoke(()=>RaisePropertyChanged("GetLinkInfo"));
}

Работа, связанная с пользовательским интерфейсом, должна вызываться из потока пользовательского интерфейса. Это (если быть проще) цель объекта Dispatcher.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...