将事件绑定到wpf列表以进行实时更新
本文关键字:实时更新 列表 wpf 事件 绑定 | 更新日期: 2023-09-27 18:21:26
我正在构建一个WPF应用程序,它将填充来自各种新闻服务的过滤标题。每个标题都会触发一个事件,我可以在控制台应用程序中显示该事件。我想在这里使用WPF,但在此之前已经有机器人使用过了。我的主窗口xaml如下所示。我最初的想法是让ObservableCollection在xaml的列表视图中填充列表项。如果这不是正确的方法,我愿意接受专家对更好方式的意见,因为显示收据的速度至关重要。如果我所做的是正确的,那么我如何将ObservableCollection的新条目绑定到要显示的新列表项?
<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列表项。我将从主窗口方法启动流?或者我创建的某种方法在其中运行?
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();
这是我的原始标题ViewModel
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; }
}
我不知道你的体系结构,但wpf主要用于他们所称的MVVM(模型-视图-视图-模型),其中你有你的视图(你已经发布了代码)、ViewModel(我相信你没有)和模型(这就是你正在使用的标题)。ViewModel的目标是简化视图的使用寿命,并提供显示所需的所有信息和操作。
例如,您应该为正在构建的整个视图创建一个ViewModel,比如"HeadlinePanelViewModel"(我不建议使用名称中的面板,因为使用ViewModel的想法是抽象正在使用的控件或技术)。HeadlinePanelViewModel需要使标题可用,因此它必须有一个ViewModel集合,表示与标题相关的所有信息(图标、标题、链接…)。最后,您有一个包含ObservableCollection的HeadlinePanel ViewModel。将其设置为视图的DataContext,您必须准备好显示您的信息。
现在是实际加载信息的部分。再说一遍,我不知道你的架构。但简单来说,您可以在HeadlinePanelViewModel中实例化filteredStream,每次触发HeadlineReceivedEvent时,您都会创建一个与之对应的HeadlineViewModel并添加到您的集合中。
基于您答案中的代码的"完整"代码:
ViewModel:
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,那么跨线程操作可能会遇到一些问题。解决方法是在这个链接中使用解决方案,但我认为这不是最好的方法。
将ObservableCollection创建为可以在XAML中引用的属性。直接在MainWindow类中创建它,或者将集合实例化为StaticResource。
将您的ObservableCollection作为ItemsSource绑定到您的Listbox
<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就不会被它弄得一团糟