【问题标题】:SignalR KnockoutJS and AzureTodo OnChangeEventSignalR KnockoutJS 和 AzureTodo OnChangeEvent
【发布时间】:2016-11-17 17:54:52
【问题描述】:

我希望当待办事项从其他地方插入到 Azure 的表中时触发 CollectionChanged。

我有一个移动应用程序,我可以通过 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>

另一种选择是从应用程序触发我的 Hub 中的 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

再次获取数据。

当新项目添加到 azure 表而不刷新整个站点时,我如何在客户端更新我的列表?

希望您了解我的目标。 BR

【问题讨论】:

    标签: azure knockout.js signalr


    【解决方案1】:

    另一种选择是在服务器而不是客户端上设置时间间隔。

    喜欢:

    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);
        }
    

    这可能是一个更聪明/更好的选择吗?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-05-06
      • 2013-03-02
      • 2013-11-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多