첨부 실행 코드는 나눔고딕코딩 폰트를 사용합니다.
유용한 소스 코드가 있으면 icodebroker@naver.com으로 보내주시면 감사합니다.
블로그 자료는 자유롭게 사용하세요.

■ Binding 태그 확장 : IDataErrorInfo 인터페이스를 이용해 바인딩 에러 처리하기

------------------------------------------------------------------------------------------------------------------------

Product.cs

 

 

using System;

using System.Collections.Generic;

using System.ComponentModel;

 

/// <summary>

/// 제품

/// </summary>

public class Product : IDataErrorInfo

{

    //////////////////////////////////////////////////////////////////////////////////////////////////// Field

    ////////////////////////////////////////////////////////////////////////////////////////// Private

 

    #region Field

 

    /// <summary>

    /// 에러 사전

    /// </summary>

    private Dictionary<string, List<string>> errorDictionary = new Dictionary<string, List<string>>();

 

    /// <summary>

    /// ID 에러 메시지

    /// </summary>

    private const string ID_ERROR_MESSAGE = "Value cannot be less than 5.";

 

    /// <summary>

    /// ID 경고 메시지

    /// </summary>

    private const string ID_WARNING_MESSAGE = "Value should not be less than 10.";

 

    /// <summary>

    /// 명칭 에러 메시지

    /// </summary>

    private const string NAME_ERROR_MESSAGE = "Value must not contain any spaces.";

 

    /// <summary>

    /// 명칭 경고 메시지

    /// </summary>

    private const string NAME_WARNING_MESSAGE = "Value should be 5 characters or less.";

 

    /// <summary>

    /// ID

    /// </summary>

    private int id;

 

    /// <summary>

    /// 명칭

    /// </summary>

    private string name;

 

    #endregion

 

    //////////////////////////////////////////////////////////////////////////////////////////////////// Property

    ////////////////////////////////////////////////////////////////////////////////////////// Public

 

    // IDataErrorInfo

    #region 에러 - Error

 

    /// <summary>

    /// 에러

    /// </summary>

    public string Error

    {

        get

        {

            throw new NotImplementedException();

        }

    }

 

    #endregion

 

    // IDataErrorInfo

    #region 인덱서 - this[propertyName]

 

    /// <summary>

    /// 인덱서

    /// </summary>

    /// <param name="propertyName">속성명</param>

    /// <returns>메시지</returns>

    public string this[string propertyName]

    {

        get

        {

            return (!this.errorDictionary.ContainsKey(propertyName) ? null :

                string.Join(Environment.NewLine, this.errorDictionary[propertyName]));

        }

    }

 

    #endregion

 

 

    #region ID - ID

 

    /// <summary>

    /// ID

    /// </summary>

    public int ID

    {

        get

        {

            return this.id;

        }

        set

        {

            if(IsIDValid(value) && this.id != value)

            {

                this.id = value;

            }

        }

    }

 

    #endregion

 

    #region 명칭 - Name

 

    /// <summary>

    /// 명칭

    /// </summary>

    public string Name

    {

        get

        {

            return this.name;

        }

        set

        {

            if(IsNameValid(value) && this.name != value)

            {

                this.name = value;

            }

        }

    }

 

    #endregion

 

    //////////////////////////////////////////////////////////////////////////////////////////////////// Method

    ////////////////////////////////////////////////////////////////////////////////////////// Public

 

    #region ID 무결성 여부 조사하기 - IsIDValid(id)

 

    /// <summary>

    /// ID 무결성 여부 조사하기

    /// </summary>

    /// <param name="id">ID</param>

    /// <returns>ID 무결성 여부</returns>

    public bool IsIDValid(int id)

    {

        bool isValid = true;

 

        if(id < 5)

        {

            AddError("ID", ID_ERROR_MESSAGE, false);

 

            isValid = false;

        }

        else

        {

            RemoveError("ID", ID_ERROR_MESSAGE);

        }

 

        if(id < 10)

        {

            AddError("ID", ID_WARNING_MESSAGE, true);

        }

        else

        {

            RemoveError("ID", ID_WARNING_MESSAGE);

        }

 

        return isValid;

    }

 

    #endregion

 

    #region 명칭 무결성 여부 조사하기 - IsNameValid(name)

 

    /// <summary>

    /// 명칭 무결성 여부 조사하기

    /// </summary>

    /// <param name="name">명칭</param>

    /// <returns>명칭 무결성 여부</returns>

    public bool IsNameValid(string name)

    {

        bool isValid = true;

 

        if(name.Contains(" "))

        {

            AddError("Name", NAME_ERROR_MESSAGE, false);

 

            isValid = false;

        }

        else

        {

            RemoveError("Name", NAME_ERROR_MESSAGE);

        }

 

        if(name.Length > 5)

        {

            AddError("Name", NAME_WARNING_MESSAGE, true);

        }

        else

        {

            RemoveError("Name", NAME_WARNING_MESSAGE);

        }

 

        return isValid;

    }

 

    #endregion

 

    #region 에러 추가하기 - AddError(propertyName, message, isWarning)

 

    /// <summary>

    /// 에러 추가하기

    /// </summary>

    /// <param name="propertyName">속성명</param>

    /// <param name="message">메시지</param>

    /// <param name="isWarning">경고 여부</param>

    public void AddError(string propertyName, string message, bool isWarning)

    {

        if(!this.errorDictionary.ContainsKey(propertyName))

        {

            this.errorDictionary[propertyName] = new List<string>();

        }

 

        if(!this.errorDictionary[propertyName].Contains(message))

        {

            if(isWarning)

            {

                this.errorDictionary[propertyName].Add(message);

            }

            else

            {

                this.errorDictionary[propertyName].Insert(0, message);

            }

        }

    }

 

    #endregion

 

    #region 에러 제거하기 - RemoveError(propertyName, message)

 

    /// <summary>

    /// 에러 제거하기

    /// </summary>

    /// <param name="propertyName">속성명</param>

    /// <param name="message">메시지</param>

    public void RemoveError(string propertyName, string message)

    {

        if(this.errorDictionary.ContainsKey(propertyName) && this.errorDictionary[propertyName].Contains(message))

        {

            this.errorDictionary[propertyName].Remove(message);

 

            if(this.errorDictionary[propertyName].Count == 0)

            {

                this.errorDictionary.Remove(propertyName);

            }

        }

    }

 

    #endregion

}

 

 

MainPage.xaml.cs

 

 

using System.Windows.Controls;

using System.Windows.Input;

 

...

 

#region 생성자 - MainPage()

 

/// <summary>

/// 생성자

/// </summary>

public MainPage()

{

    InitializeComponent();

 

    this.grid.DataContext = new Product() { ID = 10, Name = "food" };

}

 

#endregion

 

...

 

#region 텍스트 박스 키 다운시 처리하기 - TextBox_KeyDown(sender, e)

 

/// <summary>

/// 텍스트 박스 키 다운시 처리하기

/// </summary>

/// <param name="sender">이벤트 발생자</param>

/// <param name="e">이벤트 인자</param>

private void TextBox_KeyDown(object sender, KeyEventArgs e)

{

    if(e.Key == Key.Enter)

    {

        (sender as TextBox).GetBindingExpression(TextBox.TextProperty).UpdateSource();

    }

}

 

#endregion

 

 

MainPage.xaml

 

 

<Grid x:Name="grid"

    xmlns:input="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data.Input"

    Margin="10"

    Background="White">

    <Grid.RowDefinitions>

        <RowDefinition Height="Auto" />

        <RowDefinition Height="Auto" />

        <RowDefinition Height="Auto" />

        <RowDefinition Height="Auto" />

        <RowDefinition Height="Auto" />

    </Grid.RowDefinitions>

    <Grid.ColumnDefinitions>

        <ColumnDefinition Width="Auto" />

        <ColumnDefinition Width="200" />

        <ColumnDefinition Width="Auto" />

    </Grid.ColumnDefinitions>

    <TextBlock Grid.Row="0" Grid.Column="1"

        Margin="3"

        FontWeight="Bold"

        Text="Product" />

    <input:Label Grid.Row="1" Grid.Column="0"

        Margin="3"

        HorizontalAlignment="Right"

        Target="{Binding ElementName=idTextBox}" />

    <TextBox x:Name="idTextBox" Grid.Row="1" Grid.Column="1"

        Margin="3"

        MaxLength="5"

        Text="{Binding ID,

            Mode=TwoWay,

            ValidatesOnExceptions=True,

            ValidatesOnDataErrors=True,

            NotifyOnValidationError=True}"

        KeyDown="TextBox_KeyDown" />

    <input:DescriptionViewer Grid.Row="1" Grid.Column="2"

        Description="ID must be greater than 4 and should be greater than 9." />

    <input:Label Grid.Row="2" Grid.Column="0"

        Margin="3"

        HorizontalAlignment="Right"

        Target="{Binding ElementName=nameTextBox}" />

    <TextBox x:Name="nameTextBox" Grid.Row="2" Grid.Column="1"

        Margin="3"

        MaxLength="10"

        Text="{Binding Name, Mode=TwoWay,

            ValidatesOnExceptions=True,

            ValidatesOnDataErrors=True,

            NotifyOnValidationError=True}"

        KeyDown="TextBox_KeyDown" />

    <input:DescriptionViewer Grid.Row="2" Grid.Column="2"

        Description="Name must not contain spaces and should be 5 characters or less." />

    <input:ValidationSummary Grid.Row="3" Grid.ColumnSpan="2"

        Margin="3" />

</Grid>

 

------------------------------------------------------------------------------------------------------------------------

※ ValidatesOnExceptions 속성을 설정하는 이유는 IDataErrorInfo 인터페이스에서 처리하는 무결성 조사 외에 예외가 발생하는 경우도 표시하기 위한 것이다.

※ NotifyOnValidationError 속성을 설정하는 이유는 ValidationSummary 엘리먼트에 에러 정보를 표시하기 위한 것이다.

Posted by 사용자 icodebroker
TAG

댓글을 달아 주세요