Monday, July 20, 2009

B&N Draconian eBooks

I want to get on the eBook train. I want to get an eBook reader, and have digital copies of all the books that I read that I can carry with me every where I go. I want this because I read. A lot.

Likewise, I spend a good amount on books every year. It’s a category in my family budget. That’s how serious I am about the things.

So, imagine my joy at hearing about another big-name book seller that is creating an eBook-store.

Especially after the idiocy earlier this week of Amazon stealing files from users of its Kindle service who purchased an item in good faith from their store.

So, of course the first thing I do is head over to Barnes & Noble’s new ebooks site—and proceeded to extinguish the joy.

First off, there is no hardware device there at all. But, I’m actually fine with that.

Or I was until I realized that they’re pushing their proprietary software in order to read the eBooks which you “purchase” from their site.

According to their FAQ, these books are in PDB or PRC formats—a format which have traditionally been used in PALM devices (and more recently the Protein Database format). So, they’re already starting with their own file format attached to their own software.

Software which is only available for a handful of devices, excluding the Linux OS.

All this said, I LIKE the reader software. It’s intuitive and easy to use.

B&N eBook ReaderThere are even themes, so that you can easily change the paper to something that works well with your eyes.

But ultimately, that doesn’t help me.

If I am going to use eBooks I want them easily portable. Otherwise, I’ll continue to purchase actual books.

Let’s be clear here. I don’t want a BlackBerry, and have no intention of getting an iPhone/iTouch (at least until they’re undocked from the AT&T service). Therefore my option to read B&N eBooks is to cart around my desktop and monitors?

Because you cannot use it on an eBook reader such as the Cool-er.

Or at least that’s the impression one receives. I’ve not taken the trouble to attempt to convert those PDB files that come with the reader to find out though.

But on the subject of that, I have to say, that’s the most disingenuous free give-away that I’ve seen in a long time.

Free Offer from B&N

If you look closely, there are a possible of 6 books that Barnes
& Nobles will give you FREE with their reader.

There’s two bundled with the software and then an additional four for signing up for an account.

That sixth on the list I found extremely humorous considering the fact that I don’t own a device that I can mobily carry these files (or their bloat-ware) on.

But the other five? Those I laughed aloud over.

They are as follows:

  • The Last of the Mohicans
  • Sense and Sensibility
  • Dracula
  • Pride and Prejudice
  • Little Women

As I was reading that list, it struck me. Every book on that list has been around for over a century.

So, I headed over to Project Gutenberg and took a minute to look up, and find every one of them.

SpaceBalls - Perriair Freebies are easy to give away when they cost the company nothing. It’s the silliest thing I’ve read about since that canned air thing from over in Japan.

How hard is it for these companies to understand this?

I don’t want DRM. I don’t want to use your software.

If I want to write my own software to read the eBooks I purchase, I want to be able to do that without having to break the DRM, and make myself a criminal (and is that not a fun thought? Creating a piece of software to access files you paid for can be a felony).

Otherwise, what’s the use.

Why should I bother with their bookstore and their DRM?

After all, I can easily make myself a Full Auto Book Scanner and media-shift hardcopies to PDF (or using OCR, ePUB) formats.

Barnes & Noble’s, and Amazon’s and anyone else who is trying to get me to purchase eBooks, goal should be simple. To get me to think it not worth the time and effort to media-shift the books I purchase into digital media.

Ultimately that means that I need quick and easy access to the files I purchase, in an open format that I can move between devices.

And they need to be priced reasonably for what amounts to an electronic file.

After all, I switch back and forth between my iPod and my Zune for music/video consumption. I refuse to be tied down to a single device, and I refuse to allow my media library to be treated the same way.

The lesson here: I’ll buy analog and convert before I buy DRM.


Edit 7/22/09: After a few emails back and forth with the Barnes & Nobles support, I got them to verify that you are only able to use their eBooks with their software

Another fine example of a company that hates (and is actively hostile towards) its customer base.

Sunday, July 19, 2009

WPF Datagrid Items Refresh, part II


Back in January, I posted a short entry about refreshing the datagrid in WPF. Which has gotten a number of questions regarding it. Well, one from Mykhaylo Khodorev made me go look some more into it. Apparently, the use of a generic IEnumerable object was failing this little trick. First, some information I've learned since then.

If the collection you're using to assign to the ItemSource attribute of your datagrid is an ObservableCollection (or inherits from it) any changes to the collection are automatically propagated to the grid. Secondly, the process described works while using a Generic List collection.

But, just so that we're clear on exactly what's happening, I'm placing my code that I used here. So here's the XAML:



<Window x:Class="Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:wpftk="http://schemas.microsoft.com/wpf/2008/toolkit"
Title="Window1" Height="300" Width="300" Initialized="Window_Initialized" >
<DockPanel>
<StackPanel Orientation="Horizontal" DockPanel.Dock="Top">
<TextBox Name="txtAddItem" Width="50" MaxWidth="50" />
<Button Name="btnAddItem" Content="Add Item" Click="btnAddItem_Click"
HorizontalAlignment="Right" />
<Button Name="btnRefresh" Content="Refresh" HorizontalAlignment="Right" Click="btnRefresh_Click" />
</StackPanel>
<Grid>
<Grid.ColumnDefinitions >
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<wpftk:DataGrid Name="xGridObservableCollection" Grid.Column="0" AutoGenerateColumns="False">
<wpftk:DataGrid.Columns>
<wpftk:DataGridTextColumn Header="Item" Binding="{Binding Item}" IsReadOnly="True" />
</wpftk:DataGrid.Columns>
</wpftk:DataGrid>

<wpftk:DataGrid Name="xGridList" Grid.Column="1" AutoGenerateColumns="False">
<wpftk:DataGrid.Columns>
<wpftk:DataGridTextColumn Header="Item" Binding="{Binding Item}" IsReadOnly="True" />
</wpftk:DataGrid.Columns>
</wpftk:DataGrid>
</Grid>
</DockPanel>
</Window>

And here's the VB.Net CodeBehind for that XAML:


Imports System.Collections.ObjectModel

Class Window1

Private Sub btnAddItem_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
Dim x As String = Me.txtAddItem.Text
Dim b As New ItemClass(x)
_itemList.Add(b)
_items.Add(b)
End Sub

Private _items As New Items
Private _itemList As New List(Of ItemClass)

Private Sub Window_Initialized(ByVal sender As System.Object, ByVal e As System.EventArgs)

Dim x As Integer = 0
Do While x < 5
Dim i As New ItemClass("Auto Gen Item # " & x)
i.Value = x
_itemList.Add(i)
_items.Add(i)

x += 1
Loop
Me.xGridList.ItemsSource = _itemList
Me.xGridObservableCollection.ItemsSource = _items
End Sub

Private Sub btnRefresh_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
Me.xGridList.Items.Refresh()
End Sub
End Class

Public Class ItemClass
Implements System.ComponentModel.INotifyPropertyChanged

Private _v As Integer
Public Property Value() As Integer
Get
Return _v
End Get
Set(ByVal value As Integer)
_v = value
OnPropertyChanged("Value")
End Set
End Property
Private _item As String
Public Property Item() As String
Get
Return _item
End Get
Set(ByVal value As String)
_item = value
OnPropertyChanged("Item")
End Set
End Property

Public Sub New(ByVal itemtext As String)
_item = itemtext
End Sub

Protected Overridable Sub OnPropertyChanged(ByVal propertyName As String)
Dim e As New System.ComponentModel.PropertyChangedEventArgs(propertyName)
RaiseEvent PropertyChanged(Me, e)
End Sub
Public Event PropertyChanged(ByVal sender As Object, ByVal e As System.ComponentModel.PropertyChangedEventArgs) Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged
End Class

Public Class Items
Inherits ObservableCollection(Of ItemClass)
End Class

Now, please realize that this is not 100% perfect (or production worthy) code, but rather stuff I tossed together for the provenance of this point.

What I've done is built a WPF application which holds two grids, one whose ItemsSource is pointed towards an ObservableCollection while the other's ItemsSource looks at a List. This is to show that when new items are added to these collections, one will automatically update while the other requires an explicit call to the datagrid's Items collection in order for the UI to be updated.

Now if you go back and look at Mykhaylo's code in the comment posted, you'll notice that the values are being populated via an IEnumerable accessed via a LINQ query of a DataTable in a DataSet.

Additionally, when Mykhaylo adds new items to the datatable, it appears in the datatable but not in the datagrid.

There's a reason for this.

And that is because the datagrid and the datatable are not bound together.

Here is mykhaylo's code:
AccDataGrid.ItemsSource = from account in _myDataSet.Accounts select new Account(account);
Notice that what's happening is that Mykhaylo is basically using LINQ to generate a new List which only exists as an object in the Datagrid's ItemsSource property.

Therefore when new items are added to the _myDataSet.Accounts object, there's nothing anywhere telling the datagrid about those objects.

The easiest solution would be to bind the datagrid in this manner:
AccDatagrid.ItemsSource = _myDataSet.Accounts
Then when items are added to the Accounts datagrid, it becomes a simple matter of using the AccDataGrid.Items.Refresh() command to update the UI.

Wednesday, July 15, 2009

Class Libraries and "ApplicationDefinition"

Oh the joys of Visual Studio IDE.

99% of the time, I love this tool, but there's that other 1% of the time, when I could happily smack it six ways to Sunday.

Well today I was working in a Class Library of one of my projects, and all of a sudden, it stopped compiling.

Just refused.

Which of course broke things up and down the solution, as this particular library is my Data Layer.

So, I peruse the Error List, and come across this two errors:

Error 1 Library project file cannot specify ApplicationDefinition element.
Error 2 The project file contains a property value that is not valid.
With absolutely NO reference to where, how, what, or even which object in the project that is generating these two wonderful ambiguous errors.

So, I turn to my good friend Google.

And got a lot, and a lot of results. Most of them talking about removing APP.XAML from the project (which I didn't have one in this project) or just flat out not knowing what it was/is/or means.

It's at this point that I start rubbing the bridge of my nose. I need to test my changes, and deploy for a customer display by this afternoon.

Starting to worry a bit, I removed the new dialog I had created (even though it was a WinForms dialog as opposed to a WPF window) and attempted to recompile.

Still with the error.

So, I change my search parameters slightly, and delve deeper into the mysterious workings of Google Search Results.

And found this link (translated into English here).

The basics talks of dragging objects from a WPF Application or a WPF Library project into a standard project. Apparently, the BUILD for these items will be changed from whatever they are in the WPF-based project to an "Application Definition" build command.

Which of course breaks a library, as only executable projects can build with Application Definition--and it's usually the App.XAML file which recieves this build type.

Pondering this, as I had not dragged nor dropped anything into the project, I remembered that I had added an object to this library; but instead of creating it new, or dragging & dropping, I had cut-and-pasted it into my resources folder.

So, I look at the build information for this image, and lo-and-behold, it had been changed to ApplicationDefinition.

I quickly modified it back to Resource like it should have been, and then compiled.

Eureka! And not the tv show, or the anime character, but rather the original intent.

Compilation proceeded, things started working, and life was good.

At least until I ran across my next bug....

Blog Widget by LinkWithin