dimohy
12월 24, 2022, 12:29오후
1
아들과 단 둘이 대화를 나눌 수 있는 애플리케이션을 만드는 것을 목적으로 슬로그를 시작합니다.
필수 기능
모바일 앱이나 홈페이지, 윈도우 앱 형태 등 자유로운 형태로 대화 서비스를 이용할 수 있어야 함
전개
Uno 플랫폼 사용
DB 사용하지 않음
아들과 대화할 것이므로 로그인에 필요한 정보는 파일 형태로 저장 함
대화 내용도 파일로 저장
Stl.Fusion을 이용해 실시간 기능 구현
최초 버젼은 일단 대화만 잘되도록 함.
화면 구성은 심플하되 깔끔하게 구현. 몇몇 디자인은 아들에게 맡김
필요 기술
메시지 실시간 수신 : Stl.Fusion
메시지 푸시 : Uno ?
인증 : ? (모바일 및 웹어셈블리, 윈도 애플리케이션)
코드명
DnSE (발음 덴스)
5개의 좋아요
dimohy
12월 24, 2022, 12:39오후
3
5개의 좋아요
오, 아드님과 재미난 프로젝트인거 같군요 !
좋아 보입니다
완성 되신 후 기회가 된다면 Flutter로 클론해보겠습니다.
(근데 이렇게 개인 slog에 중간 댓글로 이렇게 끼어들어도 되는건가요?.)
4개의 좋아요
네 그럼요. 개인 슬로그지만 다양한 참여를 환영합니다 ^^
그런데 10살짜리 아들에게 코딩 흥미를 유발하기 위한 프로젝트라… 대단한 것이 아닙니다. ^^;
2개의 좋아요
Uno 플랫폼을 사용하시는군요.
Uno 플랫폼을 사용해 보는 것만으로도 의미가 있을 거 같습니다.
2개의 좋아요
dimohy
12월 27, 2022, 11:29오전
7
스플래시 스크린
플랫폼마다 스플래시 스크린을 보이는 방식이 다르기 때문에 완전 자동은 아닙니다.
먼저 스플래시 스크린으로 사용할 이미지를 Shared
프로젝트의 Assets
디렉토리에 SplashScreen.png
로 배치합니다.
이제 이 이미지는 플랫폼 별도 접근이 되게 됩니다. 안드로이드의 경우 @drawable/assets_splashscreen
로 접근이 되고 웹어셈블리의 경우 스플래시 이미지 경로가 Assets/SplashScreen.png
로 되어 있기 때문에 바로 반영이 됩니다.
Windows의 경우에도 기본 설정되어 있습니다. (그런데 WinUI 3에서는 스플래시 화면이 뜨지는 않는군요…)
안드로이드의 경우 Styles.xml
의 AppTheme
스타일에 다음을 추가해야 합니다.
...
<item name="android:windowSplashScreenAnimatedIcon">@drawable/assets_splashscreen</item>
...
그러면 시작할 때 잘은 보이는데 사이즈가 안맞게 출력되는군요.
스플래시 화면은 플랫폼 마다 사이즈가 다르므로 플랫폼 별로 준비하는것도 방법일 것 같습니다.
https://platform.uno/docs/articles/splash-screen.html?tabs=tabid-vswin
2개의 좋아요
dimohy
12월 28, 2022, 12:53오전
8
테마
테마 시스템은 WinUI의 그것과 같습니다. 테마 자원은 ThemeResource
로 접근할 수 있습니다.
현재 설정된 테마는 FrameworkElement
별 ActualTheme
속성으로 확인할 수 있고 RequestedTheme
속성으로 테마를 지정할 수 있습니다. RequestedTheme
로 설정할 수 있는 테마는 Default, Light, Dark
입니다.
App.Current.RequestedTheme
로 설정이 되면 좋은데요, 처음 앱이 시작할 때만 이 테마 설정이 적용되고 이후 변경하는것은 반영하지 않습니다.
그리고 윈도의 경우 Window.Current
가 null
입니다. 웹어셈블리나 안드로이드에서는 Window.Current
로 적용해야만 테마가 적용됩니다. MainPage
인스턴스의 RequestedTheme
속성을 바꿔도 적용되지 않는데요, 그렇기 떄문에 다음의 코드를 통해 테마를 지정할 수 있습니다.
| MainPage.xaml, 테마 변경 토글
private void ToggleSwitch_Toggled(object sender, RoutedEventArgs e)
{
var root = (FrameworkElement)Window.Current?.Content ?? this;
root.RequestedTheme = themeToggleSwitch.IsOn is false ? ElementTheme.Light : ElementTheme.Dark;
}
테마 테스트 중…
1개의 좋아요
WinUI와의 호환성
Uno 플랫폼은 WinUI의 namespace를 그대로 사용합니다. WinUI를 100% 모두 완전히 지원하지는 않겠지만 이 말은 XAML부터 컨트롤, 세부 구현까지 UWP 및 WinUI 3의 기존 구현된 코드를 거의 그대로 가져다가 쓸 수 있다는 장점이 있습니다.
(물론 UWP 및 WinUI 3의 개발자가 생각보다 많지 않다는 점은 함점입니다. ㅡ.,ㅡ)
어쨌든 그래서 WinUI 개발자라면 Uno 플랫폼의 UI 작업에 허들이 없습니다. .NET Blazor에서 html및 css를 만져야 하는 고통이 있는 분은 Uno 플랫폼을 추천합니다.
1개의 좋아요
dimohy
3월 22, 2023, 12:38오전
10
시간이 꽤 흘렀습니다. 요즘에는 일주일이 하루 지나가는 것 마냥 지나가네요. 벌써 3월도 끝나가고 있습니다.
Uno는 UWP를 이미 한 분이라면 거의 적응 기간 없이 개발 진행이 가능합니다. Microsoft.UI.Xaml.Controls
에 호환되는 XAML 및 컨트롤을 그대로 사용할 수 있기 때문입니다. 또한 WinUI 3을 경험했다면 마찬가지로 바로 개발이 가능합니다.
화면 레이아웃을 구성했습니다.
메시지 목록은 1만개로 데스크톱 앱 형태로 거의 즉시 표시되는 것을 알 수 있었고 웹어셈블리로도 상당히 빠르게 표시되는 것을 확인할 수 있었습니다.
오늘은 메시지 입력 영역을 조명해보겠습니다.
이 부분인데요, 특별한 것은 없지만 나중을 위해 컴포넌트화 했습니다.
| MessageInput.xaml
<UserControl
x:Class="DnSE.Controls.MessageInput"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="using:DnSE.Controls"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid MinHeight="64" MaxHeight="300">
<ScrollViewer Grid.Column="0">
<TextBox
x:Name="messageTextBox"
AcceptsReturn="True"
Text="{x:Bind Message, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
TextWrapping="Wrap">
</TextBox>
</ScrollViewer>
<SplitButton
x:Name="sendButton"
HorizontalAlignment="Right"
VerticalAlignment="Bottom"
Command="{x:Bind SendCommand}">
<SymbolIcon Symbol="Send" />
</SplitButton>
</Grid>
</UserControl>
| MessageInput.xaml.cs
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using System.Windows.Input;
namespace DnSE.Controls;
public sealed partial class MessageInput : UserControl
{
public static readonly DependencyProperty MessageProperty = DependencyProperty.Register(
nameof(Message),
typeof(string),
typeof(MessageInput),
new PropertyMetadata(string.Empty, OnMessageChanged)
);
public static readonly DependencyProperty SendCommandProperty = DependencyProperty.Register(
nameof(SendCommand),
typeof(ICommand),
typeof(MessageInput),
new PropertyMetadata(null)
);
public string Message
{
get => (string)GetValue(MessageProperty);
set => SetValue(MessageProperty, value);
}
public ICommand? SendCommand
{
get => (ICommand)GetValue(SendCommandProperty);
set => SetValue(SendCommandProperty, value);
}
public MessageInput()
{
this.InitializeComponent();
sendButton.IsEnabled = false;
}
private static void OnMessageChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var @this = (d as MessageInput)!;
if (string.IsNullOrEmpty(e.NewValue.ToString()) is true)
@this.sendButton.IsEnabled = false;
else
@this.sendButton.IsEnabled = true;
}
}
Message
및 SendCommand
를 바인딩 할 수 있어서 다음과 같이 사용할 수 있습니다.
| MainPage.xaml
<controls:MessageInput Message="{x:Bind ViewModel.ChatMessage, Mode=TwoWay}" SendCommand="{x:Bind ViewModel.SendCommand}" />
일반적인 XAML의 바인딩과 동일하죠?
5개의 좋아요
@dimohy 아빠와나 연재 기다리고 있었습니다.
2개의 좋아요
UNO 를 선택 하신 특별한 이유가 있는지 궁금 합니다.
MAUI 는 선택지에 없으셨는지도 궁금 하구요 ?
UNO 는 모바일 , 윈도우 전부 커버 되나요 ?
3개의 좋아요
웹 및 앱에서 동작하기를 바라는데 이것을 가장 잘 지원하는 것이 Uno입니다. MAUI의 경우 웹은 안되어요.
넵
3개의 좋아요
자료가 꽤 많이 나오지만, .NET으로 크로스플랫폼을 하는 방법에는 여러가지가 있습니다
MAUI는 그냥 MS공식이라 유명한 것이고 결정적으로 Linux Desktop에서 안됩니다.
하지만 Uno Platform과 AvaloniaUI는 Flutter처럼 다기종 OS에서 동작합니다.
Flutter 같이 호환이 좋은 것과는 별개지만 되긴… 합니다.
2개의 좋아요
MAUI 가 안드로이드는 되자나요
그런데 리눅스 데탑은 안되나요 ?
3개의 좋아요
네 제가 알기론 안됩니다.
추가적으로 MAUI는 Pixel Perfect 가 아닙니다.
Uno Platform과 AvaloniaUI는 Pixel Perfect 입니다.
Slack처럼 OS를 변경해도 똑같이 생겼다는 뜻입니다.
3개의 좋아요
MVVM 구조로 만들기 위해 Uno 프로젝트 템플릿에서 최근에 도입된 마법사 기능 을 활용해 보려 했는데 {x:bind}
는 지원하지 않는 것 같아 (아직 몰라서일 수도 있습니다) 그냥 Community Toolkit MVVM의 Ioc를 이용했습니다.
| App.cs
public class App : Application
{
public App()
{
Ioc.Default.ConfigureServices(ConfigureServices());
}
...
private IServiceProvider ConfigureServices() => new ServiceCollection()
.AddTransient<MainViewModel>()
.BuildServiceProvider();
}
| MainPage.xaml.cs
public sealed partial class MainPage : Page
{
private MainViewModel ViewModel { get; } = Ioc.Default.GetRequiredService<MainViewModel>();
public MainPage()
{
this.InitializeComponent();
}
}
1개의 좋아요