2015-11-11 20 views
0

我正在构建一个WPF应用程序,该应用程序将填充来自各种新闻服务的过滤标题。每个标题触发一个事件,在控制台应用程序中我可以在控制台上显示该事件。我想在这里使用WPF,但是在这个尝试之前已经使用了bot。我的主窗口xaml如下所示。我最初的想法是有一个ObservableCollection在xaml的列表视图中填充列表项。如果这不是正确的方法,我会以更好的方式向专家征求意见,因为接收速度显示至关重要。如果我正在做的事情是正确的,那么我该如何将一个新的条目绑定到ObservableCollection来显示一个新的列表项?绑定事件到wpf列表实时更新

<StackPanel Orientation="Vertical" Margin="5,150 5 50" Name="HeadlinePanel"> 
     <TextBlock Text="Filtered Headlines From Monitoring List" 
     HorizontalAlignment="Left" Margin="0,0 5 5" Name="ScrollingHeadlineLabel" FontWeight="Bold" FontSize="14" Background="LightSkyBlue" /> 
     <ListBox>     
      <ListBoxItem> 
       <StackPanel Orientation="Horizontal"> 
        <Image Source="a property on the headline" /> 
        <TextBlock><Run Text="headline is from a website"/></TextBlock> 
       </StackPanel> 
      </ListBoxItem> 
      <ListBoxItem> 
       <StackPanel Orientation="Horizontal"> 
        <Image Source="a property on the headline" /> 
        <TextBlock><Run Text="headline is from TWTR"/></TextBlock> 
       </StackPanel> 
      </ListBoxItem> 
      <ListBoxItem> 
       <StackPanel Orientation="Horizontal"> 
        <Image Source="a property on the headline" /> 
        <TextBlock><Run Text="headline from a different website"/></TextBlock> 
       </StackPanel> 
      </ListBoxItem> 
      <ListBoxItem> 
       <StackPanel Orientation="Horizontal"> 
        <Image Source="a property on the headline" /> 
        <TextBlock><Run Text="text from a different tweet"/></TextBlock> 
       </StackPanel> 
      </ListBoxItem>    
     </ListBox> 
    </StackPanel> 

在filteredStream.Start(控制台应用程序流传输开始时(如下所示代码)),但处理程序需要事先注册。在控制台应用程序中,我可以写入控制台(注释掉),但是在事件触发时,我将标题对象添加到集合中。我的问题是如何将它绑定到我的xaml列表项。我将从mainwindow方法启动流?或者我创建的一些方法在那里运行?

var config = new TwitterOAuthConfig() 
     { 
      ConsumerKey = customerKey, 
      ConsumerSecret = customerSecret, 
      AccessToken = accessToken, 
      AccessTokenSecret = accessTokenSecret, 
      GeoOnly = false, 
      KeywordsToMonitor = keywords, 
      UsersToFollow = followers 
     }; 
     var filteredStream = new TwitterClient(config); 
     var headlineCollection = new ObservableCollection<Headline>(); 
     // subscribe to the event handler 
     filteredStream.HeadlineReceivedEvent += 
      (sender, arguments) => headlineCollection.Add(arguments.Headline); 
       //Console.WriteLine("ID: {0} said {1}", arguments.Headline.Username, arguments.Headline.HeadlineText); 


     filteredStream.ExceptionReceived += (sender, exception) => Console.WriteLine(exception.HeadlineException.ResponseMessage); 

     filteredStream.Start(); 

这是我原来的HeadlineViewModel

public class HeadlineViewModel : ObservableItem 
{ 
    private string _headlineText; 

    public string Source { get; set; } 
    public string Username { get; set; } 

    public string Text 
    { 
     get { return _headlineText; } 
     set 
     { 
      _headlineText = value; 
      RaisePropertyChangedEvent("HeadlineText"); 
     } 
    } 
    public List<string> UrlsParsedFromText { get; set; } 
    public string TimeStamp { get; set; } 
} 

我也更新到以下几点:

public class HeadlineViewModel 
{ 
    public class HeadlineDisplayItems: ObservableItem 
    { 
     private string _headlineText; 
     public string HeadlineIconPath { get; set; } 
     public string TimeStamp { get; set; } 
     public string Username { get; set; } 
     public string Text 
     { 
      get { return _headlineText; } 
      set 
      { 
       _headlineText = value; 
       RaisePropertyChangedEvent("HeadlineText"); 
      } 
     } 
    } 
    public List<string> UrlsParsedFromText { get; set; } 
    public ObservableCollection<HeadlineDisplayItems> HeadlineCollection { get; set; } 
} 

回答

4

我不知道你的架构,但WPF大多与使用他们称之为MVVM(Model-View-ViewModel),你有View(你已经发布了代码),ViewModel(我相信你没有)和Model(你使用的Headline)。 ViewModel的目标是简化视图的生命并提供需要显示的所有信息和操作。例如,您应该为您正在构建的整个视图创建一个ViewModel,比方说“HeadlinePanelViewModel”(我不推荐在该名称中使用面板,因为使用ViewModel的想法是将控件或技术抽象为用过的)。 HeadlinePanelViewModel需要使标题可用,所以它必须有一个ViewModel集合,代表与标题(图标,标题,链接,...)有关的所有信息。最后,你有一个包含ObservableCollection的HeadlinePanelViewModel。将其设置为View的DataContext,并且您必须准备好显示您的信息。

现在来实际加载信息的一部分。再一次,我不知道你的架构。但是非常简单,您可以实例化HeadlinePanelViewModel中的filteredStream,并且每次触发HeadlineReceivedEvent时,都会创建一个HeadlineViewModel并将其添加到您的集合中。

“完成” 基于代码在你的答案代码:

视图模型:

public class HeadlineViewModel 
{ 
    public HeadlineViewModel() 
    { 
     // This is here only for simplicity. Put elsewhere 
     var config = new TwitterOAuthConfig() 
     { 
      ConsumerKey = customerKey, 
      ConsumerSecret = customerSecret, 
      AccessToken = accessToken, 
      AccessTokenSecret = accessTokenSecret, 
      GeoOnly = false, 
      KeywordsToMonitor = keywords, 
      UsersToFollow = followers 
     }; 
     var filteredStream = new TwitterClient(config); 
     HeadlineCollection = new ObservableCollection<HeadlineDisplayItems>(); 

     // subscribe to the event handler 
     filteredStream.HeadlineReceivedEvent += 
      (sender, arguments) =>  HeadlineCollection.Add(ConvertToViewModel(arguments.Headline)); 
       //Console.WriteLine("ID: {0} said {1}",  arguments.Headline.Username, arguments.Headline.HeadlineText); 


     filteredStream.ExceptionReceived += (sender, exception) =>  Console.WriteLine(exception.HeadlineException.ResponseMessage); 

     filteredStream.Start(); 
    } 

    private HeadlineDisplayItems ConvertToViewModel(Headline headline) 
    { 
     // Conversion code here 
    } 

    public class HeadlineDisplayItems: ObservableItem 
    { 
     private string _headlineText; 
     public string HeadlineIconPath { get; set; } 
     public string TimeStamp { get; set; } 
     public string Username { get; set; } 
     public string Text 
     { 
      get { return _headlineText; } 
      set 
      { 
       _headlineText = value; 
       RaisePropertyChangedEvent("HeadlineText"); 
      } 
     } 
    } 
    public List<string> UrlsParsedFromText { get; set; } 
    public ObservableCollection<HeadlineDisplayItems> HeadlineCollection {   get; set; } 
} 

的观点:

<StackPanel Orientation="Vertical" Margin="5,150 5 50" Name="HeadlinePanel"> 
    <TextBlock Text="Filtered Headlines From Monitoring List" 
    HorizontalAlignment="Left" Margin="0,0 5 5" Name="ScrollingHeadlineLabel" FontWeight="Bold" FontSize="14" Background="LightSkyBlue" /> 
    <ListBox ItemsSource="{Binding HeadlineCollection}">  
     <ListBox.ItemTemplate> 
      <DataTemplate> 
       <StackPanel Orientation="Horizontal"> 
        <Image Source="{Binding HeadlineIconPath}" /> 
        <TextBlock><Run Text="{Binding Text}"/></TextBlock> 
       </StackPanel> 
      </DataTemplate> 
     </ListBox.ItemTemplate>      
    </ListBox> 
</StackPanel> 

的代码所缺少就是你做的this.DataContext = new HeadlineViewModel();到风景。

编辑:如果您尝试从不同于视图线程的线程更新observableCollection,您可能会遇到一些跨线程操作问题。解决方法是使用此link中的解决方案,但我认为这不是最好的方法。

+0

我有一个HeadlineViewModel,其中香港专业教育学院现在包括在后。所以viewmodel类需要标题的ObservableCollection?所以它可以绑定必要的属性? – dinotom

+0

是的。而已。但是您需要注意的是,您必须为每个标题创建一个ViewModel,并为具有ObservableCollection的“Container”创建一个。然后通过属性ItemsSource将ListBox映射到“Container”集合。 Editted答案 –

+0

我tihnk我拿到哪里youre去,虽然这是我的第一个WPF应用程序。我重做了Veiwmodel并将其张贴在原始帖子中。在PropertyChanged事件不知道应该只为标题,因为所有的displayitems每个标题 – dinotom

0

创建您的ObservableCollection为可以在XAML中引用的一个属性。可以直接在您的MainWindow-Class中创建它,或者将您的集合实例化为StaticResource。

绑定你的ObservableCollection为的ItemsSource到您的列表框

<ListBox ItemsSource="{Binding Path=HeadlineCollection}"></ListBox> 

和使用的DataTemplate将数据绑定到它

<ListBox.ItemTemplate> 
    <DataTemplate> 
     <StackPanel Orientation="Horizontal"> 
      <Image ... /> 
      <TextBlock Text="{Binding Path=Text}" /> 
     </StackPanel> 
    </DataTemplate> 
</ListBox.ItemTemplate> 

为标题,创建一个数据类管理你需要什么显示(标题,图标等)。事情是这样的:

class Headline 
{ 
    bool isTwitter {get; set;} 
    string Text {get; set;} 
} 

然后在你的客户对象,你可以简单地通过调用Add添加一个新的对象到的ObservableCollection() - 方法和应用程序将自动生成新的对象。

您可以在主UI线程上启动查询客户端,但对于响应式UI,您应让查询例程在其自己的线程中运行(例如通过使用BackgroundWorker),以便UI不会混乱。