ListBox - CollectionViewSource - 多线程 - 定时器 - 不更新

时间:2011-03-18 09:12:12

标签: wpf mvvm listbox

我在更新列表框时遇到问题 零件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 在我看来,这与计时器有关。但我不知道如何到处走走。

寻求帮助。

ADDED
- 我正确的标志(选择t).Count()&gt; 0)来自==
- 当我将计时器更改为DispatcherTimer时,我可以访问DataContent,但不能自动更新。

LinkViewModel lvm = this.DataContext as LinkViewModel;

我可以使用_lbLink.Items.Refresh();任何改变之后:(

ADDED2
重播后Stave B我想起DispatcherHelper
我就像那样使用它 Unit testing with MVVM Light & DispatcherHelper

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

但不会刷新窗台。

ADDED3:
在此更改后,我看到执行属性GetLinkInfo但在ListBox中不刷新:(

ADDED4:

评论blindmeis后,我的应用程序正确刷新。感谢大家的帮助。

2 个答案:

答案 0 :(得分:0)

将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"));
}

必须从UI线程调用与UI相关的工作。这是(简单)Dispatcher对象的目的。

答案 1 :(得分:0)

我看不到你的GetLinkInfo的定义,所以我假设如下。

在您的窗口的datacontext中,您有一个属性,您只需初始化该集合,只需添加,删除编辑项目。

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

在您的计时器线程或您想要更新状态的任何其他方法中,所以就这样做

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

现在重要的是,如果你向你的集合中添加或删除一个项目,observablecollection将引发INotifyPropertyChanged,你的ui会更新。如果更新集合中的现有项目,则要更新的项目(类)应实现INotifyPropertyChanged。我想知道你的列表框显示什么,导致无法看到任何DataTemplate,但我认为你有一个。