Ich bin neu in Multithreading und WPF.Asynchrone Aktualisierung auf ObservableCollection-Elemente
Ich habe eine ObservableCollection<RSSFeed>
, bei App Start Elemente zu dieser Sammlung von UI-Thread hinzugefügt werden. Eigenschaften von RSSFeed sind an WPF ListView gebunden. Später möchte ich jeden RSSFeed asynchron aktualisieren. Also ich überlege, etwas wie RSSFeed.FetchAsync()
zu implementieren und PropertyChanged auf seinen aktualisierten Eigenschaften zu erhöhen.
Ich weiß, dass ObservableCollection keine Updates von anderen Threads als dem UI-Thread unterstützt, sondern NotSupportedException. Aber da ich die ObservableCollection selbst nicht manipuliere, sondern Eigenschaften für ihre Elemente aktualisiere, kann ich damit rechnen, dass dies funktioniert und die ListView-Elemente aktualisiert werden? Oder würde es wegen PropertyChanged sowieso eine Ausnahme auslösen?
Edit: Code
RSSFeed.cs
public class RSSFeed
{
public String Title { get; set; }
public String Summary { get; set; }
public String Uri { get; set; }
public String Encoding { get; set; }
public List<FeedItem> Posts { get; set; }
public bool FetchedSuccessfully { get; protected set; }
public RSSFeed()
{
Posts = new List<FeedItem>();
}
public RSSFeed(String uri)
{
Posts = new List<FeedItem>();
Uri = uri;
Fetch();
}
public void FetchAsync()
{
// call Fetch asynchronously
}
public void Fetch()
{
if (Uri != "")
{
try
{
MyWebClient client = new MyWebClient();
String str = client.DownloadString(Uri);
str = Regex.Replace(str, "<!--.*?-->", String.Empty, RegexOptions.Singleline);
FeedXmlReader reader = new FeedXmlReader();
RSSFeed feed = reader.Load(str, new Uri(Uri));
if (feed.Title != null)
Title = feed.Title;
if (feed.Encoding != null)
Encoding = feed.Encoding;
if (feed.Summary != null)
Summary = feed.Summary;
if (feed.Posts != null)
Posts = feed.Posts;
FetchedSuccessfully = true;
}
catch
{
FetchedSuccessfully = false;
}
}
}
UserProfile.cs
public class UserProfile : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public event CollectionChangeEventHandler CollectionChanged;
private ObservableCollection<RSSFeed> feeds;
public ObservableCollection<RSSFeed> Feeds
{
get { return feeds; }
set { feeds = value; OnPropertyChanged("Feeds"); }
}
public UserProfile()
{
feeds = new ObservableCollection<RSSFeed>();
}
protected void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
protected void OnCollectionChanged(RSSFeed feed)
{
CollectionChangeEventHandler handler = CollectionChanged;
if (handler != null)
{
handler(this, new CollectionChangeEventArgs(CollectionChangeAction.Add, feed));
}
}
}
MainWindow.xaml.cs
public partial class MainWindow : Window, INotifyPropertyChanged
{
// My ListView is bound to this
// ItemsSource="{Binding Posts}
public List<FeedItem> Posts
{
get
{
if (listBoxChannels.SelectedItem != null)
return ((RSSFeed)listBoxChannels.SelectedItem).Posts;
else
return null;
}
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
// here I load cached feeds
// called from UI thread
// now I want to update the feeds
// since network operations are involved,
// I need to do this asynchronously to prevent blocking the UI thread
}
}
Danke.
Danke beziehen. Ich habe eine verschachtelte Sammlung in meiner RSSFeed-Klasse. Wäre es eine gute Lösung, wenn RSSFeed.FetchAsync() bei seiner Beendigung ein Ereignis ausgelöst und eine neue (aktualisierte) RSSFeed-Instanz über EventArgs zurückgegeben hat? Später würde ich das entsprechende Element in der Sammlung vom UI-Thread aktualisieren. – Martin
Das ist eine mögliche Lösung. Wenn wir etwas Code sehen könnten, könnte ich Ihnen eine konkretere Antwort geben. –
@malymato normalerweise Async Methoden bieten einen Rückruf, wenn sie abgeschlossen sind. Welche Art von Implementierung verwenden Sie? –