Uno Platform とは
UWPベースのコード(C#およびXAML)を書くだけでタイトルにある4プラットフォームで実行できるプラットフォームです。(iOS,Android,WebAssembly)
環境準備
- Visual Studio 2019
以下のワークロードのインストール
- ユニバーサルWindowsプラットフォーム
- .NET デスクトップ開発
- .NET によるモバイル開発
- ASP.NET と Web 開発
実装
手順は公式と同じように進むので英語ですがこちらでも参照できます。
https://platform.uno/docs/articles/getting-started-tutorial-1.html
拡張機能のインストール
拡張機能→拡張機能の管理から 「Uno Platform Solution Templates」を追加し、 vs を再起動します。
プロジェクトの作成
拡張機能追加後にプロジェクトを作成すると、 Un Platform のテンプレートが追加されていますのでそちらを使用します。今回はアプリケーションを作成するので App を選択します。
Nuget のアップデートと追加
ソリューションを選択し以下の3つの nuget をそれぞれ最新にバージョンアップさせます。
- Uno.Core
- Uno.UI
- Uno.Wasm.Bootstrap
ただし、Microsoft.Extensions.Logging.Console は更新しない ようにしてください。
同じくソリューションを選択し以下の Nuget を追加します。
Refractored.MvvmHelpers
フォルダとクラスの作成
プロジェクト名.Shared の中に Models フォルダを作成し、IssueItem.cs を作成します。
同じくプロジェクト名.Shared の中に Converts フォルダを作成し、 StringFormatConverter.cs を作成します。
作成後が以下の画像です。
using System;
using MvvmHelpers;
namespace UnoSampleApp.Shared.Models
{
public class IssueItem : ObservableObject
{
private int id;
public int Id
{
get => id;
set => SetProperty(ref id, value);
}
private IssueType type;
public IssueType Type
{
get => type;
set => SetProperty(ref type, value);
}
private string title;
public string Title
{
get => title;
set => SetProperty(ref title, value);
}
private string description;
public string Description
{
get => description;
set => SetProperty(ref description, value);
}
private IssueStatus status;
public IssueStatus Status
{
get => status;
set => SetProperty(ref status, value);
}
private int effort;
public int Effort
{
get => effort;
set => SetProperty(ref effort, value);
}
private DateTimeOffset createdAt = DateTimeOffset.Now.ToLocalTime();
public DateTimeOffset CreatedAt
{
get => createdAt;
set => SetProperty(ref createdAt, value);
}
private DateTimeOffset? startedAt;
public DateTimeOffset? StartedAt
{
get => startedAt;
set => SetProperty(ref startedAt, value);
}
private DateTimeOffset? completedAt;
public DateTimeOffset? CompletedAt
{
get => completedAt;
set => SetProperty(ref completedAt, value);
}
}
public enum IssueType
{
Bug,
Issue,
Task,
Feature
}
public enum IssueStatus
{
Icebox,
Planned,
WIP,
Done,
Removed
}
}
using System;
using Windows.UI.Xaml.Data;
namespace UnoSampleApp.Shared.Converters
{
public class StringFormatConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
return string.Format(parameter.ToString(), value);
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
throw new NotImplementedException();
}
}
}
MainPage.xaml の変更
以下の通りです。
<Page
x:Class="UnoSampleApp.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:UnoSampleApp"
xmlns:converters="using:UnoSampleApp.Shared.Converters"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:ios="http://nventive.com/ios"
mc:Ignorable="d ios">
<Page.Resources>
<converters:StringFormatConverter x:Key="StringFormatConverter" />
</Page.Resources>
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" RowSpacing="8">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" Orientation="Horizontal" Background="LightGray" Padding="5">
<Canvas Background="Blue" Width="10" x:Name="IssueTypeIndicator" />
<TextBlock Text="{x:Bind Item.Id}" Margin="6,0" VerticalAlignment="Center" />
<ComboBox x:Name="IssueTypeBox"
ItemsSource="{x:Bind IssueTypeList}"
SelectedItem="{x:Bind Item.Type,Mode=TwoWay}"
SelectionChanged="IssueType_SelectionChanged"
PlaceholderText="Enter the Issue Type"
HorizontalAlignment="Stretch"
Margin="10,0,0,0"/>
</StackPanel>
<TextBox Text="{x:Bind Item.Description,Mode=TwoWay}"
Grid.Row="2"
AcceptsReturn="True"
Header="Description"
Height="200"
Margin="10,0"
PlaceholderText="Enter Text Here" />
<TextBlock Text="Planning" FontWeight="Bold" FontSize="16" Grid.Row="3" Margin="10,0" />
<StackPanel Orientation="Horizontal" Grid.Row="4" Margin="10,0" Spacing="20">
<StackPanel Background="LightGray" Padding="20">
<TextBlock Text="Effort" FontWeight="Bold" FontSize="16" Margin="10,0" />
<TextBox Text="{x:Bind Item.Effort,Mode=TwoWay}"
HorizontalTextAlignment="Center"
HorizontalAlignment="Center"
HorizontalContentAlignment="Center"
BorderBrush="Transparent"
Background="Transparent"/>
<Slider Value="{x:Bind Item.Effort,Mode=TwoWay}" Width="100" Minimum="0" Maximum="15" />
</StackPanel>
<StackPanel Background="LightGray"
Padding="20">
<TextBlock Text="Status" FontWeight="Bold" FontSize="16" Margin="10,0" />
<ComboBox ItemsSource="{x:Bind StatusList}"
SelectedItem="{x:Bind Item.Status}"
HorizontalAlignment="Stretch"
SelectionChanged="StatusPicker_SelectionChanged" />
<TextBlock Text="{x:Bind Item.StartedAt,Converter={StaticResource StringFormatConverter},ConverterParameter='Started: {0:MMM dd, yyyy hh:mm tt}',Mode=OneWay}" />
<TextBlock Text="{x:Bind Item.CompletedAt,Converter={StaticResource StringFormatConverter},ConverterParameter='Completed: {0:MMM dd, yyyy hh:mm tt}',Mode=OneWay}" />
</StackPanel>
</StackPanel>
<TextBlock Text="{x:Bind Item.CreatedAt, Converter={StaticResource StringFormatConverter}, ConverterParameter='Created: {0:MMM dd, yyyy hh:mm tt}'}" Grid.Row="5"
Margin="10,0"/>
</Grid>
</Page>
xmlns:local="using:UnoSampleApp"
xmlns:converters="using:UnoSampleApp.Shared.Converters"
ここのコードはそれぞれのプロジェクトに合わせて変更してください。
xaml.cs も併せて変更します。
using System;
using UnoSampleApp.Shared.Models;
using Windows.UI;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409
namespace UnoSampleApp
{
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class MainPage : Page
{
public static readonly DependencyProperty IssueItemProperty =
DependencyProperty.Register(nameof(Item), typeof(IssueItem), typeof(MainPage), new PropertyMetadata(default(IssueItem)));
public MainPage()
{
this.InitializeComponent();
}
public IssueItem Item
{
get => (IssueItem)GetValue(IssueItemProperty);
set => SetValue(IssueItemProperty, value);
}
public IssueStatus[] StatusList => new[]
{
IssueStatus.Icebox,
IssueStatus.Planned,
IssueStatus.WIP,
IssueStatus.Done,
IssueStatus.Removed
};
public IssueType[] IssueTypeList => new[]
{
IssueType.Bug,
IssueType.Feature,
IssueType.Issue,
IssueType.Task
};
protected override void OnNavigatedTo(NavigationEventArgs e)
{
Item = new IssueItem
{
Id = 1232,
Title = "Getting Started",
Description = @"Create a page to enter Issues that we need to work on.
## Acceptance Criteria
- Display the issue Id
- Provide an ability to select the issue Type (i.e. Bug, Feature, etc)
- Include an Issue Title
- Include a full issue description with support for Markdown
- Include an issue effort
- Include an ability for a developer to update the Status (i.e Icebox, WIP, etc)
## Additional Comments
We would like to have a visual indicator for the type of issue as well as something to visualize the effort involved",
Effort = 3,
Status = IssueStatus.WIP,
Type = IssueType.Feature,
CreatedAt = new DateTimeOffset(2019, 04, 03, 08, 0, 0, TimeSpan.FromHours(-8)),
StartedAt = new DateTimeOffset(2019, 04, 30, 08, 0, 0, TimeSpan.FromHours(-8))
};
}
// Sets the time when we Complete or Start an issue.
private void StatusPicker_SelectionChanged(object sender, SelectionChangedEventArgs args)
{
switch (Item.Status)
{
case IssueStatus.Removed:
case IssueStatus.Done:
if (Item.CompletedAt is null)
Item.CompletedAt = DateTimeOffset.Now.ToLocalTime();
break;
case IssueStatus.WIP:
if (Item.StartedAt is null)
Item.StartedAt = DateTimeOffset.Now.ToLocalTime();
break;
default:
Item.StartedAt = null;
Item.CompletedAt = null;
break;
}
}
// Provides a unique color based on the type of Issue
private void IssueType_SelectionChanged(object sender, SelectionChangedEventArgs args)
{
var color = Colors.Red;
switch (IssueTypeBox.SelectedItem)
{
case IssueType.Feature:
color = Colors.Green;
break;
case IssueType.Issue:
color = Colors.Blue;
break;
case IssueType.Task:
color = Colors.Yellow;
break;
}
IssueTypeIndicator.Background = new SolidColorBrush(color);
}
}
}
以上で終了です。
ctrl + F5 で実行しましょう。