2014-12-30 4 views
0

ObservableCollection이있는 ListBox에 내 응용 프로그램의 ItemsSource가 있습니다. 또한이 ItemsSource에 대한 데이터를 제공하는 serveral 클래스가 있습니다.ItemsWork를 BackgroundWorker에서 수정하면 예외가 발생합니다.

public ObservableCollection<Notification> NotificationItems { get; set; } 
    private object _stocksLock = new object(); 

은 내가 serveral DLL 어셈블리에서리스트 박스에 대한 데이터를 제공하는 모듈을로드하고 그

this.NotificationItems = new ObservableCollection<Notification>(); 
System.Windows.Data.BindingOperations.EnableCollectionSynchronization(
     this.NotificationItems, _stocksLock); 

처럼 내 생성자 내 컬렉션을 만들 수 있습니다. 컬렉션은 BackgroundWorker에

BackgroundWorker worker = new BackgroundWorker(); 
worker.DoWork += GetPluginModuleNotifications; 
List<IModul> Modules = new List<IModul>(); 
//[...] 
foreach (IModul PluginModul in AssemblyList) 
{ 
    //[...] 
    Modules.Add(PluginModul); 
    //[...] 
} 
this.Notifications.ItemsSource = this.NotificationItems; 

object[] Parameter = new object[] { Modules, this.ComponentFactory, 
     this.MyListBox}; 

//-->Edited 
worker.WorkerReportsProgress = true; 
worker.ProgressChanged += OnProgressChanged; 
//<--Edited 

worker.RunWorkerAsync(Parameter); 
//... 

//-->EDITED 
private void OnProgressChanged(object sender, ProgressChangedEventArgs e) 
{ 
    Notification toAdd = (Notification)e.UserState; 
    this.NotificationItems.Add(toAdd); 
} 
//<--EDITED 

내에서 호출되는 방법은 내가 목록 상자에 대한 항목을 제공하기 위해 IModul 각 항목을 원하는 알림 데이터를 얻을 수 있습니다. 이 부분은 잘 작동하므로 수신 할 데이터가로드됩니다. 내 응용 프로그램을 실행하고 때이 객체가 다른 스레드가 소유하고 있음을 XamlParseException의 원인이됩니다

.<dx:DXListBox x:Name="Notifications" VerticalAlignment="Stretch" BorderBrush="Transparent" MouseDoubleClick="NotificationGotoSource" ItemsSource="{Binding NotificationItems}"> 
    <dx:DXListBox.ItemTemplate> 
    <DataTemplate DataType="{x:Type cbcore:Notification}"> 
     <StackPanel Orientation="Horizontal"> 
      <Grid> 
       <Grid.ColumnDefinitions> 
        <ColumnDefinition Width="38" /> 
        <ColumnDefinition Width="*" MinWidth="157"/> 
        <ColumnDefinition Width="15" /> 
       </Grid.ColumnDefinitions> 
       <Image Source="{Binding ImageSource}" Grid.Column="0" Width="32" Height="32" VerticalAlignment="Top" HorizontalAlignment="Left" /> 
       <StackPanel Orientation="Vertical" Grid.Column="1"> 
        <Label FontWeight="Bold" FontSize="10" MaxHeight="25" MaxWidth="150"> 
         <TextBlock Text="{Binding Headline}" TextWrapping="Wrap" /> 
        </Label> 

        <Label FontWeight="Normal" FontSize="9" MaxHeight="100" MaxWidth="150"> 
         <TextBlock Text="{Binding Note}" TextWrapping="Wrap" /> 
        </Label> 
       </StackPanel> 
       <Label Cursor="Hand" Padding="0" Margin="0" MouseLeftButtonUp="Notification_RemoveSelected" Grid.Column="2" 
         OverridesDefaultStyle="True" BorderBrush="Black" Background="Transparent" 
         FontSize="8" FontWeight="Bold" VerticalAlignment="Top" HorizontalAlignment="Right"> 
        <TextBlock Foreground="Red" TextAlignment="Center">X</TextBlock> 
       </Label> 
      </Grid> 
     </StackPanel> 
    </DataTemplate> 
    </dx:DXListBox.ItemTemplate> 
</dx:DXListBox> 

: 다음은 NotificationPanel의 XAML은 다음과 같습니다 내 BackgroundWorker.DoWork 이벤트

private void GetPluginModuleNotifications(object sender, DoWorkEventArgs e) 
    { 
     object[] args = e.Argument as object[]; 
     if (args == null || args.Length != 3) return; 
     List<IModul> Module = args[0] as List<IModul>; 
     IComponentFactory Factory = args[1] as IComponentFactory; 
     // DXListBox lb = args[2] as DXListBox; 
     if (Module == null || Factory == null) return; 

     foreach (IModul Modul in Module) 
     { 
      Notification[] res = Modul.GetImportantNotifications(Factory); 
      if (res == null || res.Length == 0) continue; 

      foreach (Notification notif in res) 
      { 
       //-->EDITED 
       (sender as BackgroundWorker).ReportProgress(1, notif); 
       System.Threading.Thread.Sleep(100); 
       //this.ReceiveNotification(notif); 
       //<--EDITED 
      } 
     } 

    } 

    private void ReceiveNotification(Notification obj) 
    { 
     if (obj == null) return; 

     Dispatcher.BeginInvoke(new Action(() => 
     { 
      this.NotificationItems.Add(obj); 
      if (this.NotificationPanel.Width.Value == 0) 
      this.NotificationPanel.Width = new GridLength(NOTIFICATION_BAR_WIDTH); 
     })); 
    } 

입니다 메인 UI 스레드가 액세스 할 수 없습니다.

누구든지 저 문제를 해결할 수 있습니까?

답변

2

BackgroundWorker.WorkerSupportProgressTrue으로 설정하고 ProgressChangedEvent을 첨부하십시오. UI를 업데이트하려면 ReceiveNotification 메서드를 ReportProgress 호출로 바꿉니다. ProgressChangedEventHandler은 UI 스레드에 마샬링되므로 아무 것도 요청하지 않습니다.

+0

이전에도이 방법을 시도했지만 예외가 발생합니다. – DaKirsche

+0

수정 된 코드 게시 – Sievajet

+0

스 니펫을 추가했습니다. 나는 그것이 내가 수정 한 것 뿐이라고 생각한다. //-> EDITED 코드 블록으로 표시 – DaKirsche

0

나는 잘못된 발송자를 사용한다고 생각합니다. 귀하의 경우에는 배경 작업자의 디스패처를 사용합니다.

here에 따라 UI 디스패처의 레퍼 런스를 유지하십시오. Application.Current.Dispatcher로 액세스하면됩니다.

+0

에서 호출됩니다. Application.Current.Dispatcher도 그 예외를 발생시킵니다. – DaKirsche

+0

저는 (devExpress없이) 작은 프로젝트를 만들려고 노력했고 Sievajet의 솔루션이 저에게 효과적이었습니다. 어쩌면 당신의 예외는 당신의 backgroundworker ....에서 오지 않았다. sry 나는 다르게 돕는 방법을 모른다. –

0

ObservableCollection은 다른 스레드가 소유하지 않았지만 Notification 모델의 공용 BitmapImage ImageSource는 예외가 발생하지 않았으므로 예외가 throw되었습니다.

응용 프로그램이 Binding을 사용하여 BitmapImage를 읽으려고하면 오류가 발생합니다. 그래서 내 솔루션은 다음과 같습니다 :

private BitmapImage _ImageSource = null; 
    public object _originalImageSource= null; 
    public object ImageSource 
    { 
     get { return this._ImageSource; } 
     set 
     { 
      this._originalImageSource = value; 
      if (this._ImageSource != value) 
      { 
       this._ImageSource = value is BitmapImage ? (BitmapImage)value : 
        value is Uri ? 
        new BitmapImage(value as Uri) : 
        new BitmapImage(new Uri(value.ToString())); 
       this.RaisePropertyChanged("ImageSource"); 
      } 
     } 
    } 

을 OnProgressChanged 방법 내에서 내가 1 생성 : 새로운 BitmapImage에게

//-->EDITED 
    private void OnProgressChanged(object sender, ProgressChangedEventArgs e) 
    { 
     Notification t = (Notification)e.UserState; 
     Notification toAdd = new Notification(t.Parent, t.OriginalSource, t.Headline, t.Note, t._originalImageSource); 
     this.NotificationItems.Add(toAdd); 

     if (this.NotificationItems.Count > 0 && this.NotificationPanel.Width.Value == 0) 
      this.NotificationPanel.Width = new GridLength(NOTIFICATION_BAR_WIDTH); 
    } 
    //<--EDITED 

감사합니다 귀하의 지원을 많이 만들 수 _originalImageSource를 사용하여 통지의 1 부입니다.