Microsoft-ui-xaml: INotifyDataErrorInfo๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ UWP์— ์ž…๋ ฅ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ์ง€์› ์ถ”๊ฐ€

์— ๋งŒ๋“  2019๋…„ 01์›” 14์ผ  ยท  50์ฝ”๋ฉ˜ํŠธ  ยท  ์ถœ์ฒ˜: microsoft/microsoft-ui-xaml

์ œ์•ˆ: INotifyDataErrorInfo๋กœ ์ž…๋ ฅ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ์ง€์› ์ถ”๊ฐ€

์š”์•ฝ

x:Bind ๋ฐ Binding์—์„œ ์ง€์›ํ•˜๋Š” INotifyDataErrorInfo๋กœ ์ž…๋ ฅ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ์ง€์›์„ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. ๋‘ ๋งˆํฌ์—… ํ™•์žฅ์€ ๊ธฐ๋ณธ์ ์œผ๋กœ WPF์˜ ๋ฐ”์ธ๋”ฉ์—์„œ์™€ ๊ฐ™์ด true์ธ ์ƒˆ ValidatesOnNotifyDataErrors ์†์„ฑ์„ ๊ฐ€์ ธ์™€์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์ด๋ก ์  ํ•ด์„

ํ˜„์žฌ UWP์—๋Š” ํ”Œ๋žซํผ์— ๋‚ด์žฅ๋œ ์ž…๋ ฅ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋ชจ๋“  LOB(Line of Business) ์•ฑ์—๋Š” ์ž…๋ ฅ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ์ ์ ˆํ•œ ์—”ํ„ฐํ”„๋ผ์ด์ฆˆ ์•ฑ์„ ์œ„ํ•œ ๊ฐ€์žฅ ์ค‘์š”ํ•œ ๊ธฐ๋Šฅ ์ค‘ ํ•˜๋‚˜์ž…๋‹ˆ๋‹ค. ์ด ๊ธฐ๋Šฅ์ด WinUI์™€ ํ•จ๊ป˜ ์ œ๊ณต๋œ๋‹ค๋Š” uservoice ํ•ญ๋ชฉ์ด ์žˆ์ง€๋งŒ ์•„์ง ๋ณธ ์ ์ด ์—†์Šต๋‹ˆ๋‹ค. https://wpdev.uservoice.com/forums/110705-universal-windows-platform/suggestions/13052589-uwp-input -ํ™•์ธ

feature proposal needs-winui-3 team-Markup

๊ฐ€์žฅ ์œ ์šฉํ•œ ๋Œ“๊ธ€

INDEI๋Š” ๋ชจ๋“  ์—”ํ„ฐํ‹ฐ์™€ ํ•˜์œ„ ์—”ํ„ฐํ‹ฐ๋ฅผ ๊ตฌํ˜„ํ•˜๋„๋ก ์š”๊ตฌํ•ฉ๋‹ˆ๋‹ค.

์ด์— ๋Œ€ํ•ด ๋” ์ž์„ธํžˆ ์„ค๋ช…ํ•ด ์ฃผ์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?

๊ทœ์น™์„ ์‚ฌ์šฉํ•˜๋ฉด ๋ณ€๊ฒฝํ•  ํ•„์š”๊ฐ€ ์—†์œผ๋ฉฐ ๋ชจ๋‘ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ์†์„ฑ๋งŒ ์‚ฌ์šฉํ•˜์—ฌ ์ž๋™์œผ๋กœ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

๋Œ€๋ถ€๋ถ„์˜ ๊ฒฝ์šฐ ValidationAttributes ๋ฐ INotifyDataErrorInfo ๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ๋„ ๋ชจ๋‘ ์ž๋™์œผ๋กœ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค. ์‚ฌ์–‘์— ์žˆ๋Š” ๋ช‡ ๊ฐ€์ง€ ์ฝ”๋“œ ์Šค๋‹ˆํŽซ์„ ์—ฌ๊ธฐ์— ํ‘œ์‹œํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์šฐ๋ฆฌ๋Š” (๋ฐ”๋ผ๊ฑด๋Œ€) ๊ฐ™์€ ํŽ˜์ด์ง€์— ์žˆ์Šต๋‹ˆ๋‹ค.

FWIW, ์šฐ๋ฆฌ๋Š” ์ด ValidationBase ํด๋ž˜์Šค๋ฅผ Toolkit์— ํฌํ•จํ•  ๊ณ„ํš์ด๋ฏ€๋กœ ์ด ์ƒ์šฉ๊ตฌ ์ฝ”๋“œ๋ฅผ ์ง์ ‘ ์ž‘์„ฑํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

public class ValidationBase : INotifyPropertyChanged, INotifyDataErrorInfo
{
   public event PropertyChangedEventHandler PropertyChanged;
   public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;

   protected void SetValue<T>(ref T currentValue, T newValue, [CallerMemberName] string propertyName = "")
   {
       if (!EqualityComparer<T>.Default.Equals(currentValue, newValue))
       {
           currentValue = newValue;
           OnPropertyChanged(propertyName, newValue);
       }
   }

   readonly Dictionary<string, List<ValidationResult>> _errors = new Dictionary<string, List<ValidationResult>>();
   public bool HasErrors
   {
       get
       {
           return _errors.Any();
       }
   }
   public IEnumerable GetErrors(string propertyName)
   {
       return _errors[propertyName];
   }

   private void OnPropertyChanged(string propertyName, object value)
   {
       PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
       Validate(propertyName, value);
   }

   private void AddErrors(string propertyName, IEnumerable<ValidationResult> results)
   {
       if (!_errors.TryGetValue(propertyName, out List<ValidationResult> errors))
       {
           errors = new List<ValidationResult>();
           _errors.Add(propertyName, errors);
       }

       errors.AddRange(results);
       ErrorsChanged?.Invoke(this, new DataErrorsChangedEventArgs(propertyName));
   }

   private void ClearErrors(string propertyName)
   {
       if (_errors.TryGetValue(propertyName, out List<ValidationResult> errors))
       {
           errors.Clear();
           ErrorsChanged?.Invoke(this, new DataErrorsChangedEventArgs(propertyName));
       }
   }

   public void Validate(string memberName, object value)
   {
       ClearErrors(memberName);
       List<ValidationResult> results = new List<ValidationResult>();
       bool result = Validator.TryValidateProperty(
            value,
            new ValidationContext(this, null, null)
            {
                MemberName = memberName
            },
            results
            );

        if (!result)
        {
            AddErrors(memberName, results);
        }
    }
}

๊ทธ๋Ÿฌ๋ฉด ๋ชจ๋ธ์ด ํ•ด๋‹น ํด๋ž˜์Šค์—์„œ ํŒŒ์ƒ๋˜๊ณ  ๋‹ค์Œ๊ณผ ๊ฐ™์ด ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค.

public class Person : ValidationBase
{
    private string name;
    [MinLength(4)]
    [MaxLength(6)]
    public string Name
    {   
        get { return name; }
        set { SetValue(ref name, value); }
    }
}

์ด Person ํด๋ž˜์Šค๊ฐ€ Page ์˜ ViewModel ์†์„ฑ์œผ๋กœ ์„ค์ •๋˜์–ด ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•˜๋ฉด ์ด์— ๋ฐ”์ธ๋”ฉํ•˜๊ณ  ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๊ฐ€ ์ž๋™์œผ๋กœ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

<TextBox Text="{x:Bind ViewModel.Name, Mode=TwoWay}" />

์ด๊ฒƒ์ด ์˜ค๋Š˜๋‚  ์—ฌ๋Ÿฌ๋ถ„์ด ํ•˜๊ณ  ์žˆ๋Š” ๊ฒƒ๊ณผ ์•ฝ๊ฐ„ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์ดํ•ดํ•˜์ง€๋งŒ, ํ•„์š”ํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ ๋™์ผํ•œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๋‘ ๊ฐ€์ง€ ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์„ ์ง€์›ํ•˜์ง€ ์•Š์œผ๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์ด ๋ง์ด ๋˜๋Š”์ง€, ์•„๋‹ˆ๋ฉด ์•„์ง ์šฐ๋ฆฌ๊ฐ€ ๋†“์น˜๊ณ  ์žˆ๋Š” ๊ฒƒ์ด ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•œ๋‹ค๋ฉด ์•Œ๋ ค์ฃผ์„ธ์š”!

๋ชจ๋“  50 ๋Œ“๊ธ€

@LucasHaines ์ด๊ฒƒ์ด ๋‹น์‹ ์ด ์กฐ์‚ฌํ•œ ์ž…๋ ฅ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ๊ธฐ๋Šฅ๊ณผ ์–ด๋–ค ๊ด€๋ จ์ด ์žˆ์Šต๋‹ˆ๊นŒ?

@jevansaks ์ด๊ฒƒ์€ ๋‚ด๊ฐ€ ์„ค๋ช…ํ•˜๋Š” ์ž…๋ ฅ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ์ž‘์—…๊ณผ ์ง์ ‘ ๊ด€๋ จ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

์—„์ฒญ๋‚œ. ๊ณต์œ ํ•  ๋ฏธ๋ฆฌ ๋ณด๊ธฐ ํ•ญ๋ชฉ์ด ์žˆ์œผ๋ฉด ๊ธฐ๊บผ์ด ์‚ฌ์šฉํ•ด ๋ณด๊ณ  ํ”ผ๋“œ๋ฐฑ๊ณผ ์ƒ๊ฐ์„ ์ œ๊ณตํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

image

์ด๊ฒƒ์€ Build 2018์—์„œ ์–ธ๊ธ‰๋œ ์ผ์ข…์˜ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ์ž…๋‹ˆ๋‹ค.

`
x:Name="์‚ฌ์šฉ์ž ์ด๋ฆ„" ํ—ค๋”="์‚ฌ์šฉ์ž ์ด๋ฆ„:"
Text="{x:๋ฐ”์ธ๋“œ ViewModel.Person.UserName,
UpdateSourceTrigger=์†์„ฑ ๋ณ€๊ฒฝ,
๋ชจ๋“œ=์–‘๋ฐฉํ–ฅ}" />

x:Name="๋น„๋ฐ€๋ฒˆํ˜ธ" ํ—ค๋”="๋น„๋ฐ€๋ฒˆํ˜ธ:"
Password="{x: ViewModel.Person.Password ๋ฐ”์ธ๋”ฉ,
UpdateSourceTrigger=๋กœ์ŠคํŠธํฌ์ปค์Šค,
๋ชจ๋“œ=์–‘๋ฐฉํ–ฅ}"/>
`

@thomasclaudiushuber {Binding}์˜ ์ผ๋ถ€๋กœ ์ด ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฒƒ์ด ์–ผ๋งˆ๋‚˜ ์ค‘์š”ํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ•˜์‹ญ๋‹ˆ๊นŒ? ๊ธฐ์ˆ ์ ์ธ ๋ฌธ์ œ๊ฐ€ ์‚ฌ์†Œํ•˜์ง€ ์•Š๊ณ  ํ•˜์œ„ ์ˆ˜์ค€์—์„œ ์ž‘๋™ํ•  ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์— ๋ฌป์Šต๋‹ˆ๋‹ค. ์šฐ๋ฆฌ์˜ ์›๋ž˜ ์•„์ด๋””์–ด๋Š” ๋งˆํฌ์—… ์ปดํŒŒ์ผ๋Ÿฌ ๋ณ€๊ฒฝ๋งŒ ํ•„์š”ํ•˜๊ณ  ํ•˜์œ„ ์ˆ˜์ค€์—์„œ ์ž‘๋™ํ•  ์ˆ˜ ์žˆ๋Š” x:Bind๋ฅผ ์ง€์›ํ•˜๋Š” ๊ฒƒ์ด์—ˆ์Šต๋‹ˆ๋‹ค.

๋˜ํ•œ INotifyDataErrorInfo ๋ฐ DataAnnotations ํŒจ๋Ÿฌ๋‹ค์ž„๋งŒ ์ง€์›ํ•  ๊ณ„ํš์ด์—ˆ์Šต๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” Binding.ValidationRules์™€ ์œ ์‚ฌํ•œ ๊ฒƒ์„ ์ถ”๊ฐ€ํ•  ์˜๋„๊ฐ€ ์—†์—ˆ์œผ๋ฏ€๋กœ ValidatesOnNotifyDataErrors์— ๋Œ€ํ•œ ์ถฉ๋ถ„ํ•œ ํ•„์š”์„ฑ์„ ๋Š๋ผ์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค.

์ด ๊ธฐ๋Šฅ์ด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ˆ˜ํ–‰๋  ์ˆ˜ ์žˆ๋„๋ก ๊ณ„์† ์ž‘์—…ํ•˜๋ฉด์„œ ํ”ผ๋“œ๋ฐฑ์„ ๋ฐ›๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค!

@stevenbrix

์งง์€ ๋Œ€๋‹ต: ์˜ˆ, ๋‹น์‹ ์ด ์ƒ๊ฐํ•˜๋Š” ๊ฒƒ๊ณผ ๊ณ„ํšํ•œ ๊ฒƒ์ด ํ›Œ๋ฅญํ•˜๊ฒŒ ๋“ค๋ฆฝ๋‹ˆ๋‹ค. x:Bind๋งŒ ๊ดœ์ฐฎ๊ณ  INotifyDataErrorInfo๋„ ๊ดœ์ฐฎ์Šต๋‹ˆ๋‹ค.

๊ธด:

๊ทธ๋ƒฅ x:๋ฐ”์ธ๋“œ? ๐Ÿ‘

๋ชจ๋“  WPF-LOB์˜ ๊ฒฝ์šฐ์—๋Š” ํ•ญ์ƒ ์ปดํŒŒ์ผ ํƒ€์ž„์— ์•Œ๋ ค์ง„ ์ผ์ข…์˜ ViewModel์ด ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ ์˜ค๋ฆฌ ํƒ€์ดํ•‘์ด ์—†์œผ๋ฏ€๋กœ x:Bind๊ฐ€ ์ข‹์Šต๋‹ˆ๋‹ค. WPF์—์„œ์™€ ๋™์ผํ•œ ๊ตฌ๋ฌธ์„ ์–ป์„ ์ˆ˜ ์žˆ๋„๋ก ์ง€์›ํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ์ด ๋ฌธ์ œ์—์„œ๋„ {Binding}์„ ์ž‘์„ฑํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ด๊ฒƒ์€ ๋งค์šฐ ์ค‘์š”ํ•œ ๊ฒƒ๋ณด๋‹ค "์žˆ์œผ๋ฉด ์ข‹์€" ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  {Binding}๊ณผ x:Bind๋Š” ์ด๋ฉด์—์„œ ์™„์ „ํžˆ ๋‹ค๋ฅธ ๋‘ ๊ฐ€์ง€์ด๊ณ  {Binding}์ด ํฌํ•จ๋œ ๋Ÿฐํƒ€์ž„ ํ•ญ๋ชฉ์€ ์–ธ๊ธ‰ํ•œ ๊ฒƒ์ฒ˜๋Ÿผ ์ค‘์š”ํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ {Binding}์€ ์žŠ์–ด๋ฒ„๋ฆฌ์„ธ์š”. x:Bind์šฉ์œผ๋กœ๋งŒ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์€ ๊ดœ์ฐฎ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๋‚ด๊ฐ€ ์ƒ๊ฐํ•  ์ˆ˜ ์žˆ๋Š” ์‚ฌ์šฉ ์‚ฌ๋ก€์—์„œ ์ž‘๋™ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. UWP ๋ฐ x:Bind์— ๋Œ€ํ•œ ๋ชจ๋“  ํšŒ์˜์—์„œ x:Bind๋Š” ๋ชจ๋“  XAML ๊ฐœ๋ฐœ์ž๊ฐ€ ๊ฐ€์žฅ ์ข‹์•„ํ•˜๋Š” UWP ๊ธฐ๋Šฅ ์ค‘ ํ•˜๋‚˜์ด๋ฉฐ "์–ด๋””์—์„œ๋“  ๋ฐ”์ธ๋”ฉ๋ณด๋‹ค x:Bind๋ฅผ ์„ ํ˜ธํ•ฉ๋‹ˆ๋‹ค. ํ•  ์ˆ˜์žˆ๋‹ค". :) Intellisense, perf, step-into-code ๋ฐ compile-time ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด UWP์—์„œ x:Bind๊ฐ€ ์ƒˆ ๊ธฐ๋ณธ๊ฐ’์ด ๋˜๋ฏ€๋กœ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ์ง€์›์„ ๊ฑฐ๊ธฐ์— ๋‘๋Š” ๊ฒƒ์ด ์ข‹๊ณ  ์ข‹์€ ๊ฒฐ์ •์ž…๋‹ˆ๋‹ค.

INotifyDataErrorInfo ๋ฐ DataAnnotations ํŒจ๋Ÿฌ๋‹ค์ž„๋งŒ ์žˆ์Šต๋‹ˆ๊นŒ? ๐Ÿ‘

INotifyDataErrorInfo ๋ฐ DataAnnotations ํŒจ๋Ÿฌ๋‹ค์ž„์„ ์ง€์›ํ•˜๋Š” ๊ฒƒ๋งŒ์œผ๋กœ๋„ ๊ธฐ๋ถ„์ด ์ข‹์Šต๋‹ˆ๋‹ค. WPF๋Š” ๋ฐ์ดํ„ฐ ์ฃผ์„์„ ์ž๋™์œผ๋กœ ์„ ํƒํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ Validator ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ INotifyDataErrorInfo ๊ตฌํ˜„์—์„œ ์ˆ˜๋™์œผ๋กœ ์—ฐ๊ฒฐํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. "DataAnnotations ํŒจ๋Ÿฌ๋‹ค์ž„"์ด๋ผ๊ณ  ํ•  ๋•Œ ์ด๊ฒƒ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๊นŒ? ์•„๋‹ˆ๋ฉด ๊ฐœ๋ฐœ์ž๊ฐ€ ์†์„ฑ์— ๋ฐ์ดํ„ฐ ์ฃผ์„์„ ๋„ฃ์„ ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋Š” ๊ธฐ๋ณธ ์ œ๊ณต DataAnnotation ์ง€์›์„ ๊ณ„ํšํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๊นŒ? ASP.NET Core MVC์—์„œ์ฒ˜๋Ÿผ? ๊ทธ๊ฒŒ ์ข‹๊ฒ ์ง€๋งŒ ํ•„์š”ํ•˜์ง€ ์•Š๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ValidationContext, Validator ๋ฐ ValidationResult ํด๋ž˜์Šค์™€ System.ComponentModel.DataAnnotations์˜ ๋‹ค๋ฅธ ํด๋ž˜์Šค๊ฐ€ ์žˆ์œผ๋ฉด ์ถฉ๋ถ„ํ•ฉ๋‹ˆ๋‹ค.

Binding.ValidationRules๋ฅผ ์ถ”๊ฐ€ํ•˜์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ? ๋…ธ์šฐ ;-)

์•„๋‹ˆ์š”, ํ™•์‹คํžˆ ์ถ”๊ฐ€ํ•˜์ง€ ๋งˆ์‹ญ์‹œ์˜ค. INotifyDataErrorInfo๋Š” ์ถฉ๋ถ„ํ•˜๊ณ  ์ตœ๊ณ ์ž…๋‹ˆ๋‹ค. IDataErrorInfo ์ง€์›์ด WPF์— ์ถ”๊ฐ€๋œ ํ›„ ๋” ์ด์ƒ ValidationRules๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์•˜๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  INotifyDataErrorInfo๊ฐ€ .NET Framework 4.5์— ์ถ”๊ฐ€๋˜์—ˆ์„ ๋•Œ ์ €์™€ ์ œ ๊ณ ๊ฐ์€ ์ž…๋ ฅ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๋ฅผ ์œ„ํ•ด ๋ชจ๋“  ํ”„๋กœ์ ํŠธ์—์„œ ํ•ด๋‹น ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์‚ฌ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด ์ธํ„ฐํŽ˜์ด์Šค๋งŒ ์ง€์›ํ•ด๋„ ๊ดœ์ฐฎ์Šต๋‹ˆ๋‹ค.

ValidatesOnNotifyDataErrors๋ฅผ ์ถ”๊ฐ€ํ•˜์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ? ์•„๋‹ˆ, ํ•˜์ง€๋งŒ...

์˜ˆ, ์ด๊ฒƒ์„ ์ถ”๊ฐ€ํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ Binding.ValidationRules์™€ ์•„๋ฌด ๊ด€๋ จ์ด ์—†์Šต๋‹ˆ๋‹ค. ์ด ์†์„ฑ์€ INotifyDataErrorInfo ์ธํ„ฐํŽ˜์ด์Šค์™€ ์ง์ ‘ ๊ด€๋ จ์ด ์žˆ์Šต๋‹ˆ๋‹ค. WPF์˜ ๋ฐ”์ธ๋”ฉ ๋งˆํฌ์—… ํ™•์žฅ์—์„œ ValidatesOnNotifyDataErrors๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ true์ž…๋‹ˆ๋‹ค. ์ฆ‰, ๋ฐ”์ธ๋”ฉ๋œ ๊ฐœ์ฒด๊ฐ€ ํ•ด๋‹น ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒฝ์šฐ {Binding}์ด ๊ตฌํ˜„๋œ INotifyDataErrorInfo ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๋ฅผ ์„ ํƒํ•ฉ๋‹ˆ๋‹ค. Binding ํƒœ๊ทธ ํ™•์žฅ์˜ ValidatesOnNotifyDataErrors ์†์„ฑ์„ false๋กœ ์„ค์ •ํ•˜๋ฉด Binding ํƒœ๊ทธ ํ™•์žฅ์€ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๋ฅผ ์œ„ํ•ด INotifyDataErrorInfo ๊ตฌํ˜„์„ ์„ ํƒํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ x:Bind๋กœ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ์ด ๊ทธ๋ฆฌ ์–ด๋ ต์ง€ ์•Š์„ ์ˆ˜๋„ ์žˆ์ง€๋งŒ ํ•„์š”ํ•˜์ง€ ์•Š์„ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‹ˆ, ํ•˜์ง€๋งˆ. ์ด๊ฑด ๋นผ๋„ ๊ดœ์ฐฎ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๊ณผ๊ฑฐ์— ์ด๊ฒƒ์ด ํ•„์š”ํ–ˆ๋˜ ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ์„ค๋ช…ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

WPF ์ปจํŠธ๋กค์€ ๊ธฐ๋ณธ์ ์œผ๋กœ Validation.ErrorTemplate์„ ํ†ตํ•ด ์ •์˜๋œ ๋นจ๊ฐ„์ƒ‰ ํ…Œ๋‘๋ฆฌ๋ฅผ ํ‘œ์‹œํ•ฉ๋‹ˆ๋‹ค. ์ด์ œ FirstName ์†์„ฑ์ด ์žˆ๋Š” ํด๋ž˜์Šค๋กœ INotifyDataErrorInfo ๊ตฌํ˜„์ด ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ํ•„์ˆ˜์ด๋ฏ€๋กœ FirstName ์†์„ฑ์ด null์ด๊ฑฐ๋‚˜ ๋น„์–ด ์žˆ์œผ๋ฉด ์˜ค๋ฅ˜๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. ์ด์ œ TextBox๋ฅผ ํ•ด๋‹น FirstName ์†์„ฑ์— ๋ฐ”์ธ๋”ฉํ–ˆ์Šต๋‹ˆ๋‹ค. ์‚ฌ์šฉ์ž๊ฐ€ ํ•ด๋‹น ์ด๋ฆ„์„ ์ œ๊ฑฐํ•˜๋ฉด ๋นจ๊ฐ„์ƒ‰ ํ…Œ๋‘๋ฆฌ๊ฐ€ ๋‚˜ํƒ€๋‚ฉ๋‹ˆ๋‹ค. ํ›Œ๋ฅญํ•ฉ๋‹ˆ๋‹ค. ์ •ํ™•ํžˆ ๋‹น์‹ ์ด ์›ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ UI์˜ ๋‹ค๋ฅธ ์œ„์น˜์— FirstName ์†์„ฑ์—๋„ ๋ฐ”์ธ๋”ฉ๋œ ๋‹ค๋ฅธ ์ปจํŠธ๋กค์ด ์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ํƒญ ํ—ค๋”์˜ TextBlock. WPF๋Š” ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ์˜ค๋ฅ˜๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ ํ•ด๋‹น TextBlock์˜ ๋นจ๊ฐ„์ƒ‰ ํ…Œ๋‘๋ฆฌ์—๋„ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ด๊ฒƒ์€ ๋‹น์‹ ์ด ์›ํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ์‚ฌ์šฉ์ž๊ฐ€ ์ด๋ฆ„์„ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๋Š” TextBox์—์„œ๋งŒ ์˜ค๋ฅ˜๋ฅผ ์›ํ•˜์ง€๋งŒ Tab ํ—ค๋”์˜ TextBlock์—์„œ๋Š” ๊ทธ๋ ‡์ง€ ์•Š์Šต๋‹ˆ๋‹ค. TextBlock์˜ ๋นจ๊ฐ„์ƒ‰ ํ…Œ๋‘๋ฆฌ๋ฅผ ์ œ๊ฑฐํ•˜๋ ค๋ฉด TextBlock์˜ ErrorTemplate์„ ํŽธ์ง‘ํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ๋Œ€์‹  ValidatesOnNotifyDataErrors ์†์„ฑ์„ false๋กœ ์„ค์ •ํ•˜์—ฌ TextBlock-FirstName-Binding์— ๋Œ€ํ•œ INotifyDataErrorInfo ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๋ฅผ ์„ค์ •ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์ด ๋‚ด๊ฐ€ ์ด ์†์„ฑ์— ๋Œ€ํ•ด ๊ฐ€์ง„ ์œ ์ผํ•œ ์‚ฌ์šฉ ์‚ฌ๋ก€์ž…๋‹ˆ๋‹ค. :)

์ด๊ฒŒ ๋„์›€์ด ๋˜๊ธธ ๋ฐ”๋ž€๋‹ค.

์š”์•ฝ

์˜ˆ, ์ „์ ์œผ๋กœ ๋™์˜ํ•ฉ๋‹ˆ๋‹ค. INotifyDataErrorInfo๋ฅผ ์ง€์›ํ•˜๋Š” x:Bind์—์„œ๋งŒ ์ž…๋ ฅ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฒƒ์ด ์ข‹์€ ๊ณ„ํš์ž…๋‹ˆ๋‹ค.

์•„๋‹ˆ์š”, ํ™˜์ƒ์ ์ธ ๊ณ„ํš์ž…๋‹ˆ๋‹ค. ๋ฒŒ์จ๋ถ€ํ„ฐ ๋งค์šฐ ๊ธฐ๋Œ€๋ฉ๋‹ˆ๋‹ค!

@thomasclaudiushuber ์ž์„ธํ•œ ํ›„์† ์กฐ์น˜์— ๊ฐ์‚ฌ๋“œ๋ฆฝ๋‹ˆ๋‹ค! ๋‹น์‹ ์ด ์„ค๋ช…ํ•˜๋Š” ํ•ต์‹ฌ ์‹œ๋‚˜๋ฆฌ์˜ค๋Š” ์šฐ๋ฆฌ๊ฐ€ ์ง„์ •ํ•œ ๊ฐ€์น˜ ๋™์ธ์ด๋ผ๊ณ  ๋ฏฟ๋Š” ๊ฒƒ๊ณผ ๋ผ์ธ์—…์„ ๊ตฌ์„ฑํ•˜๋ฏ€๋กœ ์ข‹์€ ์†Œ์‹์ž…๋‹ˆ๋‹ค. ์ด ๊ธฐ๋Šฅ๊ณผ API์˜ ์ „์ฒด ๋””์ž์ธ์€ ๋Œ€๋ถ€๋ถ„ WPF๊ฐ€ ์ˆ˜ํ–‰ํ•œ ์ด์ „ ์ž‘์—…์œผ๋กœ ์ธํ•ด ์œ ๋™์ ์ด์—ˆ์Šต๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์— ๋ช‡ ๊ฐ€์ง€ ์ค‘์š”ํ•œ ์‚ฌํ•ญ์ด ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

  1. ์œ„์—์„œ ๋…ผ์˜ํ•œ ๋ฐ”์™€ ๊ฐ™์ด WPF์˜ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ์‹œ์Šคํ…œ์—๋Š” ๊ฐ€์น˜๊ฐ€ ์ถ”๊ฐ€๋˜์ง€ ์•Š์•˜๊ฑฐ๋‚˜ ๋” ๋‚˜์€ ํŒจํ„ด์œผ๋กœ ๋Œ€์ฒด๋œ ํŠน์ • ์ธก๋ฉด์ด ์žˆ์—ˆ๊ธฐ ๋•Œ๋ฌธ์— UWP๋กœ ๊ฐ€์ ธ์˜ฌ ๊ณ„ํš์ด ์—†์—ˆ์Šต๋‹ˆ๋‹ค.

  2. WPF ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ์‹œ์Šคํ…œ์˜ ํŠน์ • ๊ธฐ๋Šฅ์€ UWP์— ์—†๋Š” ํ•ต์‹ฌ WPF ๊ธฐ๋Šฅ์„ ํ™œ์šฉํ•ฉ๋‹ˆ๋‹ค. ๊ฐ€์žฅ ์ฃผ๋ชฉํ• ๋งŒํ•œ ๊ฒƒ์€ WPF์˜ ๋ชจ๋“  UIElement๊ฐ€ ์ปจํŠธ๋กค(์ผ๋ถ€ ํ…œํ”Œ๋ฆฟ ๋ถ€๋ถ„ ์ถ”๊ฐ€๋ฅผ ํ†ตํ•ด)๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ์‹œ๊ฐ์  ๊ฐœ์ฒด๋ฅผ ํ‘œ์‹œํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋Š” ํ‘œ์‹œ๊ธฐ ๋ ˆ์ด์–ด์ž…๋‹ˆ๋‹ค.

  3. UWP Xaml์—๋Š” ํ˜„์žฌ ์—ฐ๊ฒฐ๋œ ์ด๋ฒคํŠธ์˜ ๊ฐœ๋…์ด ์—†์œผ๋ฉฐ Validation ํด๋ž˜์Šค๋ฅผ ๋ฏธ๋Ÿฌ๋งํ•˜๋ฉด Validation.Error ์ด๋ฒคํŠธ๊ฐ€ ์ถ”๊ฐ€๋ฉ๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ์€ ๊ฑฐ๋ž˜ ์ฐจ๋‹จ๊ธฐ๊ฐ€ ์•„๋‹ˆ๋ผ ๋ณต์žก์„ฑ์„ ๊ฐ€์ค‘์‹œํ‚ค๊ธฐ ๋•Œ๋ฌธ์— ์ผ๋ฐ˜์ ์œผ๋กœ ์ƒˆ๋กœ์šด ๊ฐœ๋…์„ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์„ ์กฐ์‹ฌํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์–ธ๊ธ‰ํ•  ์‚ฌํ•ญ์ž…๋‹ˆ๋‹ค. ๋˜ํ•œ ์ž‘์—…์—๋Š” ์ปจํŠธ๋กค์˜ ํ…œํ”Œ๋ฆฟ์„ ๋ณ€๊ฒฝํ•ด์•ผ ํ•˜๋ฏ€๋กœ ํŠน์ • ํ…œํ”Œ๋ฆฟ ๋ณ€๊ฒฝ์„ ์ œ๊ณตํ•˜๋Š” ์ปจํŠธ๋กค ์ง‘ํ•ฉ๋งŒ ๊ธฐ๋ณธ์ ์œผ๋กœ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค. ์ผ๋ฐ˜์ ์œผ๋กœ ๋งํ•ด์„œ ์ž‘๋™ํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ด์ง€๋งŒ ์ผ๋ถ€ ์‹œ๋‚˜๋ฆฌ์˜ค์—์„œ๋Š” ์ž‘๋™ํ•˜์ง€ ์•Š๋Š” API๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์€ ์ข‹์€ ์Šต๊ด€์ด ์•„๋‹ˆ๋ฏ€๋กœ ํ•ด๋‹น ๋ชจ๋ธ์—์„œ ๋ถ„๋ฆฌํ•˜๋Š” ๊ฒƒ์ด ๋” ๋‚ซ๋‹ค๊ณ  ์ƒ๊ฐํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ์ปจํŠธ๋กค์ด ๊ตฌํ˜„ํ•˜๋Š” ๊ณตํ†ต ์ธํ„ฐํŽ˜์ด์Šค ๋ฐ/๋˜๋Š” ์†์„ฑ๊ณผ ๊ฐ™์€ ๋‹ค๋ฅธ ๊ฒƒ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

์šฐ๋ฆฌ๋Š” ์—ฌ์ „ํžˆ ์ƒˆ๋กญ๊ณ  ํฅ๋ฏธ๋กœ์šด ์˜คํ”ˆ ์†Œ์Šค ์„ธ๊ณ„์—์„œ API ๋ฐ ์‚ฌ์–‘ ๊ฒ€ํ† ๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์ดํ•ดํ•˜๋Š” ๊ณผ์ •์— ์žˆ์Šต๋‹ˆ๋‹ค. ์ปค๋ฎค๋‹ˆํ‹ฐ์˜ ํ”ผ๋“œ๋ฐฑ์„ ๋ฐ›๊ณ  ์‹ถ๊ธฐ ๋•Œ๋ฌธ์— ๊ณง API ์ œ์•ˆ์„ ๋ฐ›์•„ ์ปค๋ฎค๋‹ˆํ‹ฐ๊ฐ€ ์‚ดํŽด๋ณด๊ณ  ๋ชจ๋‘๊ฐ€ ์—ด๊ด‘ํ•˜๋Š” ๊ฒƒ์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ๊ธฐ๋ฅผ ๋ฐ”๋ž๋‹ˆ๋‹ค!

@stevenbrix ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ๊ธฐ๋Šฅ์— ๋Œ€ํ•œ ์˜คํ”ˆ ์†Œ์Šค ์‚ฌ์–‘์„ ์‹œ์ž‘ํ•  ๋•Œ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๊ฐ€ ์–ด๋–ป๊ฒŒ ๋ณด์ด๋Š”์ง€์— ๋Œ€ํ•œ ์ผ๋Ÿฌ์ŠคํŠธ๋ ˆ์ด์…˜๊ณผ ์ƒ˜ํ”Œ ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ์ œ๊ณตํ•˜์—ฌ ๋Œ€ํ™”๊ฐ€ UI ์ธก๋ฉด์— ๋Œ€ํ•ด ์ข€ ๋” ๊ด‘๋ฒ”์œ„ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ? , ์ฝ”๋”ฉ๋ณด๋‹ค :)

@mdtauk ๋ฌผ๋ก ์ž…๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๊ฐ€ ๊ณต์œ ํ•œ ํ˜„์žฌ UI๋Š” ์—ฌ์ „ํžˆ ์ •ํ™•ํ•ฉ๋‹ˆ๋‹ค. ํ”ผ๋“œ๋ฐฑ์ด ์žˆ๋Š” ๊ฒฝ์šฐ ์ด ์Šค๋ ˆ๋“œ์— ์ž์œ ๋กญ๊ฒŒ ์ œ๊ณตํ•˜์‹ญ์‹œ์˜ค.

@LucasHaines UI๊ฐ€ ์ข‹์•„ ๋ณด์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์˜ค๋ฅ˜๊ฐ€ ํ‘œ์‹œ๋˜๋Š” ๋ฐฉ์‹์„ ์–ด๋–ป๊ฒŒ ์กฐ์ •ํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ๊ถ๊ธˆํ•ฉ๋‹ˆ๋‹ค. ๋‚˜๋Š” ์ด๊ฒƒ์— ๊ด€ํ•ด ์•„๋ฌด ๊ฒƒ๋„ ์ฐพ์ง€ ๋ชปํ–ˆ๊ณ  ๋‹น์‹ ์ด ์ด๋ฏธ ๊ทธ ๋ถ„์•ผ์—์„œ ๊ณต์œ ํ•  ๊ฒƒ์ด ์žˆ๋Š”์ง€ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค. WPF์—์„œ ์ฒจ๋ถ€๋œ Validation.ErrorTemplate ์†์„ฑ๊ณผ ์œ ์‚ฌํ•œ ๊ฒƒ์ด ์žˆ์Šต๋‹ˆ๊นŒ?

์ด์— ๋Œ€ํ•œ ๊ณต์‹์ ์ธ ์‚ฌ์–‘/์ œ์•ˆ์ด ์–ธ์ œ ๋ฐœํ‘œ๋  ๊ฒƒ์ธ์ง€์— ๋Œ€ํ•œ ์ผ์ •์ด ์žˆ์Šต๋‹ˆ๊นŒ?
์ œํ’ˆ์— ๋” ๋นจ๋ฆฌ ์ ์šฉํ•˜๋ ค๋ฉด ์–ด๋–ป๊ฒŒ ํ•ด์•ผ ํ•ฉ๋‹ˆ๊นŒ?

์œ„์˜ @mrlacey ์— ๋™์˜ํ•ฉ๋‹ˆ๋‹ค... ์ด์ œ ์ด๊ฒƒ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ๊ฐ€๋Šฅํ•œ ํ•œ ๋„์›€์„ ๋“œ๋ฆฌ๊ฒŒ ๋˜์–ด ๊ธฐ์ฉ๋‹ˆ๋‹ค.

์šฐ๋ฆฌ๋Š” ๊ณต๊ฐœ ์‚ฌ์–‘์„ ์ž‘์—… ์ค‘์ด๋ฉฐ ์‚ฌ์–‘ ๋ฆฌํฌ์ง€ํ† ๋ฆฌ์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Œ์„ ๋ชจ๋“  ์‚ฌ๋žŒ์—๊ฒŒ ์•Œ๋ฆด ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์งˆ๋ฌธ: IDataErrorInfo๋„ ์ง€์›ํ•˜์ง€ ์•Š๋Š” ์ด์œ ๋Š” ๋ฌด์—‡์ž…๋‹ˆ๊นŒ? .net ํ‘œ์ค€์—์„œ ์ง€์›๋˜๋Š”๋ฐ, ์ง€์›ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์ด ์ด์ƒํ•˜์ง€ ์•Š์„๊นŒ์š”? ์ด๊ฒƒ์€ ๋ฐ”์ธ๋”ฉ์— ์‚ฌ์šฉํ•  ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ปดํŒŒ์ผ ํƒ€์ž„์— ํ™•์ธํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ์‚ฌ๋žŒ๋“ค์˜ ์„ฑ๋Šฅ์— ์˜ํ–ฅ์„ ๋ฏธ์น˜์ง€ ์•Š์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๊ณต๊ฐœ ์‚ฌ์–‘ ๋ฆฌํฌ์ง€ํ† ๋ฆฌ์—์„œ ์ž…๋ ฅ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ์— ๋Œ€ํ•œ ๊ณต๊ฐœ ์‚ฌ์–‘ ๊ฒ€ํ† ๋ฅผ ์‹œ์ž‘ํ–ˆ์Šต๋‹ˆ๋‹ค. https://github.com/Microsoft/microsoft-ui-xaml-specs/pull/26

์•ˆ๋…•ํ•˜์„ธ์š” ์—ฌ๋Ÿฌ๋ถ„, ์šฐ๋ฆฌ๋Š” ์ด๊ฒƒ์„ ์–ด๋–ป๊ฒŒ ์ถ”์ ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๊นŒ? ETA๊ฐ€ ์žˆ์Šต๋‹ˆ๊นŒ?

@knightmeister ์—ฌ๊ธฐ์— ๊ณต๊ฐœ ์‚ฌ์–‘์ด ์ƒ์„ฑ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค . ๊ฒ€ํ† ์— ์ฐธ์—ฌํ•˜๊ณ  ๊ธฐ๋Šฅ์„ ํ˜•์„ฑํ•˜๋Š” ๋ฐ ๋„์›€์„ ์ฃผ์„ธ์š”. ์šฐ๋ฆฌ๋Š” ์ด๊ฒƒ์„ WinUI 3.0์˜ ์ผ๋ถ€๋กœ ์ œ๊ณตํ•  ๊ณ„ํš์ž…๋‹ˆ๋‹ค. WinUI 3.0 ๋กœ๋“œ๋งต์— ๋Œ€ํ•œ ์ž์„ธํ•œ ๋‚ด์šฉ์€ ๋ฌธ์ œ #717์„ ํ™•์ธํ•˜์‹ญ์‹œ์˜ค.

์•ˆ๋…•ํ•˜์„ธ์š” ์—ฌ๋Ÿฌ๋ถ„ - ์‚ฌ์–‘์˜ ์ตœ์‹  ์ƒ˜ํ”Œ์„ ์‚ดํŽด๋ณด์‹ญ์‹œ์˜ค. @stevenbrix ๋Š” ์ƒ˜ํ”Œ์— ๋Œ€ํ•œ ๋ช‡ ๊ฐ€์ง€ ํ›Œ๋ฅญํ•œ ์—…๋ฐ์ดํŠธ๋ฅผ ์ˆ˜ํ–‰ํ•˜๊ณ  ๋‹ค๋ฅธ ํ”ผ๋“œ๋ฐฑ์„ ์ฒ˜๋ฆฌํ–ˆ์Šต๋‹ˆ๋‹ค.

ํ•œ ๊ฐ€์ง€ ์งˆ๋ฌธ: ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ์ •๋ณด๊ฐ€ ์ œ์–ด ๊ณ„์ธต์œผ๋กœ ํ๋ฅผ๊นŒ์š”? ์˜ˆ๋ฅผ ๋“ค์–ด ์ปจํ…Œ์ด๋„ˆ ์ปจํŠธ๋กค(์˜ˆ: TabView ๋˜๋Š” Pivot)์ด ์ž˜๋ชป๋œ ์ƒํƒœ์˜ ์ž์‹ ์ปจํŠธ๋กค์ด ์žˆ์Œ์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

์˜ˆ๋ฅผ ๋“ค์–ด ์ž์‹ ์ปจํŠธ๋กค์ด ์ž˜๋ชป๋œ ์ƒํƒœ์— ์žˆ์„ ๋•Œ Pivot ํ—ค๋”์˜ ์Šคํƒ€์ผ์„ ๋ณ€๊ฒฝํ•˜์—ฌ ๋ทฐ์˜ ์–ด๋Š ๋ถ€๋ถ„์— ์ฃผ์˜๊ฐ€ ํ•„์š”ํ•œ์ง€ ๊ฐ•์กฐ ํ‘œ์‹œํ•˜๋ ค๋Š” ์—ฌ๋Ÿฌ ์ปจํ…Œ์ด๋„ˆ ์ปจํŠธ๋กค์ด ์žˆ๋Š” ๋ณต์žกํ•œ ๋ทฐ๋ฅผ ์ƒ๊ฐํ•ด ๋ณด์‹ญ์‹œ์˜ค.

์ด๊ฒƒ์€ ๋‚˜์—๊ฒŒ ์ค‘์š”ํ•œ ๋ฌธ์ œ์ž…๋‹ˆ๋‹ค.
๋‚ด ์ „์ฒด XAML ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ์‹œ์Šคํ…œ์€ WPF ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ๊ทœ์น™์„ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•˜๋ฉฐ BindingExpression ์—์„œ ํ•„๋“œ์™€ ์—”ํ„ฐํ‹ฐ ๋ชจ๋ธ์„ ์ฝ๊ณ  DA ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ํŠน์„ฑ์— ๋”ฐ๋ผ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ๊ทœ์น™์„ ๋งŒ๋“ญ๋‹ˆ๋‹ค( this ์ฐธ์กฐ).

์˜ˆ๋ฅผ ๋“ค์–ด ์ปจํ…Œ์ด๋„ˆ ์ปจํŠธ๋กค(์˜ˆ: TabView ๋˜๋Š” Pivot)์ด ์ž˜๋ชป๋œ ์ƒํƒœ์˜ ์ž์‹ ์ปจํŠธ๋กค์ด ์žˆ์Œ์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

@tbolon ์˜ˆ, ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋Š” ์ž‘์—…์ด์ง€๋งŒ ํ•ด๋‹น ์ปจํ…Œ์ด๋„ˆ์— ๋‚ด์žฅ๋œ ์ง€์›์ด ์žˆ์„ ๊ฐ€๋Šฅ์„ฑ์€ ๊ฑฐ์˜ ์—†์Šต๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” ์ด ๊ธฐ๋Šฅ์ด ๋‚ด์žฅ๋œ Form ์ปจํŠธ๋กค์„ ๋งŒ๋“œ๋Š” ๊ฒƒ์— ๋Œ€ํ•ด ์ƒ๊ฐํ•ด ๋ณด์•˜์ง€๋งŒ ํ˜„์žฌ๋กœ์„œ๋Š” ์•„๋งˆ๋„ ๋ฐฑ๋กœ๊ทธ์— ์žˆ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. WPF์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ๊ฐ ์ปจํŠธ๋กค์ด ์œ ํšจํ•˜์ง€ ์•Š๊ฑฐ๋‚˜ ์œ ํšจํ•˜์ง€ ์•Š์„ ๋•Œ ๋ฐœ์ƒํ•˜๋Š” ValidationError (์ด๋ฆ„์ด ํ‹€๋ฆด ์ˆ˜ ์žˆ์Œ) ์ด๋ฒคํŠธ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ์ด๋ฒคํŠธ๋Š” ๋ผ์šฐํŠธ๋œ ์ด๋ฒคํŠธ๊ฐ€ ์•„๋‹ˆ๋ฏ€๋กœ ๋“ฃ๊ณ  ์‹ถ์€ ๊ฐ ์š”์†Œ๋ฅผ ๊ตฌ๋…ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๋‚ด ์ „์ฒด XAML ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ์‹œ์Šคํ…œ์€ WPF ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ๊ทœ์น™์„ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•ฉ๋‹ˆ๋‹ค.

@weitzhandler ํ˜„์žฌ ValidationRule ์™€ ๊ฐ™์€ ๊ฒƒ์„ WinUI์— ์ถ”๊ฐ€ํ•  ๊ณ„ํš์ด ์—†์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์„ ์‚ฌ์šฉํ•˜๋ฉด ValidationAttributes ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ๋ชจ๋ธ์ด INotifyDataErrorInfo ๋ฅผ ๊ตฌํ˜„ํ•˜๋„๋ก ํ•˜๋Š” ๊ฒƒ์ด ์žˆ์Šต๋‹ˆ๊นŒ? ์‚ฌ์šฉ ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ๋” ์ž˜ ์ดํ•ดํ•˜๊ธฐ ์œ„ํ•ด ๋ชจ๋ธ๊ณผ XAML์ด ์–ด๋–ป๊ฒŒ ์ƒ๊ฒผ๋Š”์ง€ ๋ณด๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค.

INDEI๋Š” ๋ชจ๋“  ์—”ํ„ฐํ‹ฐ์™€ ํ•˜์œ„ ์—”ํ„ฐํ‹ฐ๋ฅผ ๊ตฌํ˜„ํ•˜๋„๋ก ์š”๊ตฌํ•ฉ๋‹ˆ๋‹ค.
๊ทœ์น™์„ ์‚ฌ์šฉํ•˜๋ฉด ๋ณ€๊ฒฝํ•  ํ•„์š”๊ฐ€ ์—†์œผ๋ฉฐ ๋ชจ๋‘ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ์†์„ฑ๋งŒ ์‚ฌ์šฉํ•˜์—ฌ ์ž๋™์œผ๋กœ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

INDEI๋Š” ๋ชจ๋“  ์—”ํ„ฐํ‹ฐ์™€ ํ•˜์œ„ ์—”ํ„ฐํ‹ฐ๋ฅผ ๊ตฌํ˜„ํ•˜๋„๋ก ์š”๊ตฌํ•ฉ๋‹ˆ๋‹ค.

์ด์— ๋Œ€ํ•ด ๋” ์ž์„ธํžˆ ์„ค๋ช…ํ•ด ์ฃผ์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?

๊ทœ์น™์„ ์‚ฌ์šฉํ•˜๋ฉด ๋ณ€๊ฒฝํ•  ํ•„์š”๊ฐ€ ์—†์œผ๋ฉฐ ๋ชจ๋‘ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ์†์„ฑ๋งŒ ์‚ฌ์šฉํ•˜์—ฌ ์ž๋™์œผ๋กœ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

๋Œ€๋ถ€๋ถ„์˜ ๊ฒฝ์šฐ ValidationAttributes ๋ฐ INotifyDataErrorInfo ๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ๋„ ๋ชจ๋‘ ์ž๋™์œผ๋กœ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค. ์‚ฌ์–‘์— ์žˆ๋Š” ๋ช‡ ๊ฐ€์ง€ ์ฝ”๋“œ ์Šค๋‹ˆํŽซ์„ ์—ฌ๊ธฐ์— ํ‘œ์‹œํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์šฐ๋ฆฌ๋Š” (๋ฐ”๋ผ๊ฑด๋Œ€) ๊ฐ™์€ ํŽ˜์ด์ง€์— ์žˆ์Šต๋‹ˆ๋‹ค.

FWIW, ์šฐ๋ฆฌ๋Š” ์ด ValidationBase ํด๋ž˜์Šค๋ฅผ Toolkit์— ํฌํ•จํ•  ๊ณ„ํš์ด๋ฏ€๋กœ ์ด ์ƒ์šฉ๊ตฌ ์ฝ”๋“œ๋ฅผ ์ง์ ‘ ์ž‘์„ฑํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

public class ValidationBase : INotifyPropertyChanged, INotifyDataErrorInfo
{
   public event PropertyChangedEventHandler PropertyChanged;
   public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;

   protected void SetValue<T>(ref T currentValue, T newValue, [CallerMemberName] string propertyName = "")
   {
       if (!EqualityComparer<T>.Default.Equals(currentValue, newValue))
       {
           currentValue = newValue;
           OnPropertyChanged(propertyName, newValue);
       }
   }

   readonly Dictionary<string, List<ValidationResult>> _errors = new Dictionary<string, List<ValidationResult>>();
   public bool HasErrors
   {
       get
       {
           return _errors.Any();
       }
   }
   public IEnumerable GetErrors(string propertyName)
   {
       return _errors[propertyName];
   }

   private void OnPropertyChanged(string propertyName, object value)
   {
       PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
       Validate(propertyName, value);
   }

   private void AddErrors(string propertyName, IEnumerable<ValidationResult> results)
   {
       if (!_errors.TryGetValue(propertyName, out List<ValidationResult> errors))
       {
           errors = new List<ValidationResult>();
           _errors.Add(propertyName, errors);
       }

       errors.AddRange(results);
       ErrorsChanged?.Invoke(this, new DataErrorsChangedEventArgs(propertyName));
   }

   private void ClearErrors(string propertyName)
   {
       if (_errors.TryGetValue(propertyName, out List<ValidationResult> errors))
       {
           errors.Clear();
           ErrorsChanged?.Invoke(this, new DataErrorsChangedEventArgs(propertyName));
       }
   }

   public void Validate(string memberName, object value)
   {
       ClearErrors(memberName);
       List<ValidationResult> results = new List<ValidationResult>();
       bool result = Validator.TryValidateProperty(
            value,
            new ValidationContext(this, null, null)
            {
                MemberName = memberName
            },
            results
            );

        if (!result)
        {
            AddErrors(memberName, results);
        }
    }
}

๊ทธ๋Ÿฌ๋ฉด ๋ชจ๋ธ์ด ํ•ด๋‹น ํด๋ž˜์Šค์—์„œ ํŒŒ์ƒ๋˜๊ณ  ๋‹ค์Œ๊ณผ ๊ฐ™์ด ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค.

public class Person : ValidationBase
{
    private string name;
    [MinLength(4)]
    [MaxLength(6)]
    public string Name
    {   
        get { return name; }
        set { SetValue(ref name, value); }
    }
}

์ด Person ํด๋ž˜์Šค๊ฐ€ Page ์˜ ViewModel ์†์„ฑ์œผ๋กœ ์„ค์ •๋˜์–ด ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•˜๋ฉด ์ด์— ๋ฐ”์ธ๋”ฉํ•˜๊ณ  ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๊ฐ€ ์ž๋™์œผ๋กœ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

<TextBox Text="{x:Bind ViewModel.Name, Mode=TwoWay}" />

์ด๊ฒƒ์ด ์˜ค๋Š˜๋‚  ์—ฌ๋Ÿฌ๋ถ„์ด ํ•˜๊ณ  ์žˆ๋Š” ๊ฒƒ๊ณผ ์•ฝ๊ฐ„ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์ดํ•ดํ•˜์ง€๋งŒ, ํ•„์š”ํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ ๋™์ผํ•œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๋‘ ๊ฐ€์ง€ ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์„ ์ง€์›ํ•˜์ง€ ์•Š์œผ๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์ด ๋ง์ด ๋˜๋Š”์ง€, ์•„๋‹ˆ๋ฉด ์•„์ง ์šฐ๋ฆฌ๊ฐ€ ๋†“์น˜๊ณ  ์žˆ๋Š” ๊ฒƒ์ด ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•œ๋‹ค๋ฉด ์•Œ๋ ค์ฃผ์„ธ์š”!

๋‹น์‹  ๋ง์ด ๋งž์•„์š”. ํ•˜์ง€๋งŒ ๋‹น์‹ ์˜ ์—”ํ‹ฐํ‹ฐ๋Š” POCO๊ฐ€ ์•„๋‹ˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
ํ•œ๋ฒˆ ํ•ด๋ด์•ผ๊ฒ ๋„ค์š”. LoB ์•ฑ์—์„œ EntityBase ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์€ ๊ทธ๋ฆฌ ๋‚˜์˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ๋‹จ์ง€ POCO๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐ ์ต์ˆ™ํ•ฉ๋‹ˆ๋‹ค.

UWP์—๋Š” *HAVE Validation* ์ด ์—†์Šต๋‹ˆ๋‹ค!!!!!!! ๋ฐฉ๊ธˆ ํ”„๋กœ์ ํŠธ๋ฅผ ์‹œ์ž‘ํ–ˆ์Šต๋‹ˆ๋‹ค. ๋ช‡ ๋…„ ์ „๊นŒ์ง€ WPF๋กœ ๋Œ์•„๊ฐ€์‹ญ์‹œ์˜ค.

@rufw91 ์•Œ์ฃ ?!

๋‹น์‹ ์˜ ์‹œ๊ฐ„ ์ œ์•ฝ์€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ? ์ด๊ฒƒ์˜ ์ฒซ ๋ฒˆ์งธ ๊ตฌํ˜„์€ WinUI3 ์•ŒํŒŒ์— ์žˆ์œผ๋ฉฐ //Build ์‹œ๊ฐ„ ํ”„๋ ˆ์ž„์— ๊ณง ์ œ๊ณต๋  WinUI ๋ฐ์Šคํฌํ†ฑ์— ๋Œ€ํ•œ ๋ฏธ๋ฆฌ ๋ณด๊ธฐ๊ฐ€ ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” ์˜ฌํ•ด ๋ง๊นŒ์ง€ RTM'์„ ํ•  ๊ณ„ํš์ž…๋‹ˆ๋‹ค.

UWP์—๋Š” *HAVE Validation* ์ด ์—†์Šต๋‹ˆ๋‹ค!!!!!!! ๋ฐฉ๊ธˆ ํ”„๋กœ์ ํŠธ๋ฅผ ์‹œ์ž‘ํ–ˆ์Šต๋‹ˆ๋‹ค. ๋ช‡ ๋…„ ์ „๊นŒ์ง€ WPF๋กœ ๋Œ์•„๊ฐ€์‹ญ์‹œ์˜ค.

์•ž์œผ๋กœ ๋ช‡ ๋…„ ๋™์•ˆ WPF๋„ ๊ณ„์† ์‚ฌ์šฉํ•˜๊ธฐ๋กœ ๊ฒฐ์ •ํ–ˆ์Šต๋‹ˆ๋‹ค. ๋‚˜๋Š” ๋ชจ๋“  ์ผ(WPF, SL, WP, UWP ๋“ฑ)์„ ์ˆ˜ํ–‰ํ–ˆ์ง€๋งŒ ๊ฒฐ๊ตญ WPF์ธ ๋‹จ 1๊ฐœ์˜ ๊ธฐ์ˆ ๋งŒ ๊ฒฌ๊ณ ํ•ด ๋ณด์ž…๋‹ˆ๋‹ค. ๋ช‡ ๋…„ ์•ˆ์— WinUI๊ฐ€ ์–ด๋””์— ์žˆ๋Š”์ง€ ํ™•์ธํ•˜๋Š” ๊ฒƒ์ด ํฅ๋ฏธ๋กœ์šธ ์ˆ˜ ์žˆ์ง€๋งŒ ์ƒˆ๋กœ์šด ๊ธฐ์ˆ ๋กœ ์ „ํ™˜ํ•˜๊ณ  ์–ด๋‘  ์†์— ํ™€๋กœ ๋‚จ๊ฒจ์ง€๋Š” ๋ฐ ์ง€์ณค์Šต๋‹ˆ๋‹ค. WPF๋Š” ์„ฑ์ˆ™ํ•˜๊ณ  ํ›Œ๋ฅญํ•˜๊ฒŒ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค. ์•„๋งˆ๋„ ๋ช‡ ๋…„ ์•ˆ์— OS๋กœ์„œ์˜ Windows๋Š” ์ „ํ˜€ ๊ด€๋ จ์ด ์—†์„ ๊ฒƒ์ด๋ฏ€๋กœ ํ”Œ๋žซํผ์— ๋” ๋งŽ์€ ํˆฌ์ž๋ฅผ ํ•˜๊ธฐ ์ „์— ๊ธฐ๋‹ค๋ ค ๋ด…์‹œ๋‹ค.

์•„๋งˆ๋„ ๋ช‡ ๋…„ ์•ˆ์— OS๋กœ์„œ์˜ Windows๋Š” ์ „ํ˜€ ๊ด€๋ จ์ด ์—†์„ ๊ฒƒ์ด๋ฏ€๋กœ ํ”Œ๋žซํผ์— ๋” ๋งŽ์€ ํˆฌ์ž๋ฅผ ํ•˜๊ธฐ ์ „์— ๊ธฐ๋‹ค๋ ค ๋ด…์‹œ๋‹ค.

Windows 10 ์„ค์น˜ ์ˆ˜๊ฐ€ 10์–ต ๊ฐœ๋ฅผ ๋ง‰ ๋„˜์—ˆ๋‹ค๋Š” ์ ์„ ๊ณ ๋ คํ•  ๋•Œ ๊ทธ๊ฒƒ์ด ์‚ฌ์‹ค์ด ๋ ์ง€ ๋ฏฟ๊ธฐ ์–ด๋ ต์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋‚˜๋Š” ํ™•์‹คํžˆ ๋‹น์‹ ์˜ ์ขŒ์ ˆ๊ฐ์„ ๋Š๋ผ๊ณ  WPF์— ๋จธ๋ฌด๋ฅด๋Š” ๊ฒƒ์— ๋Œ€ํ•ด ๋‹น์‹ ์„ ๋น„๋‚œํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. FWIW, ์šฐ๋ฆฌ ํŒ€์€ ์ง€๊ธˆ WPF์˜ ์†Œ์œ ๊ถŒ์„ ๊ฐ€์ง€๊ณ  ์žˆ์œผ๋ฏ€๋กœ ์šฐ๋ฆฌ๊ฐ€ ๊ฑฐ๊ธฐ์—์„œ ํ•˜๋Š” ๊ฒƒ์„ ๋ณด๊ณ  ์‹ถ์€ ๊ฒƒ์ด ์žˆ์œผ๋ฉด ์•Œ๋ ค์ฃผ์‹ญ์‹œ์˜ค.

INDEI๋Š” ๋ชจ๋“  ์—”ํ„ฐํ‹ฐ์™€ ํ•˜์œ„ ์—”ํ„ฐํ‹ฐ๋ฅผ ๊ตฌํ˜„ํ•˜๋„๋ก ์š”๊ตฌํ•ฉ๋‹ˆ๋‹ค.

์ด์— ๋Œ€ํ•ด ๋” ์ž์„ธํžˆ ์„ค๋ช…ํ•ด ์ฃผ์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?

๋‚ด ์ฝ”๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ชจ๋“  POCO ์—”ํ„ฐํ‹ฐ๊ฐ€ ํ•ด๋‹น ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•˜์ง€ ์•Š๊ณ  ๊ธฐ๋ณธ ํด๋ž˜์Šค ์—†์ด ์œ ์ง€๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. INPC๋Š” Fody๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ž๋™์œผ๋กœ ๊ตฌํ˜„๋ฉ๋‹ˆ๋‹ค. ๋” ์„ธ๋ จ๋œ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๊ฐ€ ํ•„์š”ํ•  ๋•Œ IValidatableObject ๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ์ด ๊ฐ€์žฅ ์ข‹์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ํ•˜์œ„ ์œ ํ˜•์—์„œ๋„ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

FWIW, ์šฐ๋ฆฌ๋Š” ์ด ValidationBase ํด๋ž˜์Šค๋ฅผ Toolkit์— ํฌํ•จํ•  ๊ณ„ํš์ด๋ฏ€๋กœ ์ด ์ƒ์šฉ๊ตฌ ์ฝ”๋“œ๋ฅผ ์ง์ ‘ ์ž‘์„ฑํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

๊ทธ๊ฑด ์ข‹์ง€ ์•Š์•„. ๋‚ด ์—”ํ„ฐํ‹ฐ์— ์ด๋ฏธ ๊ธฐ๋ณธ ํด๋ž˜์Šค๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ ์–ด๋–ป๊ฒŒ ํ•ฉ๋‹ˆ๊นŒ? ์ด๊ฒƒ์ด ๋‚ด๊ฐ€ INotifyDataErrorInfo ์˜ ์—ด๋ ฌํ•œ ํŒฌ์ด ์•„๋‹Œ ์ด์œ ์ด๊ธฐ๋„ ํ•ฉ๋‹ˆ๋‹ค. INPC ์†์„ฑ์€ ํŠนํžˆ ์ˆ˜๋งŽ์€ ์—”ํ„ฐํ‹ฐ๊ฐ€ ์žˆ๋Š” ๋Œ€๊ทœ๋ชจ ๋ฐ์ดํ„ฐ ์•ฑ์„ ์ฒ˜๋ฆฌํ•  ๋•Œ ์ด๋ฏธ ๊ณจ์นซ๊ฑฐ๋ฆฌ์ž…๋‹ˆ๋‹ค.

UWP์— ์•„์ง ์ ์ ˆํ•œ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๊ฐ€ ์—†๋‹ค๋Š” ๊ฒƒ์€ ๋งค์šฐ ์ถฉ๊ฒฉ์ ์ž…๋‹ˆ๋‹ค. ์ด๋Š” ๊ฑฐ์˜ ๋ชจ๋“  ์•ฑ์—์„œ ๊ฐ€์žฅ ์ค‘์š”ํ•œ ๊ธฐ๋ณธ ๊ธฐ๋Šฅ์ด๋ฉฐ ์ตœ์šฐ์„  ์ˆœ์œ„๋ฅผ ๋‘์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

UWP์— ์•„์ง ์ ์ ˆํ•œ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๊ฐ€ ์—†๋‹ค๋Š” ๊ฒƒ์€ ๋งค์šฐ ์ถฉ๊ฒฉ์ ์ž…๋‹ˆ๋‹ค. ์ด๋Š” ๊ฑฐ์˜ ๋ชจ๋“  ์•ฑ์—์„œ ๊ฐ€์žฅ ์ค‘์š”ํ•œ ๊ธฐ๋ณธ ๊ธฐ๋Šฅ์ด๋ฉฐ ์ตœ์šฐ์„  ์ˆœ์œ„๋ฅผ ๋‘์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๋„ค, ๊ทธ๋ž˜์„œ ์ €ํฌ๊ฐ€ ๋…ธ๋ ฅํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค :)

๊ทธ๊ฑด ์ข‹์ง€ ์•Š์•„. ๋‚ด ์—”ํ„ฐํ‹ฐ์— ์ด๋ฏธ ๊ธฐ๋ณธ ํด๋ž˜์Šค๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ ์–ด๋–ป๊ฒŒ ํ•ฉ๋‹ˆ๊นŒ?

๋‚˜๋Š” ์—ฌ๊ธฐ์—์„œ ๋‹น์‹ ์˜ ์‚ฌ์šฉ๋ฒ•์„ ์ดํ•ดํ•˜๋ ค๊ณ  ๋…ธ๋ ฅํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๊ธฐ๋ณธ ํด๋ž˜์Šค๋Š” ๋ฌด์—‡์ด๋ฉฐ ์ด ํด๋ž˜์Šค์—์„œ ํŒŒ์ƒ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

๋„ค, ๊ทธ๋ž˜์„œ ์ €ํฌ๊ฐ€ ๋…ธ๋ ฅํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค :)

๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ๊ณผ ๋‚˜๋จธ์ง€ ์ž‘์—….
Needs-winui-3 ๋ ˆ์ด๋ธ”์€ ๋ฌด์—‡์„ ์˜๋ฏธํ•ฉ๋‹ˆ๊นŒ?

๋‚˜๋Š” ์—ฌ๊ธฐ์—์„œ ๋‹น์‹ ์˜ ์‚ฌ์šฉ๋ฒ•์„ ์ดํ•ดํ•˜๋ ค๊ณ  ๋…ธ๋ ฅํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๊ธฐ๋ณธ ํด๋ž˜์Šค๋Š” ๋ฌด์—‡์ด๋ฉฐ ์ด ํด๋ž˜์Šค์—์„œ ํŒŒ์ƒ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

๋‚ด ํด๋ผ์ด์–ธํŠธ์—์„œ ์ƒ์„ฑ๋œ ์—”ํ„ฐํ‹ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๊ธฐ ์œ„ํ•ด OData Connected Service ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.
์ƒ์„ฑ๋œ ๊ฐ์ฒด๋Š” ๋‹ค์Œ ํŒจํ„ด์ž…๋‹ˆ๋‹ค.

c# public abstract partial class ContactBase : Microsoft.OData.Client.BaseEntityType, INotifyPropertyChanged

Needs-winui-3 ๋ ˆ์ด๋ธ”์€ ๋ฌด์—‡์„ ์˜๋ฏธํ•ฉ๋‹ˆ๊นŒ?

@weitzhandler
์ด๋Š” ์ž…๋ ฅ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๊ฐ€ WinUI 3๊ณผ ํ•จ๊ป˜ ์ œ๊ณต๋  ๊ฒƒ์ž„์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. (ํ˜„์žฌ ๊ณ„ํš๋œ ๋Œ€๋กœ 3.0). ์ง€๊ธˆ๊นŒ์ง€ ์œ ์ง€ ๊ด€๋ฆฌ ๋ชจ๋“œ์— ์žˆ๋Š” OS XAML ์ฝ”๋“œ๋ฅผ ๋ณ€๊ฒฝํ•ด์•ผ ํ•˜๋ฏ€๋กœ WinUI 2์—๋Š” ๋‚˜์˜ค์ง€ ์•Š์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

Uno Platform ์•ฑ์—์„œ UWP๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. WinUI๊ฐ€ ์ถœ์‹œ๋˜๋ฉด ๋‹ค๋ฃฐ ๊ฒƒ์ž…๋‹ˆ๋‹ค.
์—…๋ฐ์ดํŠธ ์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค!

๋‚˜๋Š” ์—ฌ๊ธฐ์—์„œ ๋‹น์‹ ์˜ ์‚ฌ์šฉ๋ฒ•์„ ์ดํ•ดํ•˜๋ ค๊ณ  ๋…ธ๋ ฅํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๊ธฐ๋ณธ ํด๋ž˜์Šค๋Š” ๋ฌด์—‡์ด๋ฉฐ ์ด ํด๋ž˜์Šค์—์„œ ํŒŒ์ƒ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

๊ธฐ๋ณธ ํด๋ž˜์Šค๋ฅผ ๊ฐ–๋Š” ๊ฒƒ์€ ์ œ3์ž์— ์˜ํ•ด ์š”๊ตฌ๋˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ์Šต๋‹ˆ๋‹ค(์˜ˆ: ์‚ฌ์šฉํ•˜๋Š” ์ง€์†์„ฑ ํ”„๋ ˆ์ž„์›Œํฌ). UWP/WinUI๋„ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๋ฅผ ์œ„ํ•œ ๊ธฐ๋ณธ ํด๋ž˜์Šค๋ฅผ ์š”๊ตฌํ•˜๋Š” ๊ฒƒ๋„ ์˜ต์…˜์ด ์•„๋‹™๋‹ˆ๋‹ค. ์œ ์šฉํ•˜๋ ค๋ฉด ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ํ•„์š”ํ•˜๋ฉฐ, ์šฐ๋ฆฌ์˜ ์–ด๋–ค ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜๋„ ๊ธฐ๋ณธ ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. (์ฆ‰, ์‚ฌ์šฉํ•˜๋ ค๋Š” ์‚ฌ๋žŒ๋“ค์„ ์œ„ํ•œ ๊ธฐ๋ณธ ํด๋ž˜์Šค๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์—†๋‹ค๋Š” ์˜๋ฏธ๋Š” ์•„๋‹™๋‹ˆ๋‹ค. ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š” ์œ ์ผํ•œ ๋ฐฉ๋ฒ•์ด ์•„๋‹ˆ๋ผ ์„ ํƒ ์‚ฌํ•ญ์ผ ํ•„์š”๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.)

๊ธฐ๋ณธ ํด๋ž˜์Šค๋ฅผ ๊ฐ–๋Š” ๊ฒƒ์€ ์ œ3์ž์— ์˜ํ•ด ์š”๊ตฌ๋˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ์Šต๋‹ˆ๋‹ค(์˜ˆ: ์‚ฌ์šฉํ•˜๋Š” ์ง€์†์„ฑ ํ”„๋ ˆ์ž„์›Œํฌ). UWP/WinUI๋„ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๋ฅผ ์œ„ํ•œ ๊ธฐ๋ณธ ํด๋ž˜์Šค๋ฅผ ์š”๊ตฌํ•˜๋Š” ๊ฒƒ๋„ ์˜ต์…˜์ด ์•„๋‹™๋‹ˆ๋‹ค. ์œ ์šฉํ•˜๋ ค๋ฉด ์ธํ„ฐํŽ˜์ด์Šค๊ฐ€ ํ•„์š”ํ•˜๋ฉฐ, ์šฐ๋ฆฌ์˜ ์–ด๋–ค ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜๋„ ๊ธฐ๋ณธ ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

์กฐ๊ธˆ ๋ฐฑ์—…ํ•ฉ์‹œ๋‹ค. ๋‚ด๊ฐ€ ๋งŒ๋“  ๋งˆ์ง€๋ง‰ ๋ช‡ ๊ฐœ์˜ ๋Œ“๊ธ€์ด ์•ฝ๊ฐ„์˜ ํ˜ผ๋ž€์„ ์ผ์œผ์ผฐ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ์ œ ์ž˜๋ชป์ž…๋‹ˆ๋‹ค.

๋ชจ๋ธ์— ํ•„์š”ํ•œ ๋ชจ๋“  ๊ฒƒ์€ System.ComponentModel.INotifyDataErrorInfo (๋˜๋Š” C++์˜ ๊ฒฝ์šฐ Windows.UI.Xaml.Data.INotifyDataErrorInfo )๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ปดํŒŒ์ผ๋Ÿฌ๋Š” {x:Bind} ๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ๋ทฐ์™€ ์—ฐ๊ฒฐํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ์ ์ ˆํ•˜๊ฒŒ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.

์œ„์—์„œ ์–ธ๊ธ‰ํ•œ ValidationBase ํด๋ž˜์Šค๋Š” INotifyPropertyChanged ์™€ ํ•จ๊ป˜ ์ด๊ฒƒ์„ ๊ตฌํ˜„ํ•˜๋Š” ์ปค๋ฎค๋‹ˆํ‹ฐ ํˆดํ‚ท์— ์ œ๊ณตํ•  ๊ณ„ํš์ด์—ˆ๋˜ ๋„์šฐ๋ฏธ ํด๋ž˜์Šค์ž…๋‹ˆ๋‹ค. ์‚ฌ์šฉ ์‚ฌ๋ก€์—์„œ ํ—ˆ์šฉํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ ํŒŒ์ƒํ•  ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

@stevenbrix์˜ ์„ค๋ช…์— ๊ฐ์‚ฌ๋“œ๋ฆฝ๋‹ˆ๋‹ค.

์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ํŠน์„ฑ ๋ฐ IValidatableObject ๋Š” ์–ด๋–ป์Šต๋‹ˆ๊นŒ? UWP ๋Ÿฐํƒ€์ž„์—์„œ ์ด๋ฅผ ์กด์ค‘ํ•ฉ๋‹ˆ๊นŒ?

์•ž์„œ ์–ธ๊ธ‰ํ•œ MaxLength ์†์„ฑ๊ณผ ๊ฐ™์€ ๋‹ค๋ฅธ ์†์„ฑ์€ ASP.NET์—์„œ์™€ ๊ฐ™์ด TextBox ์ตœ๋Œ€ ๊ธธ์ด๊ฐ€ ์ž๋™์œผ๋กœ ์„ค์ •๋ฉ๋‹ˆ๊นŒ?
DataTypeAttribute , EditableAttribute ์™€ ๋™์ผํ•ฉ๋‹ˆ๋‹ค.
๋˜ํ•œ ํ•„๋“œ ํ—ค๋”๋ฅผ ์ƒ์„ฑํ•˜๊ธฐ ์œ„ํ•œ DisplayAttribute ์ž…๋‹ˆ๋‹ค.
๋‚ด๊ฐ€ ๊ธฐ์–ตํ•˜๋Š” ํ•œ ๊ทธ๊ฒƒ๋“ค์€ ๋ชจ๋‘ Silverlight์—์„œ ์ง€์›๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

( ์ด ์ฐธ์กฐ).

์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ํŠน์„ฑ๊ณผ IValidatableObject๋Š” ์–ด๋–ป์Šต๋‹ˆ๊นŒ? UWP ๋Ÿฐํƒ€์ž„์—์„œ ์ด๋ฅผ ์กด์ค‘ํ•ฉ๋‹ˆ๊นŒ?

๋”ฐ๋ผ์„œ ํ˜„์žฌ Required ์†์„ฑ์„ ์ง€์›ํ•  ์˜ˆ์ •์ž…๋‹ˆ๋‹ค. ์ผ๋ถ€ ์ปจํŠธ๋กค์€ ์ด๊ฒƒ์ด ์‚ฌ์šฉ๋  ๋•Œ ํ—ค๋” ํ…์ŠคํŠธ ์˜†์— ์ž๋™์œผ๋กœ ์ž‘์€ ๋ณ„ํ‘œ๋ฅผ ํ‘œ์‹œํ•ฉ๋‹ˆ๋‹ค. ๋‹น์‹ ์ด ์›ํ•œ๋‹ค๋ฉด ์šฐ๋ฆฌ๋Š” ์•ž์œผ๋กœ ๋” ๋งŽ์€ ๊ฒƒ์„ ์ง€์›ํ•  ์ค€๋น„๊ฐ€ ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ๋” ๋งŽ์€ ๊ฒƒ์„ ๋ณด๊ณ  ์‹ถ์œผ์‹œ๋‹ค๋ฉด ๋ณ„๋„์˜ ๋ฌธ์ œ๋ฅผ ์—ฌ์‹ญ์‹œ์˜ค. ๊ธฐ๋Œ€์น˜๋ฅผ ์„ค์ •ํ•˜๊ธฐ ์œ„ํ•ด ์ถ”๊ฐ€ ์†์„ฑ ์ง€์›์€ ์ดˆ๊ธฐ WinUI3 ๋ฆด๋ฆฌ์Šค๋ฅผ ๋งŒ๋“ค ๊ฐ€๋Šฅ์„ฑ์ด ๊ฑฐ์˜ ์—†์Šต๋‹ˆ๋‹ค.

IValidatableObject ์— ๊ด€ํ•ด์„œ๋Š” ๊ทธ๊ฒƒ์ด ์–ด๋–ป๊ฒŒ ์ž‘๋™ํ•˜๋Š”์ง€ ์ž˜ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค. ์ผ๋ฐ˜ํ™”ํ•˜๋ฉด, ์šฐ๋ฆฌ ์—”์ง„์€ ๋‹จ์ˆœํžˆ INotifyDataErrorInfo.ErrorsChanged ์ด๋ฒคํŠธ๋ฅผ ์ˆ˜์‹ ํ•˜์—ฌ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค. ๋ชจ๋ธ์˜ ์‹ค์ œ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๋Š” ์•ฑ ๊ฐœ๋ฐœ์ž์—๊ฒŒ ๋‹ฌ๋ ค ์žˆ์œผ๋ฉฐ ์ผ๋ฐ˜์ ์œผ๋กœ ๋Œ€์ƒ์—์„œ ์†Œ์Šค๋กœ ๊ฐ’์„ ์ „์†กํ•  ๋•Œ ์ˆ˜ํ–‰๋ฉ๋‹ˆ๋‹ค.

์ œ์•ˆํ•œ ValidationBase ์— ๋Œ€ํ•œ ๋Œ€์•ˆ์œผ๋กœ Validator.TryValidateObject ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ํ”„๋กœ์„ธ์Šค๋ฅผ ์‹คํ–‰ํ•˜๊ณ  ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ๊ฒฐ๊ณผ๋ฅผ ์—”ํ„ฐํ‹ฐ์— ์‚ฝ์ž…ํ•˜์—ฌ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ์•Œ๋ฆฌ๋Š” ํ™•์žฅ ๋ฉ”์„œ๋“œ ์ง‘ํ•ฉ์ด ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ?
์ด๋Ÿฐ ์‹์œผ๋กœ INotifyDataErrorInfo ๋ฅผ ๊ตฌํ˜„ํ•˜๋ฉด ์‰ฝ๊ฒŒ ๋‹ฌ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ ์˜ค๋ฅ˜ ์ปฌ๋ ‰์…˜์„ ๋ณด์œ ํ•˜๋Š” ์†์„ฑ์„ ์ถ”๊ฐ€ํ•˜๋Š” INotifyDataErrorInfo ์—์„œ ์ƒ์†ํ•˜๋Š” ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ UWP ๋Ÿฐํƒ€์ž„ ๋˜๋Š” ๋„๊ตฌ ํ‚คํŠธ๊ฐ€ ๋Œ€์‹  ์ž๋™ํ™”๋œ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ๊ฐ€๋Šฅํ•œ ์—”ํ„ฐํ‹ฐ๋กœ ์ธ์‹ํ•˜๊ณ  ๊ตฌํ˜„๋œ ๊ฒฝ์šฐ ์†์„ฑ์„ ์ž๋™์œผ๋กœ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์•„๋งˆ๋„ ๋‹น์‹ ์ด ์ œ์•ˆํ•œ ValidationBase์— ๋Œ€ํ•œ ๋Œ€์•ˆ์œผ๋กœ Validator.TryValidateObject๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ํ”„๋กœ์„ธ์Šค๋ฅผ ์‹คํ–‰ํ•˜๊ณ  ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ๊ฒฐ๊ณผ๋ฅผ ์—”ํ„ฐํ‹ฐ์— ์ฃผ์ž…ํ•˜์—ฌ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ์•Œ๋ฆฌ๋Š” ํ™•์žฅ ๋ฉ”์„œ๋“œ ์ง‘ํ•ฉ์ด ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์ด๊ฒƒ์€ ์ข‹์€ ์•„์ด๋””์–ด์ž…๋‹ˆ๋‹ค :)

๐Ÿฆ™ ์ƒˆ๋กœ์šด ์†Œ์Šค ์ƒ์„ฑ๊ธฐ ํŒจ๋Ÿฌ๋‹ค์ž„์ด ์—ฌ๊ธฐ์—์„œ๋„ ๋„์›€์ด ๋  ์ˆ˜ ์žˆ๋Š”์ง€ ๊ถ๊ธˆํ•˜์‹ญ๋‹ˆ๊นŒ?

์˜ˆ @michael-hawker, ๋‚˜๋Š” ๋‹น์‹ ์˜ ์ƒ๊ฐ์„ ์ข‹์•„ํ•ฉ๋‹ˆ๋‹ค!

์–ผ๋งˆ ์ „์— ์ƒˆ๋กœ์šด ์†Œ์Šค ์ƒ์„ฑ๊ธฐ ๊ฐ€๋Šฅ์„ฑ์— ๋Œ€ํ•ด ์ฒ˜์Œ ์ฝ์—ˆ์„ ๋•Œ๋„ ๊ฐ™์€ ์ƒ๊ฐ์„ ํ–ˆ์Šต๋‹ˆ๋‹ค.

์ƒˆ๋กœ์šด ์†Œ์Šค ์ƒ์„ฑ๊ธฐ ํŒจ๋Ÿฌ๋‹ค์ž„์„ ์‚ฌ์šฉํ•˜๋ฉด INotifyDataErrorInfo ๋ฐ INotifyPropertyChanged์— ๋Œ€ํ•œ ๋ฐฐํ›„์—์„œ ๋งŽ์€ ๊ฒƒ์„ ๋นŒ๋“œ/์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๋ฅผ ์œ„ํ•œ ๋ฐ์ดํ„ฐ ์ฃผ์„์„ ํฌํ•จํ•˜์—ฌ T4, INotifyPropertyChanged ๋ฐ INotifyDataErrorInfo๋กœ ์ •ํ™•ํžˆ ์ด ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š” Pluralsight์— ๋Œ€ํ•œ WPF ๊ณผ์ •์ด ์žˆ์Šต๋‹ˆ๋‹ค. https://www.pluralsight.com/courses/wpf-mvvm-advanced-model-treatment
์ด ๊ณผ์ •์€ ๋˜ํ•œ ์‚ฌ์šฉ์ž ์ง€์ • ์—ฐ๊ฒฐ๋œ ์†์„ฑ์„ ์‚ฌ์šฉํ•˜์—ฌ ํ•ญ๋ชฉ์„ ์—ฐ๊ฒฐํ•ฉ๋‹ˆ๋‹ค.
์ด ๊ณผ์ •์˜ ๋ชฉํ‘œ๋Š” ๋ชจ๋“  ์ž…๋ ฅ ํ•„๋“œ๊ฐ€ ๋ณ€๊ฒฝ๋˜๊ณ  ์›๋ž˜ ๊ฐ’์ด ๋ฌด์—‡์ธ์ง€ ํ‘œ์‹œํ•˜๋Š” MVVM WPF ์•ฑ์„ ๋นŒ๋“œํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋ณด์—ฌ์ฃผ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๋”ฐ๋ผ์„œ ํ™•์‹คํžˆ ๋ฌด์–ธ๊ฐ€๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋กœ ๋๋‚˜๋Š” ๊ฒƒ(WCT์˜ ์ผ๋ถ€๋กœ)์€ ๊ต‰์žฅํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๋‚˜๋Š” WinUI๋ฅผ ์œ„ํ•ด ๊ทธ ๊ณผ์ •์„ ๋‹ค์‹œ ํ•˜๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค. :)

@rufw91 ์•Œ์ฃ ?!

๋‹น์‹ ์˜ ์‹œ๊ฐ„ ์ œ์•ฝ์€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ? ์ด๊ฒƒ์˜ ์ฒซ ๋ฒˆ์งธ ๊ตฌํ˜„์€ WinUI3 ์•ŒํŒŒ์— ์žˆ์œผ๋ฉฐ //Build ์‹œ๊ฐ„ ํ”„๋ ˆ์ž„์— ๊ณง ์ œ๊ณต๋  WinUI ๋ฐ์Šคํฌํ†ฑ์— ๋Œ€ํ•œ ๋ฏธ๋ฆฌ ๋ณด๊ธฐ๊ฐ€ ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” ์˜ฌํ•ด ๋ง๊นŒ์ง€ RTM'์„ ํ•  ๊ณ„ํš์ž…๋‹ˆ๋‹ค.

@stevenbrix ํฌ๋งํ•ฉ๋‹ˆ๋‹ค. WPF๋กœ ๋‹ค์‹œ ์ „ํ™˜ํ•ด์•ผ ํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด์ œ ๊ฑฐ์˜ ์™„๋ฃŒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

๋‚˜๋Š” ์ด๊ฒƒ์„ ์—ด์—ˆ์Šต๋‹ˆ๋‹ค.

์ด์— ๋Œ€ํ•œ ํ›„์† ์กฐ์น˜๋กœ Twitter์—์„œ @stevenbrix ์™€ ๋Œ€ํ™”ํ•œ ํ›„ ๊ทธ๊ฐ€ ์—ฌ๊ธฐ ์— ์ œ๊ณตํ•œ ๊ธฐ๋ณธ INotifyDataErrorInfo ๊ตฌํ˜„์„ ์ƒˆ๋กœ์šด MVVM ํˆดํ‚ท์— ํฌํ•จ๋˜๋Š” ์ƒˆ๋กœ์šด ObservableValidator ํด๋ž˜์Šค์— ํ†ตํ•ฉํ–ˆ์Šต๋‹ˆ๋‹ค. Microsoft.Toolkit.Mvvm ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ), INotifyPropertyChanged ๋ฐ INotifyPropertyChanging ๋„ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค. ๐Ÿ˜„

์ด๋ฒˆ ํ˜ธ ์—์„œ ๊ด€๋ จ ์ฝ”๋“œ์™€ ํ•ด๋‹น ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์™€ ๊ด€๋ จ๋œ ๋ชจ๋“  ๋‚ด์šฉ์˜ ์š”์•ฝ์„ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
๋˜ํ•œ MVVM Toolkit์˜ ์›๋ž˜ ๋ฌธ์ œ์— ๋Œ€ํ•œ ๋งํฌ์™€ ์ƒˆ๋กœ์šด ๊ฐœ๋ฐœ์ž๋ฅผ ์œ„ํ•œ ์ถ”๊ฐ€ ๋ฌธ์„œ๋„ ํฌํ•จํ–ˆ์Šต๋‹ˆ๋‹ค.

์ด์— ๋Œ€ํ•œ ์ตœ์‹  ์ •๋ณด๋ฅผ ์ œ๊ณตํ•ด ์ฃผ์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ? UWP 10.0 18362๊ฐ€ INotifyDataErrorInfo ๋ฅผ ์ง€์›ํ•˜๋Š”์ง€ ๊ถ๊ธˆํ•ฉ๋‹ˆ๋‹ค. ๋‹ค์Œ ๋ฌธ์„œ ํŽ˜์ด์ง€์— ๋”ฐ๋ฅด๋ฉด https://docs.microsoft.com/en-us/dotnet/api/system.componentmodel.inotifydataerrorinfo?view=netcore-3.1 INotifyDataErrorInfo UWP 10.0์— "์ ์šฉ"๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ UWP 10.0 18362๋ฅผ ์„ค์น˜ํ•˜๊ณ  ๋Œ€์ƒ์œผ๋กœ ์ง€์ •ํ•˜๋ฉด ํ…์ŠคํŠธ ์ƒ์ž์— INotifyDataErrorInfo ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๊ฐ€ ํ‘œ์‹œ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ํ…์ŠคํŠธ ์ƒ์ž๋Š” XAML์—์„œ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์„ค๋ช…๋ฉ๋‹ˆ๋‹ค.

<TextBox Text="{x:Bind ViewModel.Username, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />

๊ทธ๋ฆฌ๊ณ  ์—ฌ๊ธฐ์„œ ReactiveValidationObject ๋ฅผ INotifyDataErrorInfo ๊ตฌํ˜„์œผ๋กœ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

@worldbeater ์ด๊ฒƒ์€ WinUI3์˜ ์ตœ์‹  ๋ฏธ๋ฆฌ ๋ณด๊ธฐ์—์„œ๋งŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์‚ฌ์šฉ ์ค‘์ด์‹ ๊ฐ€์š”?

@stevenbrix ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค! WinUI3๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค. INotifyDataErrorInfo ์™€ UWP๊ฐ€ ๋“œ๋””์–ด ์นœ๊ตฌ๊ฐ€ ๋˜์–ด ๊ธฐ์ฉ๋‹ˆ๋‹ค โœจ

@worldbeater , ์•„์ง ๋ฏธ๋ฆฌ ๋ณด๊ธฐ ๋‹จ๊ณ„์ด๋ฏ€๋กœ ์ด์— ๋Œ€ํ•œ ํ”ผ๋“œ๋ฐฑ์„ ๋ฐ›๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค! ๐Ÿ’ช

๊ทธ๊ฑด ๊ทธ๋ ‡๊ณ  @worldbeater ๋Š” ๋ฌธ์„œ์— UWP 10.0์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ  ๋‚˜์™€ ์žˆ์ง€๋งŒ UWP 10.0์—์„œ ์ง€์›ํ•œ๋‹ค๋Š” ์˜๋ฏธ๋Š” ์•„๋‹™๋‹ˆ๋‹ค. ๋ฌธ์„œ๊ฐ€ ์ถฉ๋ถ„ํžˆ ๋ช…ํ™•ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ด ํŽ˜์ด์ง€๊ฐ€ ๋„์›€์ด ๋˜์—ˆ๋‚˜์š”?
0 / 5 - 0 ๋“ฑ๊ธ‰