2016-11-17 85 views
0

我希望CollectionChanged在從我的表中爲其他地方的Azure插入todo項目時觸發。SignalR KnockoutJS和AzureTodo OnChangeEvent

我有一個mobileapp,我可以通過TodoItemManager插入項目。 我有一個網站列出項目。

現在我想不刷新網站,項目應該被添加。

一個選項是有一個setInterval,但我不喜歡那個選項。

<div class="products"> 
<div class="row" data-bind="template: { name: 'productTemplate', foreach:  products }"> 
</div> 
<span class="messageClass" style="color: red;"></span> 
</div> 
<script type="text/html" id="productTemplate"> 
<div class="col-sm-6 col-md-4"> 
<div class="thumbnail"> 
<div class="caption"> 
<h3 data-bind="text: name"></h3> 
</div> 
</div> 
</div> 
</script> 
<script> 
$(function() { 
//debugger; 
function productViewModel(id, name) { 
this.productId = id; 
this.name = ko.observable(name); 
var self = this; 
} 

function productListViewModel() { 
//debugger; 
this.hub = $.connection.myHub; 
this.products = ko.observableArray([]); 

var products = this.products; 

this.init = function() { 
this.hub.server.getAllProducts(); 
} 

this.hub.client.getAllProducts = function (allProducts) { 
//debugger; 
var mappedProducts = $.map(allProducts, function (item) { 
//debugger; 
return new productViewModel(item.ProductId, item.Name) 
}); 

products(mappedProducts); 
} 
} 

var vm = new productListViewModel(); 
ko.applyBindings(vm); 

$.connection.hub.start(function() { 
vm.init(); 
}).done(function() { 

});; 

}); 
</script> 

另一種選擇是觸發方法GetAllProducts從應用我的樞紐,因此會引發

await Clients.All.getAllProducts(vm.Products.ToArray()); 

但我不喜歡這種做法。

我想知道如何更新我的網頁上列出的數據,當我向Azure表中添加項目而不刷新瀏覽器時。

這裏是我的樞紐

public class MyHub : Hub 
{ 
    private ObservableCollection<TodoItem> persons; 
    public MyHub() 
    { 

    } 


    public async Task GetAllProducts() 
    { 
     var data = await GetLogs(); 
     VoteViewModel vm = new VoteViewModel(); 
     vm.Products = data.Select(m => new Products() { Name = m.Name }).ToList(); 
     //vm.Products = new List<Products>() { new Products() { Name = "Sample", ProductId = 1 } }; 
     await Clients.All.getAllProducts(vm.Products.ToArray()); 
    } 

    private async Task<List<TodoItem>> GetLogs() 
    { 
     persons = await TodoItemManager.DefaultManager.GetTodoItemsAsync(); 
     persons.CollectionChanged += this.OnCollectionChanged; 
     return persons.ToList(); 
    } 

    private void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs args) 
    { 

    } 

    class VoteViewModel 
    { 
     public List<Products> Products { get; set; } 
    } 
    public class Products 
    { 
     public int ProductId { get; set; } 
     public string Name { get; set; } 
    } 
} 

而且在TodoItemManager一看:

public partial class TodoItemManager 
{ 
    static TodoItemManager defaultInstance = new TodoItemManager(); 
    MobileServiceClient client; 

#if OFFLINE_SYNC_ENABLED 
    IMobileServiceSyncTable<TodoItem> todoTable; 
#else 
    IMobileServiceTable<TodoItem> todoTable; 
#endif 

    const string offlineDbPath = @"localstore.db"; 

    private TodoItemManager() 
    { 
     this.client = new MobileServiceClient(AzureSettings.ApplicationURL); 

#if OFFLINE_SYNC_ENABLED 
     var store = new MobileServiceSQLiteStore(offlineDbPath); 
     store.DefineTable<TodoItem>(); 

     //Initializes the SyncContext using the default IMobileServiceSyncHandler. 
     this.client.SyncContext.InitializeAsync(store); 

     this.todoTable = client.GetSyncTable<TodoItem>(); 
#else 
     this.todoTable = client.GetTable<TodoItem>(); 
#endif 
    } 

    public static TodoItemManager DefaultManager 
    { 
     get 
     { 
      return defaultInstance; 
     } 
     private set 
     { 
      defaultInstance = value; 
     } 
    } 

    public MobileServiceClient CurrentClient 
    { 
     get { return client; } 
    } 

    public bool IsOfflineEnabled 
    { 
     get { return todoTable is Microsoft.WindowsAzure.MobileServices.Sync.IMobileServiceSyncTable<TodoItem>; } 
    } 


    public async Task<ObservableCollection<TodoItem>> GetTodoItemsAsync(bool syncItems = false) 
    { 
     try 
     { 
#if OFFLINE_SYNC_ENABLED 
      if (syncItems) 
      { 
       await this.SyncAsync(); 
      } 
#endif 
      IEnumerable<TodoItem> items = await todoTable 
       .Where(todoItem => !todoItem.Done) 
       .ToEnumerableAsync(); 

      return new ObservableCollection<TodoItem>(items); 
     } 
     catch (MobileServiceInvalidOperationException msioe) 
     { 
      Debug.WriteLine(@"Invalid sync operation: {0}", msioe.Message); 
     } 
     catch (Exception e) 
     { 
      Debug.WriteLine(@"Sync error: {0}", e.Message); 
     } 
     return null; 
    } 

    public async Task SaveTaskAsync(TodoItem item) 
    { 
     if (item.Id == null) 
     { 
      await todoTable.InsertAsync(item); 
     } 
     else 
     { 
      await todoTable.UpdateAsync(item); 
     } 
    } 

#if OFFLINE_SYNC_ENABLED 
    public async Task SyncAsync() 
    { 
     ReadOnlyCollection<MobileServiceTableOperationError> syncErrors = null; 

     try 
     { 
      await this.client.SyncContext.PushAsync(); 

      await this.todoTable.PullAsync(
       //The first parameter is a query name that is used internally by the client SDK to implement incremental sync. 
       //Use a different query name for each unique query in your program 
       "allTodoItems", 
       this.todoTable.CreateQuery()); 
     } 
     catch (MobileServicePushFailedException exc) 
     { 
      if (exc.PushResult != null) 
      { 
       syncErrors = exc.PushResult.Errors; 
      } 
     } 

     // Simple error/conflict handling. A real application would handle the various errors like network conditions, 
     // server conflicts and others via the IMobileServiceSyncHandler. 
     if (syncErrors != null) 
     { 
      foreach (var error in syncErrors) 
      { 
       if (error.OperationKind == MobileServiceTableOperationKind.Update && error.Result != null) 
       { 
        //Update failed, reverting to server's copy. 
        await error.CancelAndUpdateItemAsync(error.Result); 
       } 
       else 
       { 
        // Discard local change. 
        await error.CancelAndDiscardItemAsync(); 
       } 

       Debug.WriteLine(@"Error executing sync operation. Item: {0} ({1}). Operation discarded.", error.TableName, error.Item["id"]); 
      } 
     } 
    } 
#endif 
} 

如你本身在我中心我

this.OnCollectionChanged 

嘗試,但這樣只會改變如果

private ObservableCollection<TodoItem> persons; 

變化,這將不會發生,所以我需要調用再次

GetTodoItemsAsync 

獲取數據。

如何在不刷新整個網站的情況下將新項目添加到天藍色表格時在客戶端上更新我的列表?

希望你明白我在哪裏瞄準。 BR

回答

0

另一種選擇是在服務器而不是客戶端上設置時間間隔。

像:

public class MyHub : Hub 
{ 
    private ObservableCollection<TodoItem> persons; 
    public MyHub() 
    { 
     Intervalla(); 
    } 

    public async Task Intervalla() 
    { 
     EasyTimer.SetInterval(async() => 
     { 
      var data = await GetLogs(); 
      VoteViewModel vm = new VoteViewModel(); 
      vm.Products = data.Select(m => new Products() { Name = m.Name }).ToList(); 
      //vm.Products = new List<Products>() { new Products() { Name = "Sample", ProductId = 1 } }; 
      await Clients.All.getAllProducts(vm.Products.ToArray()); 

     }, 1000); 
    } 

難道這是一個聰明/ ER選?