BLOG ARTICLE MVVM | 2 ARTICLE FOUND

  1. 2009.09.25 WPF MVVM 패턴에서 RadioButton 사용하기 (2)
  2. 2009.09.14 WPF RadioButtons in MVVM... (3)

소스 관리의 편의 문제로 현재 주석은 영어로 작성되어 있습니다.

MVVM 패턴에서 RadioButton을 사용하는 것은 생각보다 까다로울 수 있습니다.
예를 들어, 다음처럼 2개의 RadioButton을 사용하는 간단한 UI를 만든다고 가정해 보겠습니다.

2개의 RadioButton을 사용하는 아주 간단한 UI.


보통 맨 처음의 시도는 뷰를 다음처럼 만드는 것입니다:
...
<GroupBox Header="I love">
    <StackPanel>
        <RadioButton IsChecked="{Binding IsPeaceLover}">Peace</RadioButton>
        <RadioButton>Earth</RadioButton>
    </StackPanel>
</GroupBox>
...
그리고 뷰모델은 이렇게 할 것입니다:
class UserViewModel : ViewModelBase
{
    bool isPeaceLover = true;

    public bool IsPeaceLover
    {
        get { return this.isPeaceLover; }
        set
        {
            if (this.isPeaceLover == value)
                return;

            this.isPeaceLover = value;
            OnPropertyChanged("IsPeaceLover");
        }
    }
    ...
}
그러나 이미 알고 계시듯이 이렇게 작성하면 제대로 동작하지 않습니다.
구글 검색에서는 이 문제를 해결하는 여러 방법들을 소개하고 있지만, MVVM에 적합한 방법은 없더군요. (코드 비하인드를 안쓰는 방법) 
그래서 나름 고민 끝에 나온 결론은 뷰를 다음처럼 작성하는 것이었습니다:
...
<GroupBox Header="I love">
    <StackPanel>
        <RadioButton IsChecked="{Binding IsPeaceLover}">Peace</RadioButton>
        <RadioButton IsChecked="{Binding IsEarthLover}">Earth</RadioButton>
    </StackPanel>
</GroupBox>
...
그리고 뷰모델은 이렇게 작성합니다:
class UserViewModel : ViewModelBase
{
    bool isPeaceLover = true;

    public bool IsPeaceLover
    {
        get { return this.isPeaceLover; }
        set
        {
            if (this.isPeaceLover == value)
                return;

            this.isPeaceLover = value;
            OnPropertyChanged("IsPeaceLover", "IsEarthLover");
        }
    }

    public bool IsEarthLover
    {
        get { return !IsPeaceLover; }
        set { IsPeaceLover = !value; }
    }
    ...
}
만약 선택 항목이 2개 이상인 경우에는 다음처럼 응용해서 작성하시면 됩니다:
public enum Priority
{
    Low,
    Middle,
    High,
}

class JobViewModel : ViewModelBase
{
    Priority priority = Priority.Low;

    public Priority Priority
    {
        get { return this.priority; }
        set
        {
            if (this.priority == value)
                return;

            this.priority = value;
            OnPropertyChanged("Priority"
                     , "IsLowPriority", "IsMiddlePriority", "IsHighPriority");
        }
    }

    public bool IsLowPriority
    {
        get { return Priority == Priority.Low; }
        set { Priority = value ? Priority.Low : Priority; }
    }

    public bool IsMiddlePriority
    {
        get { return Priority == Priority.Middle; }
        set { Priority = value ? Priority.Middle : Priority; }
    }

    public bool IsHighPriority
    {
        get { return Priority == Priority.High; }
        set { Priority = value ? Priority.High : Priority; }
    }
}
...
<GroupBox Header="Priority">
    <StackPanel>
        <RadioButton IsChecked="{Binding IsLowPriority}">Low</RadioButton>
        <RadioButton IsChecked="{Binding IsMiddlePriority}">Middle</RadioButton>
        <RadioButton IsChecked="{Binding IsHighPriority}">High</RadioButton>
    </StackPanel>
</GroupBox>
...


YOUR COMMENT IS THE CRITICAL SUCCESS FACTOR FOR THE QUALITY OF BLOG POST
  1. Favicon of http://witstudio.net BlogIcon 김대욱 2010.01.07 02:42  댓글주소  수정/삭제  댓글쓰기

    좋은 아티클 잘읽었습니다^^

    ListBox Template을 이용해, 비하인드 코드를 사용하지 않고,
    다수의 RadioButton 목록을 구현하는 방법에 대한 아티클 주소를 남깁니다..
    http://witstudio.net/tutorial.html?article_no=23




If you try to use RadioButtons as usual in MVVM, it will not work as you expect.
For example, here is a very simple UI using two RadioButtons.

A very simple UI using two RadioButtons.


My first attempt is to use this View:
...
<GroupBox Header="I love">
    <StackPanel>
        <RadioButton IsChecked="{Binding IsPeaceLover}">Peace</RadioButton>
        <RadioButton>Earth</RadioButton>
    </StackPanel>
</GroupBox>
...
and this ViewModel:
class UserViewModel : ViewModelBase
{
    bool isPeaceLover = true;

    public bool IsPeaceLover
    {
        get { return this.isPeaceLover; }
        set
        {
            if (this.isPeaceLover == value)
                return;

            this.isPeaceLover = value;
            OnPropertyChanged("IsPeaceLover");
        }
    }
    ...
}
But as you may know, it doesn't work. There are many solutions to avoid this problem.
Anyway, I've created a new pattern that is more appropriate to MVVM (not using Code-Behind).
Try this View:
...
<GroupBox Header="I love">
    <StackPanel>
        <RadioButton IsChecked="{Binding IsPeaceLover}">Peace</RadioButton>
        <RadioButton IsChecked="{Binding IsEarthLover}">Earth</RadioButton>
    </StackPanel>
</GroupBox>
...
and this ViewModel:
class UserViewModel : ViewModelBase
{
    bool isPeaceLover = true;

    public bool IsPeaceLover
    {
        get { return this.isPeaceLover; }
        set
        {
            if (this.isPeaceLover == value)
                return;

            this.isPeaceLover = value;
            OnPropertyChanged("IsPeaceLover", "IsEarthLover");
        }
    }

    public bool IsEarthLover
    {
        get { return !IsPeaceLover; }
        set { IsPeaceLover = !value; }
    }
    ...
}
If you have more options user can choose, you can extend the pattern like this:
public enum Priority
{
    Low,
    Middle,
    High,
}

class JobViewModel : ViewModelBase
{
    Priority priority = Priority.Low;

    public Priority Priority
    {
        get { return this.priority; }
        set
        {
            if (this.priority == value)
                return;

            this.priority = value;
            OnPropertyChanged("Priority"
                     , "IsLowPriority", "IsMiddlePriority", "IsHighPriority");
        }
    }

    public bool IsLowPriority
    {
        get { return Priority == Priority.Low; }
        set { Priority = value ? Priority.Low : Priority; }
    }

    public bool IsMiddlePriority
    {
        get { return Priority == Priority.Middle; }
        set { Priority = value ? Priority.Middle : Priority; }
    }

    public bool IsHighPriority
    {
        get { return Priority == Priority.High; }
        set { Priority = value ? Priority.High : Priority; }
    }
}
...
<GroupBox Header="Priority">
    <StackPanel>
        <RadioButton IsChecked="{Binding IsLowPriority}">Low</RadioButton>
        <RadioButton IsChecked="{Binding IsMiddlePriority}">Middle</RadioButton>
        <RadioButton IsChecked="{Binding IsHighPriority}">High</RadioButton>
    </StackPanel>
</GroupBox>
...


YOUR COMMENT IS THE CRITICAL SUCCESS FACTOR FOR THE QUALITY OF BLOG POST
  1. bob 2011.08.16 02:18  댓글주소  수정/삭제  댓글쓰기

    ...srlsy? it works if you have two choice but 99% of use cases you have more than two choices and then your solution is useless. Worst than that, if you app evolve (new need) you have to redo it totally and choose another solution. Sorry but a good developer should consider future features when he makes choices like that

    • Favicon of https://blog.ryeol.com BlogIcon ryeol 2011.08.16 02:47 신고  댓글주소  수정/삭제

      I use this pattern for a small option set.
      If you do not meet this condition, you should consider collection related solutions such as CollectionView and ComboBox.

      Thanks for your comment.