티스토리 뷰
2022.02.24 - [WPF] - Microsoft.Toolkit.Mvvm을 이용한 간단한 프레임워크 part2 - Frame Navigation
2022.02.21 - [WPF] - Microsoft.Toolkit.Mvvm을 이용한 간단한 프레임워크 part1
애플리케이션에서 시간이 오래 걸리는 작업을 진행할 때 화면에 Busy...라는 메시지를 출력하면서 전체 화면을 Dim처리하는 방법에 대해서 간단히 알아 보도록 하겠습니다.
1. MainWindow.xaml
MainWindow.xaml에 Busy가 출력되도록 수정합니다.
Busy 상태에서는 화면에 다른 컨트롤을 사용할 수 없도록 Border의 Background 컬러를 추가하고, ViewModel의 IsBusy 프로퍼티와 Converter를 이용해서 Border의 보이기 속성을 변경시켜 줍니다.
<Grid>
<Frame NavigationUIVisibility="Hidden">
<b:Interaction.Behaviors>
<behaviors:FrameBehavior NavigationSource="{Binding NavigationSource, Mode=TwoWay}" />
</b:Interaction.Behaviors>
</Frame>
<Border Background="#66000000" Visibility="{Binding IsBusy, Converter={StaticResource BoolToVisibilityConverter}}">
<Border
HorizontalAlignment="Center"
VerticalAlignment="Center"
Background="White"
CornerRadius="5">
<StackPanel Width="100" Margin="10">
<ProgressBar Height="10" IsIndeterminate="True" />
<TextBlock
Margin="0,5,0,0"
HorizontalAlignment="Center"
Text="Busy..." />
</StackPanel>
<Border.Effect>
<DropShadowEffect />
</Border.Effect>
</Border>
</Border>
</Grid>
2. BoolToVisibilityConverter.cs
간단하게 컨버터를 하나 만들어 줍니다. Mvvm 패턴에서는 컨버터를 사용해야하는 경우가 많기 때문에 만드는 것에 대해서 부담을 가지지 마시고, 필요하면 계속 만들어서 사용합니다.
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
namespace WpfFramework.Converters
{
/// <summary>
/// Bool을 Visibility로 변환해주는 컨버터
/// </summary>
/// <remarks>
/// 컨버터 생성시 꼭 public을 붙여 준다. 디자인 타임에 생성이 않되서, 디자인 타임자체가 출력되지 않을 수 있음
/// </remarks>
public class BoolToVisibilityConverter : IValueConverter
{
/// <summary>
/// True일때 반환할 값 - 반대로 반환해야하는 경우 여기 속성만 변경한 인스턴스를 추가해서 사용한다.
/// </summary>
public Visibility TrueValue { get; set; } = Visibility.Visible;
/// <summary>
/// False일때 반환할 값 - 반대로 반환해야하는 경우 여기 속성만 변경한 인스턴스를 추가해서 사용한다.
/// </summary>
public Visibility FalseValue { get; set; } = Visibility.Collapsed;
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
//value를 boolValue로 형변환
if (value is bool boolValue)
{
//true면 trueValue반환, false이면 falseValue반환
if (boolValue)
{
return TrueValue;
}
else
{
return FalseValue;
}
}
return Binding.DoNothing;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
3. _ConverterRd.xaml
컨버터를 모든 화면에서 사용하기 위해서 리소스 딕셔너리에 추가합니다. 컨버터는 1개를 만들었지만, 리소스에 등록할 때는 정상적인것과 반대되는 것 2개를 만들어서 등록하면 나중에 사용하기에도 좋습니다.
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:converters="clr-namespace:WpfFramework.Converters">
<!-- true이면 보이고, false이면 않보임 -->
<converters:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter" />
<!-- true이면 않보이고, false이면 보임 -->
<converters:BoolToVisibilityConverter
x:Key="BoolToVisibilityReverseConverter"
FalseValue="Visible"
TrueValue="Collapsed" />
</ResourceDictionary>
4. App.xaml 수정
모든 리소스딕셔너리를 App.Resources에 머지를 하면, 모든 화면에서 사용이 가능합니다.
<Application
x:Class="WpfFramework.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfFramework"
StartupUri="/Views/MainWindow.xaml">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/Styles/_ConverterRd.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
5. BusyMessage.cs
Busy 메시지를 추가합니다. 이 메시지를 이용해서 Busy 화면의 보기 속성을 컨트롤 합니다.
using Microsoft.Toolkit.Mvvm.Messaging.Messages;
namespace WpfFramework.Models
{
/// <summary>
/// 비지 메시지
/// </summary>
public class BusyMessage : ValueChangedMessage<bool>
{
/// <summary>
/// BusyId
/// </summary>
public string BusyId { get; set; }
/// <summary>
/// BusyText
/// </summary>
public string BusyText { get; set; }
/// <summary>
/// todtjdwk
/// </summary>
/// <param name="value"></param>
public BusyMessage(bool value) : base(value)
{
}
}
}
6. HomeViewModel.cs
HomePage.xaml에는 버튼을 하나 추가하고, 뷰모델에 아래 코드를 추가해 줍니다.
기본적으로 커맨드는 ICommand를 사용하면됩니다. ICommand에 연결할 인스턴스는 RelayCommand를 이용해서 만들면되는데, 비동기 메소드를 실행해야하는 경우에는 비동기 메소드 전문인 AsyncRelayCommand를 이용하면 편하게 사용할 수 있습니다.
RelayCommand에 대한 자세한 사항은 여기를 참고하시기 바랍니다.
AsyncRelayCommand에 대한 자세한 사항은 여기를 참고하시기 바랍니다.
using Microsoft.Toolkit.Mvvm.Input;
using Microsoft.Toolkit.Mvvm.Messaging;
using System.Threading.Tasks;
using System.Windows.Input;
using WpfFramework.Bases;
using WpfFramework.Models;
namespace WpfFramework.ViewModels
{
public class HomeViewModel : ViewModelBase
{
public static int Count { get; set; }
/// <summary>
/// Busy 테스트 커맨드
/// </summary>
public ICommand BusyTestCommand { get; set; }
/// <summary>
/// 생성자
/// </summary>
public HomeViewModel()
{
Title = "Home";
Init();
}
private void Init()
{
BusyTestCommand = new AsyncRelayCommand(OnBusyTestAsync);
}
/// <summary>
/// OnBusyTest
/// </summary>
/// <returns></returns>
private async Task OnBusyTestAsync()
{
WeakReferenceMessenger.Default.Send(new BusyMessage(true) { BusyId = "OnBusyTestAsync" });
await Task.Delay(5000);
WeakReferenceMessenger.Default.Send(new BusyMessage(false) { BusyId = "OnBusyTestAsync" });
}
public override void OnNavigated(object sender, object navigatedEventArgs)
{
Count++;
Message = $"{Count} Navigated";
}
}
}
7. MainViewModel.cs 수정
추가된 부분에 대해서만 작성을 했습니다. 전체소스는 github를 참고하시기 바랍니다.
/// <summary>
/// Busy 목록
/// </summary>
private IList<BusyMessage> _busys = new List<BusyMessage>();
...
private bool _isBusy;
/// <summary>
/// IsBusy
/// </summary>
public bool IsBusy
{
get { return _isBusy; }
set { SetProperty(ref _isBusy, value); }
}
...
//BusyMessage 수신 등록
WeakReferenceMessenger.Default.Register<BusyMessage>(this, OnBusyMessage);
...
/// <summary>
/// 비지 메시지 수신 처리
/// </summary>
/// <param name="recipient"></param>
/// <param name="message"></param>
private void OnBusyMessage(object recipient, BusyMessage message)
{
if(message.Value)
{
var existBusy = _busys.FirstOrDefault(b => b.BusyId == message.BusyId);
if(existBusy != null)
{
//이미 추가된 녀석이기 때문에 추가하지 않음
return;
}
_busys.Add(message);
}
else
{
var existBusy = _busys.FirstOrDefault(b => b.BusyId == message.BusyId);
if(existBusy == null)
{
//없기 때문에 나감
return;
}
_busys.Remove(existBusy);
}
//_busys에 아이템이 있으면 true, 없으면 false
IsBusy = _busys.Any();
}
8. 실행
실행 후 화면
Busy Test 버튼 클릭 후 화면 5초후에 원래 화면으로 복귀합니다.
9.소스
프로젝트 : WpfFramework, branch part3/add-Busy-function
kaki104/WpfFramework at part3/add-Busy-function (github.com)
'WPF .NET' 카테고리의 다른 글
List vs ObservableCollection? part1 (1) | 2022.03.08 |
---|---|
Microsoft.Toolkit.Mvvm을 이용한 간단한 프레임워크 part4 - LayerPopup 추가 (13) | 2022.03.03 |
ListView, DataGrid에 Group을 추가해서 보여주기 (1) | 2022.02.28 |
개발 시간 단축을 위한 Code Snippet 알아보기 (0) | 2022.02.25 |
Microsoft.Toolkit.Mvvm을 이용한 간단한 프레임워크 part2 - Frame Navigation (13) | 2022.02.24 |
- Total
- Today
- Yesterday
- LINQ
- Microsoft
- ComboBox
- visual studio 2019
- #MVVM
- #uwp
- dotNETconf
- .net
- UWP
- kiosk
- Bot Framework
- Windows 10
- .net 5.0
- PRISM
- uno-platform
- Visual Studio 2022
- C#
- WPF
- MVVM
- Build 2016
- XAML
- #Windows Template Studio
- uno platform
- Always Encrypted
- Cross-platform
- Behavior
- IOT
- windows 11
- #prism
- ef core
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |