This made it hard if not impossible for us to use the foreach binding. In essence, we wanted to keep the code for building and populating the table on the server side, but then have the rows bound to our Knockout.js viewmodels.
It turns out this is very easy. Instead of using the aforementioned foreach binding, you can use the with binding. Just put the following in your markup (in the ItemTemplate of your Repeater):
<tr data-bind="with: myItems()[<%# Container.ItemIndex %>]"></tr>
Then, inside your row, you can bind your cells or other controls to the properties of your viewmodel.
If you want to go the extra mile, you could have custom bindings that don’t set the value/text/whatever of the controls initially, so the initial rendering is handled 100% server-side. With the normal bindings, Knockout.js will set the values when you call applyBindings(), even though the server already set these values. But in our case, it didn’t slow things down. The important thing was that the bindings worked, so we could use it to hide/show/calculate certain values in certain cells.
So you see, the old lady (WebForms) just won’t sink! Which is testament to the great work the ASP.NET devs did from the get-go.
Edit: You can find a working example on my GitHub.