Переглянути джерело

AccountPage layout and local storage functionality

master
Flo Smilari 4 роки тому
джерело
коміт
167cfa5acc
7 змінених файлів з 216 додано та 20 видалено
  1. 12
    10
      App.razor
  2. 44
    10
      Pages/AccountPage.razor
  3. 1
    0
      Program.cs
  4. 32
    0
      Shared/UserData.cs
  5. 35
    0
      Shared/UserDataComponent.razor
  6. 72
    0
      Shared/UserDataProvider.cs
  7. 20
    0
      wwwroot/index.html

+ 12
- 10
App.razor Переглянути файл

@@ -1,10 +1,12 @@
<Router AppAssembly="@typeof(Program).Assembly">
<Found Context="routeData">
<RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
</Found>
<NotFound>
<LayoutView Layout="@typeof(MainLayout)">
<p>Sorry, there's nothing at this address.</p>
</LayoutView>
</NotFound>
</Router>
<UserDataComponent>
<Router AppAssembly="@typeof(Program).Assembly">
<Found Context="routeData">
<RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
</Found>
<NotFound>
<LayoutView Layout="@typeof(MainLayout)">
<p>Sorry, there's nothing at this address.</p>
</LayoutView>
</NotFound>
</Router>
</UserDataComponent>

+ 44
- 10
Pages/AccountPage.razor Переглянути файл

@@ -1,22 +1,56 @@
@page "/account"
@inject NavigationManager NavigationManager
@inject UserDataProvider UserDataProvider
<h1>Counter</h1>
<div class="row px-3 h-100">
<div class="row no-gutters align-items-start w-100">
<div class="row no-gutters w-100" style="padding-top:2em">
<div class="col-6" style="padding-right:0.5em">
<MatStringField Class="w-100" Label="Firstname" Outlined="true" type="text" @bind-Value="@State.Firstname"></MatStringField>
</div>
<div class="col-6" style="padding-left:0.5em">
<MatStringField Class="w-100" Label="Lastname" Outlined="true" type="text" @bind-Value="@State.Lastname"></MatStringField>
</div>
</div>
<div class="row no-gutters align-items-center w-100">
<div class="col-12">
<MatStringField Class="w-100" Label="Address" Outlined="true"></MatStringField>
</div>
</div>
<div class="row no-gutters align-items-center w-100">
<div class="col-4" style="padding-right:0.5em">
<MatStringField Class="w-100" Label="Zip" Outlined="true"></MatStringField>
</div>
<div class="col-8" style="padding-left:0.5em">
<MatStringField Class="w-100" Label="City" Outlined="true"></MatStringField>
</div>
</div>
<div class="row no-gutters align-items-center w-100">
<div class="col-12">
<MatStringField Class="w-100" Label="Phone" Outlined="true"></MatStringField>
</div>
</div>
<div class="row no-gutters align-items-center w-100">
<div class="col-12">
<MatStringField Class="w-100" Label="E-Mail" Outlined="true"></MatStringField>
</div>
</div>
</div>
<div class="row no-gutters align-items-end justify-content-center w-100" style="padding-bottom:2em">
<MatButton Class="w-100" Raised="true" @onclick="SaveUserData">Speichern</MatButton>
</div>
</div>
<p>Current count: @currentCount</p>
<MatList>
<MatListItem>
<MatButton Raised="true" @onclick="IncrementCount">Click me!</MatButton>
</MatListItem>
</MatList>
@code {
private int currentCount = 0;
private void IncrementCount() {
currentCount++;
async private void SaveUserData() {
await UserDataProvider.Save();
}
[CascadingParameter]
public UserData State { get; set; }
}

+ 1
- 0
Program.cs Переглянути файл

@@ -19,6 +19,7 @@ namespace CaritasPWA {
builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
builder.Services.AddMatBlazor();
builder.Services.AddSingleton<AppState>();
builder.Services.AddScoped<UserDataProvider>();
await builder.Build().RunAsync();
}

+ 32
- 0
Shared/UserData.cs Переглянути файл

@@ -0,0 +1,32 @@
using System.ComponentModel;
using System.Runtime.CompilerServices;
namespace CaritasPWA.Shared {
// The class that stores the user settings
public class UserData : INotifyPropertyChanged {
private string firstname;
private string lastname;
public string Firstname {
get => firstname;
set {
firstname = value;
RaisePropertyChanged();
}
}
public string Lastname {
get => lastname;
set {
lastname = value;
RaisePropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged([CallerMemberName] string propertyName = null) {
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}

+ 35
- 0
Shared/UserDataComponent.razor Переглянути файл

@@ -0,0 +1,35 @@
@inject UserDataProvider UserDataProvider
@implements IDisposable
@if (state == null) {
<p>loading...</p>
} else {
<CascadingValue Value="@state" IsFixed="false">@ChildContent</CascadingValue>
}
@code{
private UserData state = null;
[Parameter]
public RenderFragment ChildContent { get; set; }
protected override async Task OnInitializedAsync() {
UserDataProvider.Changed += UserDataChanged;
await Refresh();
}
public void Dispose() {
UserDataProvider.Changed -= UserDataChanged;
}
private async void UserDataChanged(object sender, EventArgs e) {
await InvokeAsync(async () => {
await Refresh();
StateHasChanged();
});
}
private async Task Refresh() {
state = await UserDataProvider.Get();
}
}

+ 72
- 0
Shared/UserDataProvider.cs Переглянути файл

@@ -0,0 +1,72 @@
using Microsoft.JSInterop;
using System;
using System.ComponentModel;
using System.Threading.Tasks;
namespace CaritasPWA.Shared {
public sealed class UserDataProvider {
private const string KeyName = "state";
private readonly IJSRuntime _jsRuntime;
private bool _initialized;
private UserData _data;
public event EventHandler Changed;
public bool AutoSave { get; set; } = true;
public UserDataProvider(IJSRuntime jsRuntime) {
_jsRuntime = jsRuntime;
}
public async ValueTask<UserData> Get() {
if (_data != null)
return _data;
// Register the Storage event handler. This handler calls OnStorageUpdated when the storage changed.
// This way, you can reload the settings when another instance of the application (tab / window) save the settings
if (!_initialized) {
// Create a reference to the current object, so the JS function can call the public method "OnStorageUpdated"
var reference = DotNetObjectReference.Create(this);
await _jsRuntime.InvokeVoidAsync("BlazorRegisterStorageEvent", reference);
_initialized = true;
}
// Read the JSON string that contains the data from the local storage
UserData result;
var str = await _jsRuntime.InvokeAsync<string>("BlazorGetLocalStorage", KeyName);
if (str != null) {
result = System.Text.Json.JsonSerializer.Deserialize<UserData>(str) ?? new UserData();
} else {
result = new UserData();
}
// Register the OnPropertyChanged event, so it automatically persists the settings as soon as a value is changed
result.PropertyChanged += OnPropertyChanged;
_data = result;
return result;
}
public async Task Save() {
var json = System.Text.Json.JsonSerializer.Serialize(_data);
await _jsRuntime.InvokeVoidAsync("BlazorSetLocalStorage", KeyName, json);
}
// Automatically persist the settings when a property changed
private async void OnPropertyChanged(object sender, PropertyChangedEventArgs e) {
if (AutoSave) {
await Save();
}
}
// This method is called from BlazorRegisterStorageEvent when the storage changed
[JSInvokable]
public void OnStorageUpdated(string key) {
if (key == KeyName) {
// Reset the settings. The next call to Get will reload the data
_data = null;
Changed?.Invoke(this, EventArgs.Empty);
}
}
}
}

+ 20
- 0
wwwroot/index.html Переглянути файл

@@ -17,6 +17,7 @@
</head>
<body>
<app>Loading...</app>
<div id="blazor-error-ui">
@@ -26,6 +27,25 @@
</div>
<script src="_framework/blazor.webassembly.js"></script>
<script>navigator.serviceWorker.register('service-worker.js');</script>
<script>
function BlazorSetLocalStorage(key, value) {
localStorage.setItem(key, value);
}
function BlazorGetLocalStorage(key) {
return localStorage.getItem(key);
}
function BlazorRegisterStorageEvent(component) {
window.addEventListener("storage", async e => {
await component.invokeMethodAsync("OnStorageUpdated", e.key);
});
}
</script>
</body>
</html>

Завантаження…
Відмінити
Зберегти