Programing/WPF

WPF 에서 복수의 usercontrol switch 하기

Ezzi 2019. 9. 2. 10:37
반응형

WPF MVVM 방식을 이용하여 복수의 Usercontrol을 Switch 하는 예제 입니다. 

 

1. 먼저 viausl studio에서 wpf 용 app을 하나 만들어 줍니다.

 

2. MainModel 을 만들기 전에 BaseModel을 만들어 주겠습니다. 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
using System.ComponentModel;
 
namespace switchUsercontrol
{
    public class ViewModelBase : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
 
        protected virtual void OnPropertyChanged(string propName)
        {
            PropertyChanged?.Invoke(thisnew PropertyChangedEventArgs(propName));
        }
    }
}
 
cs

 

3. 이제 ViewModelbase를 상속받는 MainModel class를 만들어 줍니다.

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
31
32
33
34
35
36
using System.Windows.Input;
 
namespace switchUsercontrol
{
    public class MainModel : ViewModelBase
    {
        private int switchView;
        public int SwitchView
        {
            get
            {
                return switchView;
            }
            set
            {
                switchView = value;
                OnPropertyChanged("SwitchView");
            }
        }
 
        public ICommand SwitchViewCommand { get; }
 
        public MainModel()
        {
            SwitchView = 0;
 
            SwitchViewCommand = new RelayCommand<object>(p => OnSwitchView(p));
        }
 
        private void OnSwitchView(object index)
        {
            SwitchView = int.Parse(index.ToString());
        }
    }
}
 
cs

 

4. ICommand의 interface를 구현한 RelayCommand class를 만들어 준다.

이 부분은 깔끔하게 정리된 코드가 많아서 참조하였습니다.

출처는 해당 코드 안에 있습니다. 

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
using System;
using System.Diagnostics;
using System.Windows.Input;
 
namespace switchUsercontrol
{
 
    /// <summary>
    /// A command whose sole purpose is to 
    /// relay its functionality to other
    /// objects by invoking delegates. The
    /// default return value for the CanExecute
    /// method is 'true'.
    /// 
    /// Source: http://www.codeproject.com/Articles/31837/Creating-an-Internationalized-Wizard-in-WPF
    /// </summary>
    public class RelayCommand<T> : ICommand
    {
        #region Fields
        private readonly Action<T> mExecute = null;
        private readonly Predicate<T> mCanExecute = null;
        #endregion // Fields
 
        #region Constructors
        /// <summary>
        /// Class constructor
        /// </summary>
        /// <param name="execute"></param>
        public RelayCommand(Action<T> execute)
          : this(execute, null)
        {
        }
 
        /// <summary>
        /// Creates a new command.
        /// </summary>
        /// <param name="execute">The execution logic.</param>
        /// <param name="canExecute">The execution status logic.</param>
        public RelayCommand(Action<T> execute, Predicate<T> canExecute)
        {
            this.mExecute = execute ?? throw new ArgumentNullException("execute");
            this.mCanExecute = canExecute;
        }
 
        #endregion // Constructors
 
        #region events
        /// <summary>
        /// Eventhandler to re-evaluate whether this command can execute or not
        /// </summary>
        public event EventHandler CanExecuteChanged
        {
            add
            {
                if (this.mCanExecute != null)
                    CommandManager.RequerySuggested += value;
            }
 
            remove
            {
                if (this.mCanExecute != null)
                    CommandManager.RequerySuggested -= value;
            }
        }
        #endregion
 
        #region methods
        /// <summary>
        /// Determine whether this pre-requisites to execute this command are given or not.
        /// </summary>
        /// <param name="parameter"></param>
        /// <returns></returns>
        [DebuggerStepThrough]
        public bool CanExecute(object parameter)
        {
            return this.mCanExecute == null ? true : this.mCanExecute((T)parameter);
        }
 
        /// <summary>
        /// Execute the command method managed in this class.
        /// </summary>
        /// <param name="parameter"></param>
        public void Execute(object parameter)
        {
            this.mExecute((T)parameter);
        }
        #endregion methods
    }
 
    /// <summary>
    /// A command whose sole purpose is to 
    /// relay its functionality to other
    /// objects by invoking delegates. The
    /// default return value for the CanExecute
    /// method is 'true'.
    /// </summary>
    public class RelayCommand : ICommand
    {
        #region Fields
        private readonly Action mExecute;
        private readonly Func<bool> mCanExecute;
        #endregion Fields
 
        #region Constructors
 
        /// <summary>
        /// Creates a new command that can always execute.
        /// </summary>
        /// <param name="execute">The execution logic.</param>
        public RelayCommand(Action execute)
          : this(execute, null)
        {
        }
 
        /// <summary>
        /// Copy constructor
        /// </summary>
        /// <param name="inputRC"></param>
        public RelayCommand(RelayCommand inputRC)
          : this(inputRC.mExecute, inputRC.mCanExecute)
        {
        }
 
        /// <summary>
        /// Creates a new command.
        /// </summary>
        /// <param name="execute">The execution logic.</param>
        /// <param name="canExecute">The execution status logic.</param>
        public RelayCommand(Action execute, Func<bool> canExecute)
        {
            this.mExecute = execute ?? throw new ArgumentNullException("execute");
            this.mCanExecute = canExecute;
        }
 
        #endregion Constructors
 
        #region Events
        /// <summary>
        /// Eventhandler to re-evaluate whether this command can execute or not
        /// </summary>
        public event EventHandler CanExecuteChanged
        {
            add
            {
                if (this.mCanExecute != null)
                    CommandManager.RequerySuggested += value;
            }
 
            remove
            {
                if (this.mCanExecute != null)
                    CommandManager.RequerySuggested -= value;
            }
        }
        #endregion Events
 
        #region Methods
        /// <summary>
        /// Execute the attached CanExecute methode delegate (or always return true)
        /// to determine whether the command managed in this object can execute or not.
        /// </summary>
        /// <param name="parameter"></param>
        /// <returns></returns>
        [DebuggerStepThrough]
        public bool CanExecute(object parameter)
        {
            return this.mCanExecute == null ? true : this.mCanExecute();
        }
 
        /// <summary>
        /// Return the attached delegate method.
        /// </summary>
        /// <param name="parameter"></param>
        public void Execute(object parameter)
        {
            this.mExecute();
        }
        #endregion Methods
    }
}
 
cs

 

5. 자 이제 복수의 usercontrol을 만들어 줍니다.

저느 view1, view2라는 이름으로 2개를 만들고 각각을 구분할 수 있도록 Textbox를 하나 추가하여 이름을 입력했고

Button을 하나 만들어서 MainModel에서 정의 해줬던 Command를 다음과 같이 등록 해줬습니다.

이제 버튼이 클릭되면 SwitchViewCommand가 발동하면서 Parameter로 각 view에 입력된 값이 전달되게 됩니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<UserControl x:Class="switchUsercontrol.View1"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:switchUsercontrol"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800">
    <Grid>
        <StackPanel Orientation="Vertical" VerticalAlignment="Center">
            <TextBlock FontSize="20" Margin="10" VerticalAlignment="Center" HorizontalAlignment="Center">
            Screen for View1
            </TextBlock>
            <Button Content="go to view2" 
                    Command="{Binding SwitchViewCommand}"
                    CommandParameter="1"/>
        </StackPanel>        
    </Grid>
</UserControl>
 
cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<UserControl x:Class="switchUsercontrol.View2"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:switchUsercontrol"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800">
    <Grid>
        <StackPanel Orientation="Vertical" VerticalAlignment="Center">
            <TextBlock FontSize="20" Margin="10" VerticalAlignment="Center" HorizontalAlignment="Center">
            Screen for View2
            </TextBlock>
            <Button Content="go to view1" 
                    Command="{Binding SwitchViewCommand}"
                    CommandParameter="0"/>
        </StackPanel>
    </Grid>
</UserControl>
 
cs

 

6. 이제 마지막으로 MainWindow에 코드를 작성해 봅시다.

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
31
32
33
34
35
<Window x:Class="switchUsercontrol.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:switchUsercontrol"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Window.DataContext>
        <local:MainModel />
    </Window.DataContext>    
    <Window.Resources>
        <DataTemplate x:Key="View1Template" DataType="{x:Type local:MainModel}">
            <local:View1 />
        </DataTemplate>
        <DataTemplate x:Key="View2Template" DataType="{x:Type local:MainModel}">
            <local:View2 />
        </DataTemplate>
    </Window.Resources>
    <Grid>
        <ContentControl Content="{Binding }">
            <ContentControl.Style>
                <Style TargetType="{x:Type ContentControl}">
                    <Setter Property="ContentTemplate" Value="{StaticResource View1Template}" />
                    <Style.Triggers>
                        <DataTrigger Binding="{Binding SwitchView}" Value="1">
                            <Setter Property="ContentTemplate" Value="{StaticResource View2Template}" />
                        </DataTrigger>
                    </Style.Triggers>
                </Style>
            </ContentControl.Style>
        </ContentControl>
    </Grid>
</Window>
 
cs

 

처음 실행된 App의 모습입니다.

 

 

 

go to view2 버튼을 클릭하게 되면

 

 

다음과 같이 화면 전환이 되게 됩니다.

 

전체 소스코드는 https://github.com/Helloezzi/wpf_usercontrol_switch github에 있습니다.

 

 

 

반응형