Po ukazaniu się nowej odsłony Windows 8 postanowiłem nie tylko przenieść to co już było na nową wersję projektu Visual Studio, ale także równocześnie rozwijać poszczególne funkcjonalności i wprowadzać nowe pomysły do interfejsu użytkownika.
Wskutek tych działań pierwsza strona aplikacji prezentuje się obecnie następująco:
Wprowadziłem następujące zmiany:
- usunąłem gradient z tła aplikacji (kierując się duchem prostoty)
- przeniosłem przyciski paska aplikacji na prawą stronę (większość predefiniowanych aplikacji ma przyciski z tej strony)
- zmieniłem wizualizację pobieranych plików na przycisk ze statusem otwierający popup (większa prostota i wygoda użytkowania)
- zaimplementowałem pobieranie plików w tle z paskami postępu
Podzielę się teraz różnymi ciekawymi spostrzeżeniami/fragmentami kodu z ostatnich kilku dni:
- Zainstalowane aplikacje Metro - obecnie znajdują się w C:\Program Files\WindowsApps
- Słowniki z predefiniowanymi szablonami XAML – pliki .xaml w katalogu C:\Program Files (x86)\Windows Kits\8.0\Include\winrt\xaml\design (nie wszystkie szablony da się skopiować i otworzyć do edycji za pomocą Blenda)
- Edytowanie szablonów XAML - analogicznie jak we wcześniejszych wersjach Blend, na poniższym zrzucie ekranu edytuję GridViewItem (element kontrolki GridView)
- Binding relatywny - można dostrzec w nowym oknie databindingu w Blend nowe pozycje
- Strony - obecnie znacznie uległa zmianie ich implementacja w szablonach Visual Studio, wprowadzono typ bazowy, który zawiera w sobie obsługę zmiany layout’u w zależności od orientacji ekranu i stanu okna aplikacji
- AppBar - obecnie są dwie properties w stronie dla paska na dole i górze, nie osadzamy go już bezpośrednio w layout
- Przyciski AppBar - są predefionowane style dla sporej liczby przycisków, również w znakach czcionki Segoe UI Symbol odnajdziemy obecnie znacznie większą ilość symboli
- Nawigacja - określanie typu za pomocą … typu zamiast stringa z nazwą typu (jak było wcześniej), w szablonie Visual Studio pojawił się predefiniowany Frame
- Popup - analogicznie jak w Silverlight, także pozycjonowanie w oparciu o mierzenie rozmiaru obiektów
- Notyfikacje
- jeden interfejs INotifyPropertyChanged !
- predefiniowana klasa BindableBase w szablonie Visual Studio wykorzystująca atrybuty parametrów metod z C#5
[Windows.Foundation.Metadata.WebHostHidden]
public abstract class BindableBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;protected bool SetProperty<T>(ref T storage, T value, [CallerMemberName] String propertyName = null)
{
if (object.Equals(storage, value)) return false;storage = value;
this.OnPropertyChanged(propertyName);
return true;
}protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
var eventHandler = this.PropertyChanged;
if (eventHandler != null)
{
eventHandler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Dzięki implementacji z atrybutem [CallerMemberName] nie musimy w klasie dziedziczącej podawać jawnie nazwy property. Przykładowo w mojej klasie DownloadFileTask wygląda to tak:
public class DownloadFileTask : BindableBase
{
….
private double _progress;
public double Progress
{
get { return _progress; }
set
{
SetProperty<double>(ref _progress, value);
}
}
}
Mamy więc prostszą implementację niż dotychczas, choć …. nie tak prostą, gdyby porównać to z podejściem aspektowym, jakie udało się wypracować w Silverlight
- kolekcja ObservableCollection<T> obecnie już działa ! (u mnie lista pobieranych plików na popup)
- Pobieranie plików w tle
sealed partial class App : Application
{
private CancellationTokenSource _cts;
public ObservableCollection<DownloadFileTask> ActiveDownloads { get; private set; }
….
private async void DiscoverActiveDownloads()
{
ActiveDownloads = new ObservableCollection<DownloadFileTask>();
try
{
IReadOnlyList<DownloadOperation> downloads = await BackgroundDownloader.GetCurrentDownloadsAsync();
foreach (DownloadOperation download in downloads)
{
HandleDownloadAsync(download, false);
}
}
catch (Exception ex)
{ }
}
public void StartDownload(IEnumerable<YouTubeEntry> items)
{
foreach (var item in items)
StartDownload(item);
}
private async void StartDownload(YouTubeEntry item)
{
try
{
var client = new HttpClient() { MaxResponseContentBufferSize = 65536 * 4 };
var respMsg = await client.GetAsync(YouTubeUtils.Convert(item.VideoUrl) + "&nomobile=1");
if (respMsg.StatusCode != System.Net.HttpStatusCode.OK) return;
var content = await respMsg.Content.ReadAsStringAsync();
var str2 = YouTubeUtils.GetFromaturl(content, "720P");
var bd = new BackgroundDownloader();
var newFile = await KnownFolders.VideosLibrary.CreateFileAsync(item.Title + ".mp4", CreationCollisionOption.ReplaceExisting);
var download = bd.CreateDownload(new Uri(str2, UriKind.Absolute), newFile);
HandleDownloadAsync(download, true);
}
catch (Exception)
{
}
}
private async void HandleDownloadAsync(DownloadOperation download, bool start)
{
var downloadTask = new DownloadFileTask
{
Guid = download.Guid,
FileName = download.ResultFile.Name.Replace(".mp4", ""),
BytesReceived = download.Progress.BytesReceived,
TotalBytesToReceive = download.Progress.TotalBytesToReceive,
Status = download.Progress.Status
};
try
{
ActiveDownloads.Add(downloadTask);
Progress<DownloadOperation> progressCallback = new Progress<DownloadOperation>(DownloadProgress);
if (start)
{
await download.StartAsync().AsTask(_cts.Token, progressCallback);
}
else
{
await download.AttachAsync().AsTask(_cts.Token, progressCallback)
}
}
catch (TaskCanceledException)
{
}
catch (Exception ex)
{
}
finally
{
ActiveDownloads.Remove(downloadTask);
}
}
private void DownloadProgress(DownloadOperation download)
{
MarshalUpdate(download.Guid, download.Progress.BytesReceived, download.Progress.TotalBytesToReceive, download.Progress.Status);
}
private void MarshalUpdate(Guid guid, ulong bytesReceived, ulong totalBytesToReceive, BackgroundTransferStatus status)
{
Window.Current.Content.Dispatcher.Invoke(Windows.UI.Core.CoreDispatcherPriority.Normal, (sender, state) =>
{
var item = ActiveDownloads.FirstOrDefault(it => it.Guid == guid);
if (item != null)
{
if (totalBytesToReceive > 0)
item.Progress = bytesReceived * 100 / totalBytesToReceive;
}
}, this, null);
}
}
Tu taka ciekawostka - gdy podczas dłuższego pobierania całkowicie zamknę aplikację i potem ją otworzę zupełnie na nowo, w metodzie AttachAsync będzie wyjątek, tak samo w przykładzie MS na którym się wzorowałem.
- Co nowego w obecnej wersji platformy i narzędzi ?
Z tą tematyką będzie związany niejeden post, który napiszę, dokonam też za jakiś czas szczegółowego podsumowania po zapoznaniu się z wszystkimi materiałami. Dziś jedynie wspomnę, że twórcy napisali o tym trochę już postów:
- What’s changed for app developers since //build/ (part 1)
- What’s changed for app developers since //build/ (part 2)
- Migrating your apps from Developer Preview to Consumer Preview
- Blend Beta Known Issue: Menus do not render correctly when Windows 8 Basic theme is applied
- Visual Authoring for the Windows 8 Consumer Preview with Blend and Visual Studio
- Build HTML Metro style apps with Blend for Visual Studio 11 Beta
- Known Issue: XAML Designer in Visual Studio 11 Beta Crashes on Launch
- Blend’s Data Binding dialog: new features and UX refresh
Brak komentarzy:
Prześlij komentarz