2018 年 1 月

第 33 卷,第 1 期

本文章是由機器翻譯。

通用 Windows 平台 - 使用 UWP 建立企業營運應用程式

Bruno Sonnino

一天,老闆隨附您新的作業:適用於 Windows,您必須建立新的特定業務 (LOB) 應用程式。Web 不可行,您必須選擇最佳的平台,讓它,以確保將予以提供更多的至少 10 年。

似乎是很困難的選擇:您可以選取 Windows Form 或 Windows Presentation Foundation (WPF),也就是具有許多元件的成熟技術,而且您的.NET 開發人員,有很多的知識和經驗使用它們。它們會有 10 年中?我的猜測是 [否]。沒有禁止標誌,Microsoft 將會中斷其中任何在不久的未來。但除了舊的位元 (取自 2001年的 Windows Form 和 WPF 是在 2006年),這些技術有一些其他的問題:Windows Form 不使用最新的視訊卡,並且使用相同的舊無趣樣式,除非您使用額外的元件或執行某些 magic 訣竅被困。WPF 中,它仍在更新,但尚未趕上 OS 以及其 SDK 最新的增強功能。此外,不可以部署到 Windows 市集,並受益於它:那里不易於部署和安裝/解除安裝、 全球探索及發佈和等等。您可以使用 Centennial 來封裝應用程式,但是並非像是 「 真實動作 」。

更深入,您探索適用於 Windows 10 開發通用 Windows 平台 (UWP),並查看它沒有 Windows Form 和 WPF 的缺點。它主動改進,並可以搭配各種不同的裝置,從大型 Surface Hub 小覆盆子 Pi 沒有變更。但可否說明 UWP 是用於開發 Windows 平板電腦和手機; 的小型應用程式沒有這類的 LOB 應用程式使用 UWP。除了,是很難了解及開發: 所有這些新的模式、 XAML 語言、 沙箱,限制可以做什麼,以及。

所有的遠低於實際。雖然過去 UWP 會有一些限制,而且可能很難或了解,並使用,這是不再為 true。已變得積極開發新功能,其 SDK 新改建立者更新 (FCU) 與您可以甚至使用.NET 標準 2.0 Api,以及直接存取 SQL Server。在相同的時間,新的工具和元件可讓您開發新的應用程式的最佳體驗。Windows 範本 Studio (WTS) 是提供快速啟動功能完整的 UWP 應用程式的 Visual Studio 的擴充功能,您可以使用 Telerik 元件 UWP 免費,最佳的經驗不錯,no 嗎?現在您有新的平台來開發 UWP 的 LOB 應用程式 !

在本文中,我們即將開發 UWP 的 LOB 應用程式使用 WTS Telerik 元件和直接存取 SQL Server 使用標準的.NET 2.0,讓您可以查看如何運作一切正常效應。

Windows 範本 Studio 簡介

我說過之前,您需要 FCU 和其相對應的 SDK,以使用.NET 標準 2.0。一旦您擁有 FCU 安裝在您的電腦上 (如果您不確定,請按 Win + R,鍵入 Winver 以顯示您的 Windows 版本。您的版本應該是 1709年或更新版本)。因此如果您未更新,您必須執行它現在僅適用於 Visual Studio 2017 update 4 或更新版本中,在 UWP 中的.NET 標準 2.0 支援。您也需要使用它所安裝的.NET 4.7 執行階段。

與基礎結構,您可以安裝 WTS。在 Visual Studio 中,前往 [工具 |擴充功能和更新,以及搜尋 Windows 範本 Studio。您下載該套件之後,重新啟動 Visual Studio 以完成安裝。您也可以安裝它,請前往aka.ms/wtsinstall下載安裝程式,然後安裝 WTS。

Windows 範本 Studio 是一個新的開放原始延伸模組 (您可以取得中的原始程式碼aka.ms/wts),可讓您很棒的快速入門 UWP 開發:您可以選擇專案類型 (漢堡] 功能表中,瀏覽窗格的空白,或樞紐和定位點) 的模型-檢視-ViewModel (MVVM) 架構 MVVM 模式中,您要在專案中的網頁和您想要包含的 Windows 10 功能。沒有進行中此專案中,開發許多且角柱,Visual Basic 範本和 Xamarin 支援都已經在夜間組建 (即將推出的穩定版本)。

與 WTS 安裝,您可以移至 Visual Studio,並建立新的專案使用檔案 |新的專案 |Windows 通用,然後選取 Windows 範本 Studio。選擇的專案將會開啟新視窗 (請參閱圖 1)。

Windows 範本 Studio 主畫面
圖 1 Windows 範本 Studio 主畫面

選取 [瀏覽窗格中的專案與 MVVM Light 架構,然後選取 [下一步]。現在,選擇應用程式中的頁面,如下所示圖 2

頁面上選取項目
圖 2 頁選取

您可以看到權限摘要的資料行中,已經有一個空白網頁,選取,名為 Main。選取 [設定] 頁面上和設定,以及主版詳細資料頁面上將它命名並命名為 Sales,然後按一下 [下一步] 按鈕。在下一個視窗中,您可以選取應用程式中,例如即時磚或快顯通知或將會出現第一次執行應用程式的第一次使用對話的某些功能。將不會選擇的任何功能現在,除非您選擇 [設定] 頁面時,會選取的設定儲存體。

現在,按一下 [建立] 按鈕以選取的功能建立新的應用程式。您可以執行應用程式,它是完整的應用程式,其中包含漢堡 」 功能表 (空白和主版詳細資料) 的兩個頁面,設定頁面 (底部的齒輪圖示,即可存取),可讓您變更應用程式的主題。

如果您移至 [方案總管] 中,您會看到許多資料夾所建立的應用程式,例如模型、 ViewModels 和服務。即使是 EN-US 的子資料夾的字串當地語系化的字串資料夾。如果您想要新增其他語言的應用程式,您只需要加入新的子字串資料夾、 名稱 (例如 FR-FR) 語言的地區設定、 Resources.resw 檔案複製和翻譯新語言。令人驚嘆您已經的幾個透過達成按一下時,沒有嗎?但我很確定這是什麼老闆未記住他指派給您時,讓我們移自訂該應用程式 !

從應用程式存取 SQL Server

FCU 和 Visual Studio 更新 4 中導入一個好處是在 UWP 中的.NET 標準 2.0 的支援。這是一大,因為它可讓 UWP 應用程式使用大量的 Api,已無法使用,包括 SQL Server 用戶端存取和 Entity Framework Core。

若要使用 SQL Server 用戶端存取您的應用程式中,請移至應用程式內容並選取建置 16299 做為應用程式] 索引標籤中的最小版本。然後以滑鼠右鍵按一下 [參考] 節點,並選取 「 管理 NuGet 套件 」,並安裝 System.Data.SqlClient。您就可以存取本機的 SQL Server 資料庫。一個附註: 存取不使用具名管道進行 — 預設存取方法,但使用的 TCP/IP。因此,您必須執行 SQL Server 組態應用程式,並為您的伺服器執行個體啟用 TCP/IP 連接。

我也會使用 Telerik UI UWP 方格中,現在您會發現在免費的開放原始碼產品bit.ly/2AFWktT。因此,雖然您仍有的 NuGet 封裝管理員] 視窗開啟時,選取並安裝 Telerik.UI.for.UniversalWindowsPlatform 套件。如果您正在新增格線頁中 WTS,此套件會自動安裝。

此應用程式中,我將使用 WorldWideImporters 範例資料庫,您可以從下載bit.ly/2fLYuBk並將它還原至您的 SQL Server 執行個體。

現在,您必須變更預設資料存取權。如果您移到 [模型] 資料夾,您會看到 SampleOrder 類別,此註解的開頭:

// TODO WTS: Remove this class once your pages/features are using your data.
// This is used by the SampleDataService.
// It is the model class we use to display data on pages like Grid, Chart, and Master Detail.

有許多提供指引您需要在整個專案註解。在此情況下,您需要為非常類似以下的順序類別。重新命名類別的順序,並將它變更使其名稱類似於圖 3

圖 3 的 Order 類別

public class Order : INotifyPropertyChanged
{
  public long OrderId { get; set; }
  public DateTime OrderDate { get; set; }
  public string Company { get; set; }
  public decimal OrderTotal { get; set; }
  public DateTime? DatePicked { get; set; }
  public bool Delivered => DatePicked != null;
  private IEnumerable<OrderItem> _orderItems;
  public event PropertyChangedEventHandler PropertyChanged;
  public IEnumerable<OrderItem> OrderItems
  {
    get => _orderItems;
    set
    {
      _orderItems = value;
      PropertyChanged?.Invoke(
        this, new PropertyChangedEventArgs("OrderItems"));
    }
  }
  public override string ToString() => $"{Company} {OrderDate:g}  {OrderTotal}";
}

這個類別會實作 INotifyPropertyChanged 介面,因為我想要時訂購項目已變更,所以我可以視需要載入其顯示的順序時,通知 UI。我已定義另一個類別,OrderItem,來儲存排序項目:

public class OrderItem
{
  public string Description { get; set; }
  public decimal UnitPrice { get; set; }
  public int Quantity { get; set; }
  public decimal TotalPrice => UnitPrice * Quantity;
}

SalesViewModel,示圖 4,也必須修改以反映這些變更。

圖 4 SalesViewModel

public class SalesViewModel : ViewModelBase
{
  private Order _selected;
  public Order Selected
  {
    get => _selected;
    set
    {
      Set(ref _selected, value);
    }
  }
  public ObservableCollection<Order> Orders { get; private set; }
  public async Task LoadDataAsync(MasterDetailsViewState viewState)
  {
    var orders = await DataService.GetOrdersAsync();
    if (orders != null)
    {
      Orders = new ObservableCollection<Order>(orders);
      RaisePropertyChanged("Orders");
    }
    if (viewState == MasterDetailsViewState.Both)
    {
      Selected = Orders.FirstOrDefault();
    }
  }
}

選取的屬性變更時,其會檢查是否已經載入訂單項目,如果沒有,它會將其載入資料服務中呼叫 GetOrderItemsAsync 方法。

讓程式碼的最後一個變更是在 SampleDataService 類別中,若要移除的範例資料,並建立 SQL Server 存取,如下所示圖 5。我已重新命名為 DataService,以反映它不是範例不再類別。

圖 5 程式碼,以從資料庫擷取訂單

public static async Task<IEnumerable<Order>> GetOrdersAsync()
{
  using (SqlConnection conn = new SqlConnection(
    "Database=WideWorldImporters;Server=.;User ID=sa;Password=pass"))
  {
    try
    {
      await conn.OpenAsync();
      SqlCommand cmd = new SqlCommand("select o.OrderId, " +
        "c.CustomerName, o.OrderDate, o.PickingCompletedWhen, " +
        "sum(l.Quantity * l.UnitPrice) as OrderTotal " +
        "from Sales.Orders o " +
        "inner join Sales.Customers c on c.CustomerID = o.CustomerID " +
        "inner join Sales.OrderLines l on o.OrderID = l.OrderID " +
        "group by o.OrderId, c.CustomerName, o.OrderDate,
          o.PickingCompletedWhen " +
        "order by o.OrderDate desc", conn);
      var results = new List<Order>();
      using (SqlDataReader reader = await cmd.ExecuteReaderAsync())
      {
        while(reader.Read())
        {
          var order = new Order
          {
            Company = reader.GetString(1),
            OrderId = reader.GetInt32(0),
            OrderDate = reader.GetDateTime(2),
            OrderTotal = reader.GetDecimal(4),
            DatePicked = !reader.IsDBNull(3) ? reader.GetDateTime(3) :
              (DateTime?)null
          };
          results.Add(order);
        }
        return results;
      }
    }
    catch
    {
      return null;
    }
  }
}
public static async Task<IEnumerable<OrderItem>> GetOrderItemsAsync(
  int orderId)
{
  using (SqlConnection conn = new SqlConnection(
        "Database=WideWorldImporters;Server=.;User ID=sa;Password=pass"))
  {
    try
    {
      await conn.OpenAsync();
      SqlCommand cmd = new SqlCommand(
        "select Description,Quantity,UnitPrice " +
        $"from Sales.OrderLines where OrderID = {orderId}", conn);
      var results = new List<OrderItem>();
      using (SqlDataReader reader = await cmd.ExecuteReaderAsync())
      {
        while (reader.Read())
        {
          var orderItem = new OrderItem
          {
            Description = reader.GetString(0),
            Quantity = reader.GetInt32(1),
            UnitPrice = reader.GetDecimal(2),
          };
          results.Add(orderItem);
        }
        return results;
      }
    }
    catch
    {
      return null;
    }
  }
}

程式碼是您在任何.NET 應用程式中; 將使用相同完全沒有任何變更。現在我必須修改以反映變更,SalesPage.xaml 的清單項目資料範本中所示圖 6

圖 6 清單項目資料範本

<DataTemplate x:Key="ItemTemplate" x:DataType="model:Order">
  <Grid Height="64" Padding="0,8">
    <Grid.ColumnDefinitions>
      <ColumnDefinition Width="Auto"/>
      <ColumnDefinition Width="*"/>
    </Grid.ColumnDefinitions>
    <StackPanel Grid.Column="1" Margin="12,0,0,0" VerticalAlignment="Center">
      <TextBlock Text="{x:Bind Company}" Style="{ThemeResource ListTitleStyle}"/>
      <StackPanel Orientation="Horizontal">
        <TextBlock Text="{x:Bind OrderDate.ToShortDateString()}"
                   Margin="0,0,12,0" />
        <TextBlock Text="{x:Bind OrderTotal}" Margin="0,0,12,0" />
      </StackPanel>
    </StackPanel>
  </Grid>
</DataTemplate><DataTemplate x:Key="DetailsTemplate">
  <views:SalesDetailControl MasterMenuItem="{Binding}"/>
</DataTemplate>

我需要變更資料類型,讓它指向新的 Order 類別,並變更 Textblock 中的欄位。我也必須變更程式碼後置中 SalesDetailControl.xaml.cs 時所要載入的選定訂單的項目進行變更。這是在 OnMasterMenuItemChanged 方法中,轉換為非同步方法:

private static async void OnMasterMenuItemChangedAsync(DependencyObject d,
  DependencyPropertyChangedEventArgs e)
{
  var newOrder = e.NewValue as Order;
  if (newOrder != null && newOrder.OrderItems == null)
    newOrder.OrderItems = await
      DataService.GetOrderItemsAsync((int)newOrder.OrderId);
}

接下來,我必須變更 SalesDetailControl 以指向新的欄位,並顯示它們,如中所示圖 7

圖 7 SalesDetailControl 變更

<Grid Name="block" Padding="0,15,0,0">
  <Grid.Resources>
    <Style x:Key="RightAlignField" TargetType="TextBlock">
      <Setter Property="HorizontalAlignment" Value="Right" />
      <Setter Property="VerticalAlignment" Value="Center" />
      <Setter Property="Margin" Value="0,0,12,0" />
    </Style>
  </Grid.Resources>
  <Grid.RowDefinitions>
    <RowDefinition Height="Auto" />
    <RowDefinition Height="Auto" />
    <RowDefinition Height="*" />
  </Grid.RowDefinitions>
  <TextBlock Margin="12,0,0,0"
    Text="{x:Bind MasterMenuItem.Company, Mode=OneWay}"
    Style="{StaticResource SubheaderTextBlockStyle}" />
  <StackPanel Orientation="Horizontal" Grid.Row="1" Margin="12,12,0,12">
    <TextBlock Text="Order date:"
      Style="{StaticResource BodyTextBlockStyle}" Margin="0,0,12,0"/>
    <TextBlock Text="{x:Bind MasterMenuItem.OrderDate.ToShortDateString(),
      Mode=OneWay}"
      Style="{StaticResource BodyTextBlockStyle}" Margin="0,0,12,0"/>
    <TextBlock Text="Order total:" Style="{StaticResource BodyTextBlockStyle}"
      Margin="0,0,12,0"/>
    <TextBlock Text="{x:Bind MasterMenuItem.OrderTotal, Mode=OneWay}"
      Style="{StaticResource BodyTextBlockStyle}" />
  </StackPanel>
  <grid:RadDataGrid ItemsSource="{x:Bind MasterMenuItem.OrderItems,
    Mode=OneWay}" Grid.Row="2"
    UserGroupMode="Disabled" Margin="12,0"
    UserFilterMode="Disabled" BorderBrush="Transparent"
      AutoGenerateColumns="False">
    <grid:RadDataGrid.Columns>
      <grid:DataGridTextColumn PropertyName="Description" />
      <grid:DataGridNumericalColumn
        PropertyName="UnitPrice"  Header="Unit Price"
        CellContentStyle="{StaticResource RightAlignField}"/>
      <grid:DataGridNumericalColumn
        PropertyName="Quantity"  Header="Quantity"
        CellContentStyle="{StaticResource RightAlignField}"/>
      <grid:DataGridNumericalColumn
        PropertyName="TotalPrice"  Header="Total Price"
        CellContentStyle="{StaticResource RightAlignField}"/>
    </grid:RadDataGrid.Columns>
  </grid:RadDataGrid>
</Grid>

我的銷售資料顯示在控制項的頂端,並使用 Telerik RadDataGrid 顯示訂單項目。現在,當執行應用程式時,取得訂單在第二個頁面上,如中所示圖 8

應用程式顯示資料庫的訂單
圖 8 應用程式顯示資料庫的訂單

仍有空白的主頁面。我將使用它來顯示所有客戶的方格。在 MainPage.xaml 中,加入內容的方格資料格:

<grid:RadDataGrid ItemsSource="{Binding Customers}"/>

您必須將命名空間加入頁面標記,但是您不需要記住的語法和正確的命名空間。只要將滑鼠游標放在 RadDataGrid 中,輸入 Ctrl +。會開啟一個方塊,指出要加入正確的命名空間。您可以從新增列看到,我 ItemsSource 屬性繫結至客戶。頁面的 DataContext 是 MainViewModel,執行個體,因此我必須 MainViewModel.cs,在建立這個屬性,如中所示圖 9

圖 9 MainViewModel 類別

public class MainViewModel : ViewModelBase
{
  public ObservableCollection<Customer> Customers { get; private set; }
  public async Task LoadCustomersAsync()
  {
    var customers = await DataService.GetCustomersAsync();
    if (customers != null)
    {
      Customers = new ObservableCollection<Customer>(customers);
      RaisePropertyChanged("Customers");
    }
  }
  public MainViewModel()
  {
    LoadCustomersAsync();
  }
}

我正在載入客戶 ViewModel 建立時。請注意一件事是,我不等待完成載入。當資料已完全載入,ViewModel 表示客戶屬性已變更,而且可載入檢視中的資料。GetCustomersAsync 中的方法 DataService 是非常類似於 GetOrdersAsync,如下所示圖 10

圖 10 GetCustomersAsync 方法

public static async Task<IEnumerable<Customer>> GetCustomersAsync()
{
  using (SqlConnection conn = new SqlConnection(
    "Database=WideWorldImporters;Server=.;User ID=sa;Password=pass"))
  {
    try
    {
      await conn.OpenAsync();
      SqlCommand cmd = new SqlCommand("select c.CustomerID,
        c.CustomerName, " +
        "cat.CustomerCategoryName, c.DeliveryAddressLine2, 
          c.DeliveryPostalCode, " +
        "city.CityName, c.PhoneNumber " +
        "from Sales.Customers c " +
        "inner join Sales.CustomerCategories cat on c.CustomerCategoryID =
          cat.CustomerCategoryID " +
        "inner join Application.Cities city on c.DeliveryCityID =
          city.CityID", conn);
      var results = new List<Customer>();
      using (SqlDataReader reader = await cmd.ExecuteReaderAsync())
      {
        while (reader.Read())
        {
          var customer = new Customer
          {
            CustomerId = reader.GetInt32(0),
            Name = reader.GetString(1),
            Category = reader.GetString(2),
            Address = reader.GetString(3),
            PostalCode = reader.GetString(4),
            City = reader.GetString(5),
            Phone = reader.GetString(6)
          };
          results.Add(customer);
        }
        return results;
      }
    }
    catch
    {
      return null;
    }
  }
}

您可以執行應用程式,並中所示,在主要頁面上,查看客戶圖 11。使用 Telerik 方格,您的免費取得大量好康: 群組中的排序和篩選全都會建置到方格中,沒有進行任何額外處理。

客戶格線,內含群組和篩選
圖 11 客戶格線,內含群組和篩選

最終補充

我有現在基本 LOB 應用程式,與客戶方格顯示訂單的主版詳細資料檢視,但它可以使用最後修飾。這兩個頁面的 [橫向] 列中的圖示相同,而且您可以自訂。這些圖示會設定在 ShellViewModel。如果您前往該處,您會看到這些註解,指向 [變更圖示和文字之項目的位置:

// TODO WTS: Change the symbols for each item as appropriate for your app
// More on Segoe UI Symbol icons:
// https://docs.microsoft.com/windows/uwp/style/segoe-ui-symbol-font
// Or to use an IconElement instead of a Symbol see
// https://github.com/Microsoft/WindowsTemplateStudio/blob/master/docs/
projectTypes/navigationpane.md
// Edit String/en-US/Resources.resw: Add a menu item title for each page

您可以使用 (如同在實際的程式碼) 的字型符號圖示或影像從其他來源如果您使用 IconElements。(您可以使用 [.png 檔案、 XAML 路徑或字元從任何其他字型,看看bit.ly/2zICuB2如需詳細資訊。) 我要使用 Segoe UI 符號、 人員及 ShoppingCart 的兩個符號。若要這樣做,請我必須變更程式碼中的 NavigationItems:

_primaryItems.Add(new ShellNavigationItem("Shell_Main".GetLocalized(),
  Symbol.People, typeof(MainViewModel).FullName));
_primaryItems.Add(new ShellNavigationItem("Shell_Sales".GetLocalized(),
  (Symbol)0xE7BF, typeof(SalesViewModel).FullName));

第一個項目,符號的 Symbol.People,列舉中已經有一個符號,但秒,沒有任何這類列舉型別,因此我使用十六進位值,並將它轉換成符號列舉。若要變更頁面的標題和功能表項目的標題,編輯 Resources.resw 和變更 Shell_Main 和 Main_Title.Text 給客戶。我也可以變更某些屬性,來加入至方格的某項自訂作業:

<grid:RadDataGrid ItemsSource="{Binding Customers}" UserColumnReorderMode="Interactive"
                  ColumnResizeHandleDisplayMode="Always"
                  AlternationStep="2" AlternateRowBackground="LightBlue"/>

將動態磚加入至應用程式

我也可以加入動態磚,以加強應用程式。我將會執行,移至方案總管] 中,以滑鼠右鍵按一下專案節點並選取 Windows 範本 Studio |新功能,然後選擇 [即時磚。當您按一下 [下一步] 按鈕時,它會顯示受影響的圖格 (新的和那些已變更),因此您可以看到您真的要您的作法。按一下完成] 5d; 按鈕將會加入應用程式所做的變更。

若要加入動態磚的所有項目會有,您只需要建立的圖格的內容。這是已完成 LiveTileService.Samples。部分類別,將方法 SampleUpdate LiveTileService 加入它。中所示圖 12,我要將檔案重新命名為 LiveTileService.LobData 並加入兩個方法,UpdateCustomerCount 和 UpdateOrdersCount,這會顯示在即時磚多少客戶或訂單在資料庫中。

圖 12 類別,來更新動態磚

internal partial class LiveTileService
{
  private const string TileTitle = "LoB App with UWP";
  public void UpdateCustomerCount(int custCount)
  {
    string tileContent =
      $@"There are {(custCount > 0 ? custCount.ToString() : "no")}
        customers in the database";
    UpdateTileData(tileContent, "Customer");
  }
  public void UpdateOrderCount(int orderCount)
  {
    string tileContent =
      $@"There are {(orderCount > 0 ? orderCount.ToString() : "no")}
        orders in the database";
    UpdateTileData(tileContent,"Order");
  }
  private void UpdateTileData(string tileBody, string tileTag)
  {
    TileContent tileContent = new TileContent()
    {
      Visual = new TileVisual()
      {
        TileMedium = new TileBinding()
        {
          Content = new TileBindingContentAdaptive()
          {
            Children =
            {
              new AdaptiveText()
              {
                Text = TileTitle,
                HintWrap = true
              },
              new AdaptiveText()
              {
                Text = tileBody,
                HintStyle = AdaptiveTextStyle.CaptionSubtle,
                HintWrap = true
              }
            }
          }
        },
        TileWide = new TileBinding()
        {
          Content = new TileBindingContentAdaptive()
          {
            Children =
            {
              new AdaptiveText()
              {
                Text = $"{TileTitle}",
                HintStyle = AdaptiveTextStyle.Caption
              },
              new AdaptiveText()
              {
                Text = tileBody,
                HintStyle = AdaptiveTextStyle.CaptionSubtle,
                HintWrap = true
              }
            }
          }
        }
      }
    };
    var notification = new TileNotification(tileContent.GetXml())
    {
      Tag = tileTag
    };
    UpdateTile(notification);
  }
}

UpdateSample 原本在初始化、 ActivationService StartupAsync 方法中呼叫。我要將它取代成新 UpdateCustomerCount:

private async Task StartupAsync()
{
  Singleton<LiveTileService>.Instance.UpdateCustomerCount(0);
  ThemeSelectorService.SetRequestedTheme();
  await Task.CompletedTask;
}

此時,仍不需要更新的客戶計數。MainViewModel 中取得客戶時,就將發生的情況:

public async Task LoadCustomersAsync()
{
  var customers = await DataService.GetCustomersAsync();
  if (customers != null)
  {
    Customers = new ObservableCollection<Customer>(customers);
    RaisePropertyChanged("Customers");
    Singleton<LiveTileService>.Instance.UpdateCustomerCount(Customers.Count);
  }
}

當我 SalesViewModel 中收到訂單時,將會更新訂單計數:

public async Task LoadDataAsync(MasterDetailsViewState viewState)
{
  var orders = await DataService.GetOrdersAsync();
  if (orders != null)
  {
    Orders = new ObservableCollection<Order>(orders);
    RaisePropertyChanged("Orders");
    Singleton<LiveTileService>.Instance.UpdateOrderCount(Orders.Count);
  }
  if (viewState == MasterDetailsViewState.Both)
  {
    Selected = Orders.FirstOrDefault();
  }
}

我有應用程式中所示圖 13

完成的應用程式
圖 13 完成的應用程式

此應用程式可以顯示客戶和訂單擷取自本機資料庫,動態磚更新與客戶和訂單數。您可以分組、 排序或篩選列出的客戶,顯示使用主版詳細資料檢視的訂單。不會不正確 !

總結

如您所見,UWP 不只是針對小型應用程式。您可以將它用於您的 LOB 應用程式,從許多來源,包括本機的 SQL Server 中取得資料 (及您甚至可以使用 Entity Framework 為 ORM)。與標準的.NET 2.0,您有很多,已在.NET Framework 中,且不會變更,您可以使用 Api 的存取。WTS 讓您快速入門中,幫助您快速並輕鬆地建立使用最佳作法,以您偏好,這些工具,並將 Windows 功能加入至它的應用程式。有很棒的 UI 控制項,來增強應用程式的外觀和應用程式將執行中各種不同的裝置: 在電話、 桌面、 Surface Hub 和甚至不會變更 HoloLens。

部署時,您可以將您的應用程式傳送至存放區和擁有全球探索、 輕鬆安裝和解除安裝並自動更新。如果您不想要部署透過市集,您可以使用 Web (bit.ly/2zH0nZY)。您可以看到,當您必須建立新的 LOB 應用程式的 Windows 中,您一定要列入考慮 UWP,因為它可提供您想要用於這種應用程式和多個很棒的優點是它正在積極開發,並讓大量的所有項目我mprovements 幾年。


Bruno Sonnino自 2007年已 Microsoft 最有價值專家 (MVP)。他是開發人員、 顧問和作者,不必撰寫許多書籍和文章解 Windows 應用程式開發。您可以在 Twitter 上關注他: @bsonnino或讀取他的部落格文章在blogs.msmvps.com/bsonnino

非常感謝下列 Microsoft 技術專家檢閱這篇文章:Clint Rutkas


MSDN Magazine 論壇中的這篇文章的討論