知乎周源微信_每周源代码40-TweetSharp和Tweet Sandwich简介

知乎周源微信

知乎周源微信

I just was at Quiznos hanging out with @QuiznosNick. He's a former Technology Executive who bought a Quiznos Franchise for his retirement. He's a major geek, and while chatting he wonder how he could take orders over Twitter. I wanted to see how easy it'd be to write as a real app. I could use PowerShell or Curl, but it's all in good fun, right?

我只是在Quiznos@QuiznosNick闲逛。 他曾任技术主管,为退休退休后购买了Quiznos连锁店。 他是一个主要的怪胎,在聊天的同时,他想知道如何通过Twitter接受订单。 我想看看编写一个真正的应用程序有多么容易。 我可以使用PowerShell或Curl,但这很有趣,对吗?

For no reason at all, here is the thought process and code as I write it. I shall call it Tweet Sandwich.

毫无疑问,这是我编写时的思考过程和代码。 我称它为Tweet Sandwich

第0步-变得漂亮 (Step 0 - Make it Pretty)

Ok, WPF will do fine. Of course, before I do any work or planning or anything, I'll need an icon. ;) Search the web, find a nice, free non-commercial icon of a sandwich. Make it transparent with Paint.NET, make a 32x32 and a 16x16 at 24 bit color and paste into Visual Studio. Name it app.ico. Waste of time, perhaps, but it motivates me personally to do the pretty stuff first.

好的,WPF会很好的。 当然,在执行任何工作或计划之前,我需要一个图标。 ;)搜索网络,找到一个漂亮的,免费的三明治非商业图标。 使用Paint.NET使其透明,以32位色制作32x32和16x16,然后粘贴到Visual Studio中。 将其命名为app.ico。 也许浪费时间,但这却促使我个人先做些漂亮的东西

Take the Window1, call it Main and setup some controls. Grab a Free Twitter Bird PNG and a picture of a Sandwich, more Paint.NET and I've got a Main Form.

以Window1为例,将其命名为Main并设置一些控件。 拿一个免费的Twitter Bird PNG和一个三明治图片,更多的Paint.NET,我有一个Main Form。

I tell you, being able to use Paint.NET and the clipboard, and a good understanding of how transparency works in Windows is an important skill to have. I'm no artist, but I can hack together a picture of a bird and a sandwich with the best of them.

我告诉你,能够使用Paint.NET和剪贴板,并且很好地了解Windows中透明度的工作原理是一项重要技能。 我不是艺术家,但我可以将其中最好的东西与鸟和三明治的照片拼在一起。

Tweet Sandwich

我需要保存什么设置 (What Settings Do I Need to Save)

OK. Now, I put the Settings in the Properties dialog for the project.

好。 现在,我将“设置”放置在项目的“属性”对话框中。

Then I'll put in some small databinding code to make the text boxes in the form fill with the data from the settings.

然后,我将输入一些小的数据绑定代码,以使表单中的文本框充满设置中的数据。

<Window x:Class="TakeOrdersOverTwitterWPF.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Tweet Sandwich" Height="459" Width="454"
xmlns:local="clr-namespace:TakeOrdersOverTwitterWPF.Properties">
<Window.Resources>
<local:Settings x:Key="settings" />
</Window.Resources>
<Grid>
<GroupBox Header="Settings" Name="groupBox1">
<Grid DataContext="{StaticResource settings}" >
<TextBox Name="twitterUserName" Text="{Binding Path=Default.TwitterUserName}"/>
...etc...

The keys are the Settings Resource that maps to the Properties (Settings) for the app. Then the Binding to the TextBox. Then we save them when the app closes with Settings.Default.Save();

键是设置资源,该资源映射到应用程序的属性(设置)。 然后绑定到TextBox。 然后,在应用程序关闭时使用Settings.Default.Save();保存它们。

我多久检查一次订单? (How Often Will I Check For Orders?)

Now, I'll setup a Timer to check for orders every five minutes:

现在,我将设置一个计时器,以每五分钟检查一次订单:

DispatcherTimer twitterTimer = null;

private void Window_Loaded(object sender, RoutedEventArgs e)
{
this.twitterTimer = new DispatcherTimer(new TimeSpan(0, 5, 0), DispatcherPriority.Normal, CheckForOrders, this.Dispatcher);
}

private void CheckForOrders(object sender, EventArgs e)
{
...
}

Gotta GET the Twitter Feed now...check the Twitter API. Do I want RSS or an API? The Twitter API has a REST model, and I need to see the replies to QuiznosNick, so I'll need to add some options to my application. I'll need to authenticate as QuiznosNick and ask for his replies list. I need his username and password. I'll probably want to call this API, which will let me see replies since some time. Looks like I can use the Date, or a status id, which is a big number that keeps getting bigger.

立即获取Twitter Feed ...检查Twitter API。 我要RSS还是API? Twitter API具有REST模型,我需要查看对QuiznosNick的答复,因此需要在应用程序中添加一些选项。 我需要验证为QuiznosNick并要求他的答复列表。 我需要他的用户名和密码。 我可能要调用此API,从一段时间以来,我将可以看到答复。 看起来我可以使用日期或状态ID,这是一个很大的数字,并且越来越大。

状态/回复 (statuses/replies)

Returns the 20 most recent @replies (status containing @username) for the authenticating user.

返回身份验证用户的最近20个@replies(包含@username的状态)。

URL: http://twitter.com/statuses/replies.format

网址: http //twitter.com/statuses/replies.format

Formats: xml, json, rss, atom

格式: xml,json,rss,atom

Method(s): GET

方法: GET

Parameters:

参数:

  • since_id.  Optional.  Returns only statuses with an ID greater than (that is, more recent than) the specified ID.  Ex: http://twitter.com/statuses/replies.xml?since_id=12345

    since_id。 可选的。 仅返回ID大于(即比指定ID更新)ID的状态。 例如:http://twitter.com/statuses/replies.xml?since_id = 12345

  • max_id. Optional.  Returns only statuses with an ID less than (that is, older than) the specified ID.  Ex: http://twitter.com/statuses/replies.xml?max_id=54321

    max_id。 可选的。 仅返回ID小于(即早于)指定ID的状态。 例如:http://twitter.com/statuses/replies.xml?max_id = 54321

  • since.  Optional.  Narrows the returned results to just those replies created after the specified HTTP-formatted date, up to 24 hours old.  The same behavior is available by setting an If-Modified-Since header in your HTTP request.  Ex: http://twitter.com/statuses/replies.xml?since=Tue%2C+27+Mar+2007+22%3A55%3A48+GMT

    以来。 可选的。 将返回的结果缩小为仅在指定的HTTP格式的日期(最多24小时)之后创建的答复。 通过在HTTP请求中设置If-Modified-Since标头,可以实现相同的行为。 例如:http://twitter.com/statuses/replies.xml?since = Tue%2C + 27 + Mar + 2007 + 22%3A55%3A48 + GMT

  • page.  Optional. Retrieves the 20 next most recent replies.  Ex:http://twitter.com/statuses/replies.xml?page=3

    页。 可选的。 检索最近的20条回复。 例如:http://twitter.com/statuses/replies.xml?page = 3

Returns: list of status elements

返回:状态元素列表

我将如何称呼Twitter?(How Will I Call Twitter?)

I could just make a call to Twitter using WebClient and Basic Auth, but since I'll only be paid in Sandwiches, I'll use TweetSharp. It's a smidge overkill for one API call, but it'll let me figure out if TweetSharp is fun or not. I could have also used LinqToTwitter, so try them both out and make your own judgment.

我只可以使用WebClient和Basic Auth致电Twitter,但是由于只用三明治付款,因此我将使用TweetSharp 。 对于一个API调用来说,这是个小菜一碟,但它会让我弄清楚TweetSharp是否有趣。 我也可以使用LinqToTwitter ,因此请尝试一下并做出自己的判断。

Here's how you would get the replies for an authenticated user using TweetSharp. I might switch this over to DirectMessages, which is less fun, but more secure, if things become a problem.

这是您使用TweetSharp获得身份验证用户答复的方式。 如果出现问题,我可能会将其切换到DirectMessages,虽然乐趣不大,但更加安全。

TwitterClientInfo info = new TwitterClientInfo() { ClientName = "TweetSandwich", ClientVersion = "1.0" };
var twitter = FluentTwitter.CreateRequest(info)
.AuthenticateAs(twitterUserName.Text, Password.Password)
.Statuses()
.Replies().AsXml();

string result = twitter.Request();

At this point, "result" has the XML I want in it.

在这一点上,“结果”具有我想要的XML。

Text Visualizer (3)

The general structure of the nodes I'll need is:

我需要的节点的一般结构是:

statuses
status
created_at
id
text
user
id
name
location

I want "all status's greater than the lastid, and from those, extract the text, user id, name and location, sorting by created_at descending." In LINQ to XML, that might be:

我希望“所有状态都大于lastid,然后从中提取文本,用户ID,名称和位置,并按created_at降序排序。” 在LINQ to XML中,可能是:

XDocument doc = XDocument.Parse(result);
var statuses = (from d in doc.Descendants("status")
where int.Parse(d.Element("id").Value) > lastOrderNum
where d.Element("text").Value.Contains(orderString.Text)
select new
{
tweetid = int.Parse(d.Element("id").Value),
name = d.Element("user").Element("name").Value,
location = d.Element("user").Element("location").Value,
tweet = d.Element("text").Value,
dateTime = d.Element("created_at").Value.ParseTwitterDateTime()
}).OrderByDescending(t => t.dateTime);

However, TweetSharp has an object model that will deserialize JSON so I don't even need to do this. I can use their objects and still use LINQ, which makes this even cleaner. I can avoid all the strings and the dataType conversions as it's all hidden. Not to mention the hacky ParseTwitterDateTime extension method I got from Wally that he got from Tim Heuer.

但是,TweetSharp具有将反序列化JSON的对象模型,因此我什至不需要这样做。 我可以使用它们的对象,但仍然使用LINQ,这使它更加干净。 我可以避免所有字符串和dataType转换,因为它们都是隐藏的。 更不用说我从Wally那里得到的骇人的ParseTwitterDateTime扩展方法,而他是从Tim Heuer得到的。

TwitterClientInfo info = new TwitterClientInfo() { ClientName = "TweetSandwich", ClientVersion = "1.0" };
var replies = FluentTwitter.CreateRequest(info)
.AuthenticateAs(twitterUserName.Text, Password.Password)
.Statuses()
.Replies()
.Since(lastOrderNum)
.AsJson();

IEnumerable<TwitterStatus> statuses = replies.Request().AsStatuses();

var statusesFiltered = from d in statuses
where d.Id > lastOrderNum
where d.Text.IndexOf(orderString.Text, StringComparison.OrdinalIgnoreCase) != -1
orderby d.CreatedDate descending
select d;

打印订单 (Printing Orders)

Now I just need to print them out. Every Quiznos has the same computer and the same printer that they got from the corporate office. I don't care though, I'll just print out an order on whatever default printer they have.

现在我只需要打印出来。 每个Quiznos都有从公司办公室获得的相同的计算机和相同的打印机。 我不在乎,我只会在他们拥有的任何默认打印机上打印出订单。

Printing is hard, and I only allocated a few hours to do this, but Printing a "Visual Object" in WPF is easy.

打印很困难,我只花了几个小时去做,但是在WPF中打印“可视对象”很容易。

PrintDialog dlg = new PrintDialog();
dlg.PrintVisual(orderCanvas, "Whatever");

I could just make a Canvas with a bunch of controls to represent the last tweeted order, and print that. 

我可以制作一个带有一堆控件的Canvas,以表示最后的推特订单,然后打印出来。

Tweet Sandwich (2)

However, the last time I did anything with Printing it was VB6 and it was hard. How hard it is now to make a real document today in WPF?  I figured I'd find out by trying.

但是,上一次我对Printing做任何事情时,都是VB6,这很困难。 现在在WPF中制作真实文档有多难? 我想我可以尝试一下。

I thought I'd use these FlowDocuments and make one that can show a Tweet. I went File | Add New Item | FlowDocument and call it SandwichOrder.xaml.

我以为我会使用这些FlowDocuments并制作一个可以显示Tweet的文档。 我去了File | 添加新商品| FlowDocument并将其称为SandwichOrder.xaml。

I made a FlowDocument as a Resource that looked like this I could do it manually, do it in Word and save it, or use an HTML to XAML converter as others have.

我制作了一个FlowDocument作为资源,看起来像这样,我可以手动执行,在Word中执行并保存它,或者像其他人一样使用HTML到XAML转换器

<FlowDocument xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
FontSize="24" FontFamily="Georgia">
<Paragraph>
<TextBlock Text="{Binding Path=User.ScreenName}"/> in
<TextBlock Text="{Binding Path=User.Location}"/>
says on <TextBlock Text="{Binding Path=CreatedDate}"/>:
</Paragraph>
<Paragraph FontFamily="Arial">
<TextBlock Text="{Binding Path=Text}"/>
</Paragraph>
</FlowDocument>

I figured I want to DataBind to it, using the TweetSharp TwitterStatus object. Dynamically creating a document from a resource template, binding to it and printing it seems like a core scenario. Googling around, though found a lot of people having trouble with a few basic things that I was hitting into also.

我想使用TweetSharp TwitterStatus对象将它绑定到DataBind。 从资源模板动态创建文档,绑定到文档并打印它似乎是一个核心方案。 到处搜寻,尽管发现很多人在我也涉及的一些基本问题上遇到了麻烦。

NOTE: I might be doing this wrong, so I need to ask a WPF expert at Microsoft to see if I'm wrong about some things I think are too hard.

注意:我可能做错了,所以我需要请Microsoft的WPF专家查看我是否对某些我认为过分困难的事情有错。

动态创建FlowDocument,数据绑定并打印 (Dynamically Creating a FlowDocument, Data Binding and Printing It)

First, I wrote this:

首先,我这样写:

private void PrintOrder(TwitterStatus t)
{
var streamInfo = Application.GetResourceStream(new Uri("resources/SandwichOrder.xaml",UriKind.Relative));
FlowDocument doc = XamlReader.Load(streamInfo.Stream) as FlowDocument;
doc.DataContext = t;
PrintDialog dlg = new PrintDialog();
dlg.PrintDocument(((IDocumentPaginatorSource)doc).DocumentPaginator,"Tweeted Sandwich Order");
}

I felt OK about it, but not awesome. First, it was too hard to get my FlowDocument out of the Embedded Resource. I thought I could do something like App.Resources["SandwichOrder.xaml"]. I also wanted to do lines one and two in all one like like: var doc = FlowDocument.FromResource("SandwichOrder.xaml").

我对此感到满意,但并不出色。 首先,将我的FlowDocument移出Embedded Resource太困难了。 我以为我可以做类似App.Resources [“ SandwichOrder.xaml”]的事情。 我还想像这样一起来做第一行和第二行:var doc = FlowDocument.FromResource(“ SandwichOrder.xaml”)。

Finally, the weird interface cast in the PrintDocument line was totally counter intuitive. Seemed like PrintDocument should have an overload that takes a FlowDocument.

最后,在PrintDocument行中转换的怪异界面完全是反直观的。 看起来像PrintDocument应该有一个带FlowDocument的重载。

Then I tried to print. When I printed, the data binding didn't happen. I just got the basic text. More Googling showed there's a threading issue and the binding happens on another thread?

然后我尝试打印。 当我打印时,没有发生数据绑定。 我刚得到基本的文字。 更多Google搜索显示存在线程问题,并且绑定发生在另一个线程上吗?

Now I had to add what appears to be the WPF equivalent of "DoEvents" - that big dispatcher call that releases the thread to do pending stuff. This CAN'T be right. I MUST be doing something wrong, so I'll update this post as I learn.

现在,我必须添加看起来像WPF中“ DoEvents”等效的东西-那个大的调度程序调用,释放线程以执行挂起的工作。 这不可能是对的。 我必须做错了什么,所以我会在学习时更新此帖子。

private void PrintOrder(TwitterStatus t)
{
var streamInfo = Application.GetResourceStream(new Uri("resources/SandwichOrder.xaml",UriKind.Relative));
FlowDocument doc = XamlReader.Load(streamInfo.Stream) as FlowDocument;
doc.DataContext = t;
Dispatcher.CurrentDispatcher.Invoke(DispatcherPriority.SystemIdle, new DispatcherOperationCallback(delegate { return null; }), null);
PrintDialog dlg = new PrintDialog();
dlg.PrintDocument(((IDocumentPaginatorSource)doc).DocumentPaginator,"Tweeted Sandwich Order");
}

After this printing and databinding worked, except the TextBlocks I was using didn't wrap, so the orders got clipped. I tried using a <Run> but they don't support DataBinding. I ended up having to add a BindableRun class as more Googling showed more confusion. Folks have created Bindable Tables also, it seems and this BindableRun pattern seems common. I need to check on why this isn't built in.

在完成此打印和数据绑定工作之后,除了我使用的TextBlocks没有包装外,所以订单被削减了。 我尝试使用<Run>,但它们不支持DataBinding。 我最终不得不添加BindableRun类,因为更多谷歌搜索显示了更多的混乱。 人们似乎也创建了Bindable Tables,并且这种BindableRun模式似乎很常见。 我需要检查为什么它不是内置的。

Now my FlowDocument looks like this:

现在我的FlowDocument看起来像这样:

<FlowDocument xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:bt="clr-namespace:TakeOrdersOverTwitterWPF.BindableText;assembly=TakeOrdersOverTwitterWPF"
FontSize="24" FontFamily="Arial">
<Paragraph FontSize="48">Twitter Order</Paragraph>
<Paragraph>
<bt:BindableRun BoundText="{Binding Path=User.Name}" />
(<bt:BindableRun BoundText="{Binding Path=User.ScreenName}" />) in
<bt:BindableRun BoundText="{Binding Path=User.Location}" /> says on
<bt:BindableRun BoundText="{Binding Path=CreatedDate}" /> :
</Paragraph>
<Paragraph FontFamily="Arial">
<bt:BindableRun BoundText="{Binding Text}" />
</Paragraph>
</FlowDocument>

And it prints exactly as it should. So, for printing, to recap, I:

并且它完全按照应有的方式打印。 因此,对于打印来说,我:

  • Made a Template FlowDocument and embedded it as a Resource

    制作了一个模板FlowDocument并将其作为资源嵌入

    • Had to use a BindableRun

      必须使用BindableRun
  • Pulled it out of the resuorce, DataBinding, did a weird dispatcher hack, printed it.

    将其从数据绑定中取出来,进行了奇怪的调度员黑客攻击,将其打印出来。

Too much Googling on that one. It wasn't nearly as obvious to print as it was to do the Graphical UI.

在那个上搜索太多。 它的打印效果不如图形用户界面明显。

This app, modified, could be used to waste dead trees by printing out tweets that contain words. Mark Nijhof is using TweetSharp to tweet what he blogs. It could also make the computer beep when a sandwich order arrives. Oh! There's an idea!

该应用程序经过修改,可以通过打印包含单词的推文来浪费死树。 马克·尼霍夫( Mark Nijhof)正在使用TweetSharp来发布他的博客内容。 当三明治命令到达时,它也可能使计算机发出哔哔声。 哦! 有个主意!

Tomorrow at lunch, I'll present Tweet Sandwich, the first automated Twitter-based Sandwich Ordering System to @QuiznosNick and hope I earned a free sandwich or ten. ;)

明天午餐时间,我将向@QuiznosNick展示Tweet Sandwich,这是第一个基于Twitter的自动三明治订购系统,希望我能免费获得一到十个三明治。 ;)

Download the Source from SkyDrive

从SkyDrive下载源

Please offer feedback, as I'm sure there's lots of ways this can be cleaner. For example, a bound listbox of Replies/Orders (starts to look like a real Twitter Client, then.)

请提供反馈意见,因为我敢肯定有很多方法可以使它更清洁。 例如,一个绑定的回复/订单列表框(然后开始看起来像一个真正的Twitter客户端。)

翻译自: https://www.hanselman.com/blog/the-weekly-source-code-40-tweetsharp-and-introducing-tweet-sandwich

知乎周源微信

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值