在另一个线程

时间:2015-11-23 04:47:56

标签: c# wpf multithreading

我正在开发我的第一个WPF浏览器应用程序。

我在dataGrid中加载发票,然后使用textBox或comboBox进行过滤。

因为加载需要几秒钟,我试图根据以下示例添加加载动画:

here

我想根据两个comboBox过滤我的dataGrid。

但我有这个错误

  

此类型的CollectionView不支持对其进行更改   来自与Dispatcher线程不同的线程的SourceCollection

invoiceCollection.Clear();行        和SearchFilter()中的invoiceCollection.Add(inv);;

我试过

App.Current.Dispatcher.Invoke((Action)delegate // <--- HERE
{
    //code here
});

但我仍然有同样的错误。

视图模型

public class ConsultInvoiceViewModel : ViewModelBase
{
      public Context ctx = new Context();

      private ICollectionView _dataGridCollection;
      private ObservableCollection<Invoice> invoiceCollection;


      public ConsultInvoiceViewModel()
      {
        if (!WPFHelper.IsInDesignMode)
        {
            var tsk = Task.Factory.StartNew(InitialStart);
            tsk.ContinueWith(t => { MessageBox.Show(t.Exception.InnerException.Message); }, CancellationToken.None, TaskContinuationOptions.OnlyOnFaulted, TaskScheduler.FromCurrentSynchronizationContext());
            }
        }

     private void InitialStart()
     {
         try
         {
          State = StateEnum.Busy;
          DataGridCollection = CollectionViewSource.GetDefaultView(Get());
          DataGridCollection.Filter = new Predicate<object>(Filter);
          }
          finally
          {
          State = StateEnum.Idle;
          }
     }

      private void SearchFilter()
      {

                                Task tsk = Task.Factory.StartNew(()=>
                                                                    {
                                         try
                                            {
                                             State = StateEnum.Busy;
                                             using (var ctx = new Context())
                                             {

                                                  var invs = ctx.Invoices
                                                             .Where(s.supplier == 1)
                                                             .GroupBy(x => new { x.suppInvNumber, x.foodSupplier })
                                                             .ToList()
                                                             .Select(i => new Invoice
                                                                          {
                                                                           suppInvNumber = i.Key.suppInvNumber,
                                                                           foodSupplier = i.Key.foodSupplier,
                                                                           totalPrice = i.Sum(t => t.totalPrice),
                                                                           });
                                                             .

                                            App.Current.Dispatcher.Invoke((Action)delegate 
                                           {
                                                invoiceCollection.Clear();
                                            });

                                                if (invs != null)
                                                       foreach (var inv in invs)
                                                       {
                                                            App.Current.Dispatcher.Invoke((Action)delegate  
                                                            {
                                                            invoiceCollection.Add(inv);
                                                            });

                                                       }
                                             }
                                             }
                                             finally
                                             {
                                              State = StateEnum.Idle;
                                             }

                    });
                                tsk.ContinueWith(t => { MessageBox.Show(t.Exception.InnerException.Message); }, CancellationToken.None, TaskContinuationOptions.OnlyOnFaulted, TaskScheduler.FromCurrentSynchronizationContext());
                            }

    public static readonly PropertyChangedEventArgs StateArgs = ViewModelBase.CreateArgs<ConsultInvoiceViewModel>(c => c.State);
    private StateEnum _State;

    public StateEnum State
    {
       get
       {
           return _State;
       }
       set
       {
            var oldValue = State;
            _State = value;
            if (oldValue != value)
            {
                 OnStateChanged(oldValue, value);
                 OnPropertyChanged(StateArgs);
            }
       }
    }

    protected virtual void OnStateChanged(StateEnum oldValue, StateEnum newValue)
    {
    }

}  

ViewModelBase

public abstract class ViewModelBase : INotifyPropertyChanged
{
    #region "INotifyPropertyChanged members"

    public event PropertyChangedEventHandler PropertyChanged;
    //This routine is called each time a property value has been set. 
    //This will //cause an event to notify WPF via data-binding that a change has occurred. 
    protected void OnPropertyChanged(string propertyName)
    {
        var handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    #endregion

    public void OnPropertyChanged(PropertyChangedEventArgs args)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, args);
    }

    public static PropertyChangedEventArgs CreateArgs<T>(Expression<Func<T, Object>> propertyExpression)
    {
        return new PropertyChangedEventArgs(GetNameFromLambda(propertyExpression));
    }

    private static string GetNameFromLambda<T>(Expression<Func<T, object>> propertyExpression)
    {
        var expr = propertyExpression as LambdaExpression;
        MemberExpression member = expr.Body is UnaryExpression ? ((UnaryExpression)expr.Body).Operand as MemberExpression : expr.Body as MemberExpression;
        var propertyInfo = member.Member as PropertyInfo;
        return propertyInfo.Name;
    }
}

3 个答案:

答案 0 :(得分:0)

也许尝试另一个例子:

的Xaml:

<Grid>
    <ListView ItemsSource="{Binding Items}">
        <ListView.ItemTemplate>
            <DataTemplate>
                <Label Content="{Binding .}"/>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
</Grid>

代码:

namespace WpfApplication2
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        DataContext = new Data();
    }
}
public class Data
{
    public ObservableCollection<int> Items { get; set; }
    public Data()
    {
        Items = new ObservableCollection<int>();
        Filters();
    }
    public void Filters()
    {
        Task.Factory.StartNew(DoWork);
    }
    public void DoWork()
    {
            int i = 0;
            while (true)
            {
                System.Threading.Thread.Sleep(1000);
                App.Current.Dispatcher.BeginInvoke(new Action(() => { Items.Add(++i); }));   
            }
    }
}
}

答案 1 :(得分:0)

.Net 4.5及更高版本中有一种非常好的解决方法:

private object _lock = new object(); 

BindingOperations.EnableCollectionSynchronization("YourCollection", _lock);

因此,每当您想要操作收藏时,您都不需要使用Dispatcher

以下是一些资源以获取更多信息:

http://10rem.net/blog/2012/01/20/wpf-45-cross-thread-collection-synchronization-redux

BindingOperations.EnableCollectionSynchronization mystery in WPF

https://msdn.microsoft.com/en-us/library/hh198845%28v=vs.110%29.aspx?f=255&MSPPError=-2147217396

答案 2 :(得分:-1)

我终于开始了它的工作。这很简单。

public class ConsultInvoiceViewModel : ViewModelBase
    {

      public Context ctx = new Context();

      private ICollectionView _dataGridCollection;
      private ObservableCollection<Invoice> invoiceCollection;


      public ConsultInvoiceViewModel()
      {
        invoiceCollection = new ObservableCollection<Invoice>();
        DataGridCollection = CollectionViewSource.GetDefaultView(Get());        

        if (!WPFHelper.IsInDesignMode)
        {
            var tsk = Task.Factory.StartNew(InitialStart);
            tsk.ContinueWith(t => { MessageBox.Show(t.Exception.InnerException.Message); }, CancellationToken.None, TaskContinuationOptions.OnlyOnFaulted, TaskScheduler.FromCurrentSynchronizationContext());
            }
        }

     private void InitialStart()
     {
         try
         {
          State = StateEnum.Busy;
          Get();
          }
          finally
          {
          State = StateEnum.Idle;
          }
     }

      private void SearchFilter()
      {

                                Task tsk = Task.Factory.StartNew(()=>
                                                                    {
                                         try
                                            {
                                             State = StateEnum.Busy;
                                             using (var ctx = new Context())
                                             {

                                                  var invs = ctx.Invoices
                                                             .Where(s.supplier == 1)
                                                             .GroupBy(x => new { x.suppInvNumber, x.foodSupplier })
                                                             .ToList()
                                                             .Select(i => new Invoice
                                                                          {
                                                                           suppInvNumber = i.Key.suppInvNumber,
                                                                           foodSupplier = i.Key.foodSupplier,
                                                                           totalPrice = i.Sum(t => t.totalPrice),
                                                                           });
                                                             .

                                            App.Current.Dispatcher.Invoke((Action)delegate 
                                           {
                                                invoiceCollection.Clear();
                                                if (invs != null)
                                                       foreach (var inv in invs)
                                                       {
                                                     invoiceCollection.Add(inv);
                                                       }
                                            });


                                             }
                                             }
                                             finally
                                             {
                                              State = StateEnum.Idle;
                                             }

                    });
                                tsk.ContinueWith(t => { MessageBox.Show(t.Exception.InnerException.Message); }, CancellationToken.None, TaskContinuationOptions.OnlyOnFaulted, TaskScheduler.FromCurrentSynchronizationContext());
                            }

        private ObservableCollection<Invoice> Get()
        {

            using (var ctx = new Context())
            {
                var invs = ctx.Invoices

                foreach (var inv in invs)
                {
                   App.Current.Dispatcher.Invoke((Action)delegate 
                   {
                       invoiceCollection.Add(inv);
                   });
                }
            }