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

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>
...


신고


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>
...


신고

비주얼 스튜디오 2008 SP1에서 WPF 개발을 하다보면 다음과 같은 경고가 발생할 수 있습니다.

The type 'ConflictTest.MainWindow' in 'C:\ConflictTest\ConflictTest\MainWindow.xaml.cs' conflicts with the imported type 'ConflictTest.MainWindow' in 'c:\ConflictTest\ConflictTest\bin\Debug\ConflictTest.exe'.
Using the type defined in 'C:\ConflictTest\ConflictTest\MainWindow.xaml.cs'.

이 경고는 가끔씩 멈추는 WPF 디자이너 때문에 비주얼 스튜디오 프로세스를 강제 종료하면 발생될 수 있습니다.
이 문제는 비주얼 스튜디오가 알 수 없는 이유로 추가한 실행 파일에 대한 참조를 참조 목록에서 지우면 해결됩니다.

실행 파일에 대한 참조를 참조 목록에서 지우세요.


신고

You may encounter strange warnings like the following if you develop WPF applications in Visual Studio 2008 SP1.

The type 'ConflictTest.MainWindow' in 'C:\ConflictTest\ConflictTest\MainWindow.xaml.cs' conflicts with the imported type 'ConflictTest.MainWindow' in 'c:\ConflictTest\ConflictTest\bin\Debug\ConflictTest.exe'.
Using the type defined in 'C:\ConflictTest\ConflictTest\MainWindow.xaml.cs'.

These warnings can be happened when you end a Visual Studio Process of which WPF designer is hanging.
To solve this problem, you have to remove a self-reference the Visual Studio adds by some reason.

Remove the executable assembly in the reference list.


신고

티스토리 툴바