WPF User Control Dependency Property ์˜ค๋ฅ˜

์•ˆ๋…•ํ•˜์‹ญ๋‹ˆ๊นŒ.
์ œ Applcation์—๋Š” 8๊ฐœ์˜ ๊ฐ™์€ ๋ชจ์–‘์˜ Toggle button์ด ์กด์žฌํ•ฉ๋‹ˆ๋‹ค. User Control๋กœ ๋งŒ๋“ค์–ด์„œ ์‚ฌ์šฉ์ค‘์ด๊ณ , Command์™€ Command Parameter๋ฅผ Dependency Property๋กœ ๋งŒ๋“ค์–ด์„œ ์‚ฌ์šฉํ•˜๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค.
8๊ฐœ์˜ Toggle button์€ ํ•˜๋‚˜์˜ Command๋ฅผ ๋ฐ”์ธ๋”ฉ ๋ฐ›๊ณ  Parameter๋กœ ํ•จ์ˆ˜์˜ ๋™์ž‘์„ ๋‚˜๋ˆ„๋ ค๊ณ  ํ•˜๋Š”๋ฐ,
xaml๋‹จ์—์„œ ๊ธฐ๋ณธ๊ฐ’ ํ˜•์‹๊ณผ ์ผ์น˜ํ•˜์ง€ ์•Š๋Š”๋‹ค๊ณ  ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๋„ค์š”. ์ œ๊ฐ€ ๋ญ˜ ์ž˜๋ชป ํ–ˆ์„๊นŒ์š”?
image
View

<StackPanel Height="72" Width="auto" Margin="0 -10 0 75" 
            HorizontalAlignment="Center" Orientation="Horizontal">
       <togglebtn:outputbtn Margin="20 30 00 0" 
                            DOCommand="{Binding DOControl}" 
                            DOCommandParameter="{Binding DoNums[0]}"/>
       <togglebtn:outputbtn Margin="0 30 00 0" 
                            DOCommand="{Binding DOControl}" 
                            DOCommandParameter="{Binding DoNums[1]}"/>
       <togglebtn:outputbtn Margin="0 30 00 0" 
                            DOCommand="{Binding DOControl}" 
                            DOCommandParameter="{Binding DoNums[2]}"/>
       <togglebtn:outputbtn Margin="0 30 20 0" 
                            DOCommand="{Binding DOControl}" 
                            DOCommandParameter="{Binding DoNums[3]}"/>
</StackPanel>
<StackPanel Height="40" Margin="0 0 0 0" Width="346"
            Orientation="Horizontal" HorizontalAlignment="Center">
        <TextBlock Text="DO5" Margin="42 10 40 0" Height="auto"/>
        <TextBlock Text="DO6" Margin="15 10 40 0" Height="auto"/>
        <TextBlock Text="DO7" Margin="15 10 40 0" Height="auto"/>
        <TextBlock Text="DO8" Margin="15 10 40 0" Height="auto"/>
  </StackPanel>
  <StackPanel Height="72" Margin="0 61 0 0"
              HorizontalAlignment="Center" Orientation="Horizontal">
        <togglebtn:outputbtn Margin="20 15 00 0" 
                             DOCommand="{Binding DOControl}" 
                             DOCommandParameter="{Binding DoNums[4]}"/>
        <togglebtn:outputbtn Margin="0 15 00 0" 
                             DOCommand="{Binding DOControl}" 
                             DOCommandParameter="{Binding DoNums[5]}"/>
        <togglebtn:outputbtn Margin="0 15 00 0" 
                             DOCommand="{Binding DOControl}" 
                             DOCommandParameter="{Binding DoNums[6]}"/>
        <togglebtn:outputbtn Margin="0 15 20 0" 
                             DOCommand="{Binding DOControl}" 
                             DOCommandParameter="{Binding DoNums[7]}"/>

UserControl.xaml.cs

        public ICommand DOCommand
        {
            get { return (ICommand)GetValue(DOCommandProperty); }
            set { SetValue(DOCommandProperty, value);}
        }

        public static DependencyProperty DOCommandProperty = 
            DependencyProperty.Register(nameof(DOCommand), typeof(ICommand), typeof(outputbtn), new PropertyMetadata(null, RaiseCommandPropertyCallback));

        private static void RaiseCommandPropertyCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            outputbtn command = (outputbtn)d;
            ToggleButton btn = command.btnDO;
            btn.Command = e.NewValue as ICommand;
        }

        public int DOCommandParameter
        {
            get { return (int)GetValue(DOCommandParameterProperty); }
            set { SetValue (DOCommandParameterProperty, value); }
        }

        public static DependencyProperty DOCommandParameterProperty =
            DependencyProperty.Register(nameof(DOCommandParameter), typeof(int), typeof(outputbtn), new PropertyMetadata(null, RaiseParameterPropertyCallback));

        private static void RaiseParameterPropertyCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            outputbtn patameter = (outputbtn)d;
            ToggleButton btn = patameter.btnDO;
            btn.CommandParameter = int.Parse((string)e.NewValue);
        }

View Model

        private List<int> _donums;

        public List<int> DoNums { get { return _donums; } }


        private RelayCommand<int> _docontrol;

        public ICommand DOControl
        {
            get
            {
                if (_docontrol == null)
                {
                    _docontrol = new RelayCommand<int>(DoOnOff);
                }

                return _docontrol;
            }
        }

        private void DoOnOff(int par)
        {
            MessageBox.Show($"toggle button num : {par}");
        }

        IOPageVM() //ctor
       {
            _donums = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, };
       } 
1๊ฐœ์˜ ์ข‹์•„์š”

๊ธฐ๋ณธ๊ฐ’์ด null์ธ๋ฐ์š” int์— null์„ ๊ธฐ๋ณธ๊ฐ’์œผ๋กœ ํ•  ์ˆ˜ ์—†์œผ๋ฏ€๋กœ ํƒ€์ž… ๋ถˆ์ผ์น˜์—์„œ ๋ฐœ์ƒํ•˜๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.
0 ๋“ฑ์œผ๋กœ ๋ฐ”๊พธ์‹œ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

1๊ฐœ์˜ ์ข‹์•„์š”

๋„ค ํ•ด๊ฒฐ๋์Šต๋‹ˆ๋‹ค. ๊ทผ๋ฐ ํ”„๋กœ๊ทธ๋žจ์„ ์‹คํ–‰ํ•˜๋‹ˆ ํ† ๊ธ€ ๋ฒ„ํŠผ์ด ํด๋ฆญ์ด ์•ˆ๋˜๋„ค์š”. ํ˜น์‹œ ์ด์œ ๋ฅผ ์•Œ๊ณ  ๊ณ„์‹ค๊นŒ์š”?

๊ณต์œ ๋œ ์ฝ”๋“œ๋กœ๋Š” ๋ช…ํ™•ํžˆ ์•Œ ์ˆ˜๋Š” ์—†์ง€๋งŒ ํ† ๊ธ€ ๋ฒ„ํŠผ ์ด๋ฒคํŠธ์— ์˜ํ•œ ๋™์ž‘์„ Command๋กœ ์ „๋‹ฌํ•˜๋Š” ์ฝ”๋“œ๊ฐ€ ๋ณด์ด์ง€ ์•Š๋Š”๋ฐ์š”, ์•„๋งˆ ๊ทธ ๋ฌธ์ œ์ผ ๋“ฏ ํ•ฉ๋‹ˆ๋‹ค.

1๊ฐœ์˜ ์ข‹์•„์š”

์ดํ•ด๊ฐ€ ์ž˜ ์•ˆ๊ฐ€๋„ค์š”. xaml์—์„œ Command๋ฅผ ๋ฐ”์ธ๋”ฉ ํ–ˆ์œผ๋‹ˆ ์ด๋ฒคํŠธ๋ฅผ ๋„˜๊ฒจ ์ค€๊ฑฐ ์•„๋‹Œ๊ฐ€์š”?

์ผ๋ถ€ ์ฝ”๋“œ๋งŒ ๊ณต์œ ํ•ด ์ฃผ์…”์„œ ์ž˜ ๋ชจ๋ฅด๊ฒ ์œผ๋‚˜, ํ˜น์‹œ ํ•ด๋‹น View ์™€ ViewModel ์—ฐ๊ฒฐ์€ ์ž˜ ๋˜์–ด ์žˆ์„๊นŒ์š”? DataContext ์ง€์ •ํ•˜๋Š” ๋ถ€๋ถ„์ด ์•ˆ๋ณด์—ฌ์„œ์š”.

1๊ฐœ์˜ ์ข‹์•„์š”
    <Page.DataContext>
        <vm:IOPageVM/>
    </Page.DataContext>

์œ„์™€ ๊ฐ™์ด ํ•ด๋‹น View์— ViewModel๊ณผ ์—ฐ๊ฒฐ ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ํŒ์—…์— ์˜ฌ๋ผ๊ฐ„ ํ† ๊ธ€ ๋ฒ„ํŠผ์ธ๋ฐ, ํ•ด๋‹น ํŒ์—…์— ๋‹ค๋ฅธ ์ปดํฌ๋„ŒํŠธ๋“ค๋„ ๋ฐ”์ธ๋”ฉ์ด ๋˜๊ณ  ์žˆ๋Š”๋ฐ ์˜์กด ์†์„ฑ์œผ๋กœ ์œ ์ € ์ปจํŠธ๋กค ํ•ด๋ณด๋Š”๊ฒŒ ์ฒ˜์Œ์ด๋ผ ์–ด๋ ต๋„ค์š”.

์•„๋งˆ๋„ view model ์—ฐ๊ฒฐ์€ ์ž˜ ๋˜์—ˆ์„ ๊ฑฐ ๊ฐ™๊ธดํ•œ๋ฐ

UserControl.xaml.cs ์ด๋ผ๊ณ  ํ‘œ์‹œํ•˜์‹  ์ฝ”๋“œ๊ฐ€ outputbtn ์„ ๊ตฌํ˜„ํ•œ ์ฝ”๋“œ์ธ ๊ฑฐ์ฃ ?
๊ทธ๋ฆฌ๊ณ  Button ์„ ์ƒ์†๋ฐ›์•„์„œ ๊ตฌํ˜„ํ•œ ๊ฑฐ ๋งž์ฃ ?

๊ทธ๋ ‡๋‹ค๋ฉด outputbtn ์—์„œ click ์ด๋ฒคํŠธ๋ฅผ command ๋กœ ์—ฐ๊ฒฐํ•˜๋Š” ๋ถ€๋ถ„๋„ ๊ตฌํ˜„๋˜์–ด ์žˆ๋‚˜์š”?

๊ธฐ์กด button ์˜ click ์ด๋‚˜ toggle ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ–ˆ์„ ๋•Œ ์‚ฌ์šฉํ•˜๋Š” command ๋ฅผ ํ•จ๊ป˜ ๊ตฌํ˜„ํ•˜๊ฑฐ๋‚˜ ์—ฐ๊ฒฐํ•ด์ฃผ์–ด์•ผ ์˜๋„ํ•œ๋Œ€๋กœ ๋™์ž‘ํ•  ๊ฑฐ ๊ฐ™์•„์š”.

๊ทธ ๋ถ€๋ถ„์ด ๊ตฌํ˜„๋˜์–ด ์žˆ์ง€ ์•Š์€ ์ƒํƒœ์—์„œ ICommand ์†์„ฑ๋งŒ usercontrol ์— ์ถ”๊ฐ€ ๊ตฌํ˜„ํ•˜๋ฉด

์•„๋ฌด์ผ๋„ ์ผ์–ด๋‚˜์ง€ ์•Š์Šต๋‹ˆ๋‹คโ€ฆ;;

1๊ฐœ์˜ ์ข‹์•„์š”

outputbtn UserControl ์—์„œ ์˜์กด ์†์„ฑ์„ ์ œ๋Œ€๋กœ ๋ฐ”์ธ๋”ฉ ํ–ˆ๋Š”์ง€ ํ™•์ธํ•ด ๋ณด์„ธ์š”. ์ฝ”๋“œ๊ฐ€ ๊ณต์œ ๋˜์–ด ์žˆ์ง€ ์•Š์•„ ๋„์›€ ๋“œ๋ฆฌ๊ธฐ๊ฐ€ ์ข€ ํž˜๋“ญ๋‹ˆ๋‹ค. ^^

1๊ฐœ์˜ ์ข‹์•„์š”
<StackPanel>
        <StackPanel.Resources>
            <Style x:Key="toggleBtn" TargetType="{x:Type ToggleButton}">
                <Setter Property="Margin" Value="10,0"/>
                <Setter Property="Height" Value="30" />
                <Setter Property="Width" Value="60" />
                <Setter Property="BorderBrush" Value="Transparent"/>
                <Setter Property="Content" Value="{DynamicResource Off}"/>
                <Style.Triggers>
                    <Trigger Property="IsChecked" Value="True">
                        <Setter Property="Content" Value="{DynamicResource On}"/>
                        <Setter Property="Background" Value="{DynamicResource ismouseovercolor}"/>
                    </Trigger>
                    <Trigger Property="IsMouseOver" Value="True">
                        <Setter Property="Background" Value="{DynamicResource ismouseovercolor}"/>
                    </Trigger>
                </Style.Triggers>
            </Style>
        </StackPanel.Resources>

        <ToggleButton x:Name="btnDO" Style="{StaticResource toggleBtn}"/>
    </StackPanel>

์œ„ ์ฝ”๋“œ๊ฐ€ outputbtn์˜ ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค. click ์ด๋ฒคํŠธ๋ฅผ command์— ์—ฐ๊ฒฐํ•ด์•ผ ๋œ๋‹ค๊ณ  ํ•˜์‹œ๋Š”๊ฒŒ ์œ„์˜ ํ† ๊ธ€ ๋ฒ„ํŠผ์— Click = "{binding ~~}"์ด๋Ÿฐ ์‹์œผ๋กœ ๋˜์•ผ ํ•œ๋‹ค๊ณ  ๋ง์”€ํ•˜์‹œ๋Š”๊ฑด๊ฐ€์š”?

์•„, ์ €๋„ ์ด์ € ์ „์ฒด ์†Œ์Šค ์ฝ”๋“œ๋ฅผ ๋”ฐ๋ผ๊ฐ€๋ฉด์„œ ํ™•์ธํ•œ ๊ฒŒ ์•„๋‹ˆ๋ผ
์ •ํ™•ํžˆ ์ด๊ฑฐ๋‹คโ€ฆ ๋ผ๊ณ  ๋ง์”€์€ ๋ชป ๋“œ๋ฆฌ๊ฒ ๊ณ  ๊ทธ๋ƒฅ ์ œ์‹œํ•˜์‹  ์ฝ”๋“œ ์•ˆ์—์„œ ์ถ”์ธก์„ ํ•œ ๊ฑด๋ฐ์š”.

UserControl.xaml.cs ์˜ ์ผ๋ถ€๋งŒ ์ œ์‹œํ•˜์‹  ๊ฑธ๋กœ๋ด์„œ
ToggleButton ์„ ์ƒ์†ํ•ด์„œ ๋ญ”๊ฐ€ ์žฌ์ •์˜ ํ•œ ๊ฑด ์•„๋‹Œ ๊ฑฐ ๊ฐ™๊ตฐ์š”.

  1. ํด๋ฆญ์ด ์•ˆ ๋œ๋‹ค๋Š” ๊ฒŒ ์–ด๋–ค ๋ง์ธ์ง€ ์ •ํ™•ํžˆ ์ž˜ ๋ชจ๋ฅด๊ฒ ์–ด์š”
    ํด๋ฆญ ๋ฒ„ํŠผ์ด ํ™œ์„ฑํ™” ์•ˆ ๋˜์–ด์„œ ๋ˆ„๋ฅด๋Š” ๊ฒŒ ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค๋Š” ์–˜๊ธฐ์ธ์ง€, UI ๋กœ ํด๋ฆญ์€ ๋˜๋Š”๋ฐ ์ด๋ฒคํŠธ ๋ฐœ์ƒ์ด ์•ˆ ๋œ๋‹ค๋Š” ๊ฑด์ง€, ์ด๋ฒคํŠธ๋Š” ๋“ค์–ด์˜ค๋Š”๋ฐ command ํ˜ธ์ถœ์ด ์•ˆ ๋œ๋‹ค๋Š” ๊ฑด์ง€โ€ฆ
    ์ •ํ™•ํ•œ ์˜๋ฏธ๋ฅผ ๋ชจ๋ฅด๊ฒ ๋„ค์š”. ์ด๊ฒƒ๋ถ€ํ„ฐ ์ •ํ™•ํžˆ ์•Œ์•„์•ผ ํ•  ๊ฑฐ ๊ฐ™์•„์š”.

  2. ๊ทธ๋ƒฅ ์—ฌ๊ธฐ์„œ command ํ˜ธ์ถœ์ด ์•ˆ ๋œ๋‹ค๋Š” ๊ฑธ๋กœ ๊ฐ€์ •ํ–ˆ์„ ๋•Œ ๋“œ๋Š” ์˜๋ฌธ์ธ๋ฐ์š”. UserControl.xaml.cs์—์„œ ๋ณ„๋„์˜ ICommand ์†์„ฑ์„ ์ •์˜ํ•˜์‹œ ์ด์œ ๊ฐ€ ์žˆ์„๊นŒ์š”?
    ๋”ฑํžˆ ์ง€๊ธˆ ์‚ฌ์šฉ๋ฒ•์ด๋‚˜ ์—ฐ๊ฒฐ ๊ตฌ๋ฌธ์œผ๋กœ ๋ดค์„ ๋•Œ์—๋Š” ๊ทธ๋‹ค์ง€ ํ•„์š”ํ•˜์ง€ ์•Š์•„๋ณด์—ฌ์„œ์š”. ์–ด์ฐจํ”ผ ์›๋ž˜ Button ์˜ ์†์„ฑ์œผ๋กœ ์กด์žฌํ•˜๋Š” ๊ฑด๋ฐ ๋”ฐ๋กœ ์ •์˜ํ•˜๋Š” ์ด์œ ๋ฅผ ๋ชจ๋ฅด๊ฒ ๋„ค์š”. ํŠน๋ณ„ํžˆ ์ „์šฉ command ๋ฅผ ๋งŒ๋“ค๊ฑฐ๋‚˜ ์กฐ์ž‘ํ•˜๋Š” ๊ตฌ๋ฌธ์€ ์—†์–ด๋ณด์ด๋Š” ๋ฐ ๋งž๋‚˜์š”?
    ICommand ๊ฐ€ ๊ตฌํ˜„๋œ ๋Œ€์ƒ ๊ฐ์ฒด๋ฅผ ์„ ํƒํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด ๊ทธ๋ƒฅ DataContext ์„ ํƒ ๊ตฌ๋ฌธ์„ Binding ๊ตฌ๋ฌธ์— ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒŒ ๋” ๋‚˜์„ ์ˆ˜๋„ ์žˆ๊ฒ ๋„ค์š”.

  3. ์ผ๋‹จ ๊ทธ๋ ‡๋‹ค๊ณ  ์น˜๊ณ , ๋งŒ์•ฝ ์ง€๊ธˆ ์ฝ”๋“œ์—์„œ ์ •์ƒ์ ์œผ๋กœ ๋นŒ๋“œ๋˜๊ณ  Command ์—ฐ๊ฒฐ์ด ์ •์ƒ์ด๋ผ๊ณ  ํ•  ๋•Œ ๋””๋ฒ„๊น…์„ ํ†ตํ•ด ์–ด๋””๊นŒ์ง€ ์ด๋ฒคํŠธ ํ˜ธ์ถœ์ด ์ง„ํ–‰๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•ด๋ณด์…จ๋Š”์ง€์š”?
    ์‚ฌ์‹ค ๋””๋ฒ„๊น… ๋ฌธ์ œ๋Š” ์ด๋ ‡๊ฒŒ ์กฐ๊ฐ๋‚œ ์ฝ”๋“œ๋งŒ ๊ฐ€์ง€๊ณ ๋Š” ์•Œ ์ˆ˜ ์žˆ๋Š” ๊ฒŒ ๋ณ„๋กœ ์—†์–ด์„œ ํฐ ๋„์›€์€ ๋ชป ๋“œ๋ฆด ๊ฑฐ ๊ฐ™๊ณ , ๊ทธ๋ƒฅ ์ถ”์ธก์„ฑ ๋ฐœ์–ธ ๋ช‡ ๊ฐ€์ง€๋“ค๋งŒ ์™”๋‹ค๊ฐ”๋‹ค ํ•  ์ˆ˜๋ฐ–์— ์—†๊ฑฐ๋“ ์š”
    ๊ทธ ๋‹ค์Œ๋ถ€ํ„ฐ๋Š” ์Šค์Šค๋กœ ๋””๋ฒ„๊น…ํ•ด์„œ ์ฐพ์•„๋‚ด๋Š” ๋ฐฉ๋ฒ•๋ฐ–์— ์—†๊ธดํ•ด์š”.

๊ฐ€์žฅ ์ข‹์€ ๊ฑด ์žฌํ˜„๊ฐ€๋Šฅํ•œ ์†Œ์Šค์ฝ”๋“œ๋ฅผ ๊ฐ™์ด ์˜ฌ๋ ค์ฃผ์‹œ๋Š” ๊ฒŒ ๊ฐ€์žฅ ์ข‹์„ ๊ฑฐ ๊ฐ™์€๋ฐ์š”. ์ง€๊ธˆ์œผ๋กœ์ฌ ์š”์ •๋„๊ฐ€ ์ตœ์„ ์ผ ๊ฑฐ ๊ฐ™์Šด๋‹ค.

3๊ฐœ์˜ ์ข‹์•„์š”

์ด ์ฝ”๋“œ๋ฅผ ์ฐธ๊ณ ํ•˜์‹œ๊ฒ ์–ด์š”? UserControl ์•ˆ์˜ ToggleButton์— Command์„ ๋„˜๊ธฐ๋Š” ๋ฐฉ๋ฒ•์„ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค.

| MainWindow.xaml

<Window
    x:Class="WpfApp41.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:local="clr-namespace:WpfApp41"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    Title="MainWindow"
    Width="800"
    Height="450"
    mc:Ignorable="d">
    <Grid>
        <StackPanel Orientation="Vertical">
            <local:CustomToggleButton
                Command="{Binding ToggleCommand}"
                CommandParameter="1"
                Text="1" />
            <local:CustomToggleButton
                Command="{Binding ToggleCommand}"
                CommandParameter="2"
                Text="2" />
            <local:CustomToggleButton
                Command="{Binding ToggleCommand}"
                CommandParameter="3"
                Text="3" />
            <local:CustomToggleButton
                Command="{Binding ToggleCommand}"
                CommandParameter="4"
                Text="4" />
            <local:CustomToggleButton
                Command="{Binding ToggleCommand}"
                CommandParameter="5"
                Text="5" />
        </StackPanel>
    </Grid>
</Window>

| MainWindow.xaml.cs
โ€ป Command๋ฅผ ๊ฐ„๋‹จํ•˜๊ฒŒ ๊ตฌํ˜„ํ•˜๊ธฐ ์œ„ํ•ด ๋ณ„๋„์˜ ViewModel์€ ์ƒ๋žตํ•˜๊ณ  xaml.cs์— Community Toolkit MVVM์„ ์‚ฌ์šฉํ•˜์—ฌ Command๋ฅผ ๊ตฌํ˜„ ํ•˜์˜€์Šต๋‹ˆ๋‹ค.

using CommunityToolkit.Mvvm.Input;

using System.Windows;

namespace WpfApp41
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            DataContext = this;
        }

        [RelayCommand]
        void OnToggle(int num)
        {
            MessageBox.Show(num.ToString());
        }
    }
}

| CustomToggleButton.xaml

<UserControl
    x:Class="WpfApp41.CustomToggleButton"
    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:local="clr-namespace:WpfApp41"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    x:Name="this"
    d:DesignHeight="450"
    d:DesignWidth="800"
    mc:Ignorable="d">
    <Grid>
        <ToggleButton
            Command="{Binding Command, ElementName=this}"
            CommandParameter="{Binding CommandParameter, ElementName=this}"
            Content="{Binding Text, ElementName=this}" />
    </Grid>
</UserControl>

| CustomToggleButton.xaml.cs

using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;

namespace WpfApp41;

/// <summary>
/// CustomToggleButton.xaml์— ๋Œ€ํ•œ ์ƒํ˜ธ ์ž‘์šฉ ๋…ผ๋ฆฌ
/// </summary>
public partial class CustomToggleButton : UserControl
{
    public readonly static DependencyProperty CommandProperty = DependencyProperty.Register(nameof(Command), typeof(ICommand), typeof(CustomToggleButton), new PropertyMetadata(null));
    public readonly static DependencyProperty CommandParameterProperty = DependencyProperty.Register(nameof(CommandParameter), typeof(int), typeof(CustomToggleButton), new PropertyMetadata(0));
    public readonly static DependencyProperty TextProperty = DependencyProperty.Register(nameof(Text), typeof(string), typeof(CustomToggleButton), new PropertyMetadata(string.Empty));

    public ICommand Command
    {
        get => (ICommand)GetValue(CommandProperty);
        set => SetValue(CommandProperty, value);
    }

    public int CommandParameter
    {
        get => (int)GetValue(CommandParameterProperty);
        set => SetValue(CommandParameterProperty, value);
    }

    public string Text
    {
        get => (string)GetValue(TextProperty);
        set => SetValue(TextProperty, value);
    }

    public CustomToggleButton()
    {
        InitializeComponent();
    }
}

| ์‹คํ–‰
image

4๊ฐœ์˜ ์ข‹์•„์š”

์Œโ€ฆ ๊ทธ๋ฆฌ๊ตฌ ๋ง๋ถ™์ด์ž๋ฉด

์ด๋Ÿฐ ์ƒํ™ฉ์—์„œ๋Š” UserControl ๋ณด๋‹ค๋Š” CustomControl ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒŒ ๋” ๋‚˜์•„๋ณด์ž„๋‹ค.

์‚ฌ์‹ค UserControl ์ด๋‚˜ CustomControl ์ด๋‚˜ view ๋ฅผ ๋งŒ๋“ ๋‹ค๋Š” ์ฐจ์›์—์„œ๋Š” ํฐ ์ฐจ์ด๊ฐ€ ์—†์„ ์ˆ˜๋„ ์žˆ๋Š”๋ฐ

์ €๋Š” ๊ฐœ์ธ์ ์œผ๋กœ

Layout ์„ ๋งŒ๋“œ๋Š” view โ†’ UserControl
componet ๋ฅผ ๋งŒ๋“œ๋Š” view โ†’ CustomControl

์ด๋ ‡๊ฒŒ ์ •์˜๋ฅผ ํ•˜๊ณ  ์‚ฌ์šฉํ•˜๋Š” ํŽธ์ด์—์š”.

๊ฐœ๋ณ„ control ์ˆ˜์ค€์˜ component ๋ฅผ ๋งŒ๋“ค์–ด ๋…๋ฆฝ์ ์œผ๋กœ ์žฌ์‚ฌ์šฉํ•ด์•ผํ•˜๋Š” ์ƒํ™ฉ์ด๋ผ๋ฉด
CustomControl ๋กœ ์ •์˜ํ•ด ๊ตฌํ˜„ํ•˜๋Š” ๊ฒŒ ํ›จ์”ฌ ๋” ๊ฐ„๋‹จํ•˜๊ณ  ์ง๊ด€์ ์ผ ์ˆ˜ ์žˆ๊ณ , ํ…Œ์ŠคํŠธํ•˜๊ธฐ ์šฉ์ดํ•ด์ ธ์š”.
๋˜ ๋…๋ฆฝ์ ์œผ๋กœ ๊ตฌํ˜„ํ•˜๊ธฐ ๋•Œ๋ฌธ์— DataContext ์— ์‹ ๊ฒฝ์“ฐ์ง€ ์•Š๊ณ  ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๊ตฌ์šœ. ใ…‡ใ……ใ…‡!

UserControl ์— component ๋ฅผ ๋‹ค ๋•Œ๋ ค๋ฐ•๊ณ  ๋งŒ๋“ค์–ด๋„ ํฐ ์ƒ๊ด€์€ ์—†๋Š”๋ฐ
component ๋ฅผ ํฌํ•จํ•˜๋Š” UserControl ์˜ ๊ฒฝ์šฐ DataContext ์— ์˜์กด์ ์ธ ๊ตฌํ˜„์ด ๋“ค์–ด๊ฐˆ ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ๊ณ 
๋””๋ฒ„๊น…ํ•  ๋•Œ ๋…๋ฆฝ์ ์œผ๋กœ ๋”ฐ๋ผ๊ธฐ ์–ด๋ ค์šด ์ƒํ™ฉ์ด ์—ฐ์ถœ๋  ์ˆ˜๋„ ์žˆ์–ด์š”.(์ง€๊ธˆ์ฒ˜๋Ÿผ๋ง์ด์ฃ .)

๋งŒ์•ฝ toggleBtn ์„ CustomControl ๋กœ ๊ตฌํ˜„ํ–ˆ๋‹ค๋ฉด
command ์—ฐ๊ฒฐ์„ ๋””๋ฒ„๊น…ํ•˜๊ณ  ์‹ถ์„ ๋•Œ ์•„์˜ˆ ๋ณ„๋„์˜ ํ”„๋กœ์ ํŠธ์— ๋œฏ์–ด๋‹ค๊ฐ€ ๋„ฃ๊ณ 
๊ฑฐ๊ธฐ์„œ ๊ฐ„๋‹จํ•œ View ์— ์—ฎ์–ด์„œ ํ…Œ์ŠคํŠธํ•ด๋ณผ ์ˆ˜ ์žˆ์ฃ .(๋ฌธ์ œ๋ฅผ ๋‹จ์ˆœํ™” ํ•ด์„œ ์ฐพ๊ธฐ ์œ„ํ•ด์„œ!)

๊ทธ๋Ÿฐ๋ฐ ์ด๋ ‡๊ฒŒ UserControl ๋‚ด๋ถ€์— ์ •์˜ํ•ด ๋‹ค๋ฅธ view ์™€ ์„ž์ธ ์ƒํƒœ๋กœ ๊ตฌํ˜„ํ•˜๋ฉด
์œ„์—์„œ ๋งํ•œ ๋ฌธ์ œ๋ฅผ ๋‹จ์ˆœํ™”ํ•˜๋Š” ๋ฐฉ์‹์˜ ๋””๋ฒ„๊น…์ด ์–ด๋ ค์›Œ ์ง‘๋‹ˆ๋‹ค.

์•„โ€ฆ ๋„คโ€ฆ ๊ทธ๋ƒฅ ๊ทธ๋ ‡๋‹ค๊ตฌ์š”โ€ฆ =ใ…=

2๊ฐœ์˜ ์ข‹์•„์š”

๋„ค. Toggle Button์„ ์ƒ์† ๋ฐ›์•„์„œ ์žฌ์ •์˜ ํ•˜์ง€๋Š” ์•Š์•˜์Šต๋‹ˆ๋‹ค. 8๊ฐœ์˜ Toggle Button์ด ๋ชจ๋‘ ๊ฐ™์€ ์™ธํ˜•๊ณผ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜๊ธฐ ๋•Œ๋ฌธ์— ํ•œ ๊ฐœ์˜ User Control๋กœ ์ •์˜ํ•˜์—ฌ ์‚ฌ์šฉํ•˜๋ ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

  1. ํ”„๋กœ๊ทธ๋žจ์„ ์‹คํ–‰ ์‹œ, ํด๋ฆญ์ด ๋˜๋Š”๊ฑด์ง€๋Š” ๋ชจ๋ฅด๊ฒ ์ง€๋งŒ ํ† ๊ธ€ ๋ฒ„ํŠผ์ด ๋ˆŒ๋ฆฌ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์›๋ž˜๋Š” ๋ˆŒ๋ฆฌ๊ฒŒ ๋  ๊ฒฝ์šฐ, ํ† ๊ธ€ ๋ฒ„ํŠผ์˜ ์ด๋ฏธ์ง€๊ฐ€ ๋ณ€ํ•ด์•ผ ํ•˜๋Š”๋ฐ ๋ณ€ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

  2. ๋ณ„๋„์˜ ICommand ์†์„ฑ์„ ์ •์˜ํ•œ ์ด์œ ๋Š” ๊ทธ๋ ‡๊ฒŒ ํ•ด์•ผ๋งŒ ํ† ๊ธ€ ๋ฒ„ํŠผ์˜ Check๋‚˜ UnCheck ๊ฐ™์€ ํด๋ฆญ ์‹œ ๋ฐœ์ƒํ•˜๋Š” ์ด๋ฒคํŠธ๋ฅผ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์„๊ฑฐ๋ผ๊ณ  ์ƒ๊ฐ ํ–ˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. User Control์ด ํ•„์š”ํ•œ ๋ถ€๋ถ„์—์„œ ํ˜ธ์ถœ ํ›„ ์ด๋ฒคํŠธ๋ฅผ ์ •์˜ํ•  ๋•Œ Dependency Property๋กœ ์„ ์–ธํ•œ ์†์„ฑ๋“ค๋งŒ ๋ณด์—ฌ์„œ ๊ทธ๋ ‡๊ฒŒ ์ƒ๊ฐํ–ˆ์Šต๋‹ˆ๋‹ค.
    ํŠน๋ณ„ํžˆ ์ „์šฉ command๋ฅผ ๋งŒ๋“ค์ง€๋Š” ์•Š์Šต๋‹ˆ๋‹ค. ๊ทธ์ € User Control์—์„œ ๋ฐœ์ƒํ•œ ์ด๋ฒคํŠธ๋ฅผ View Model ๋‹จ์—์„œ ์ฒ˜๋ฆฌํ•˜๊ณ  ์‹ถ์„ ๋ฟ์ž…๋‹ˆ๋‹ค.

  3. 1๋ฒˆ์˜ ์ด์œ ๋กœ ๋ฐ”์ธ๋”ฉ ์˜ค๋ฅ˜์ธ์ง€, ํด๋ฆญ ์‹œ ์ด๋ฒคํŠธ๊ฐ€ ์–ด๋””๊นŒ์ง€ ํƒ€๋Š”์ง€ ํ™•์ธํ•˜์ง€ ๋ชปํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹คโ€ฆ

์žฌํ˜„ ๊ฐ€๋Šฅํ•œ ์†Œ์Šค ์ฝ”๋“œ๋ผ๊ณ  ํ•˜์‹œ๋Š”๊ฒŒ ์–ด๋А ๋ถ€๋ถ„์„ ๋ง์”€ํ•˜์‹œ๋Š”์ง€ ์ •ํ™•ํžˆ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค. User Control๊ณผ ๋น„ํ•˜์ธ๋“œ ์ฝ”๋“œ, View์™€ View Model์˜ ์†Œ์Šค ์ฝ”๋“œ๋ฅผ ๋ชจ๋‘ ์˜ฌ๋ ธ๋Š”๋ฐ ๋‹ค๋ฅธ ๋ถ€๋ถ„์ด ๋” ํ•„์š”ํ•œ๊ฐ€์š”?
ํ•„์š”ํ•œ ๋ถ€๋ถ„์„ ๋ง์”€ ์ฃผ์‹œ๋ฉด ๋น ๋ฅธ ์‹œ๊ฐ„ ๋‚ด์— ์˜ฌ๋ ค๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ์งˆ๋ฌธ์ด ์ฒ˜์Œ์ด๋‹ค ๋ณด๋‹ˆ ๋ฏธ์ˆ™ํ•˜๋„ค์š”. ๋‹ต๋ณ€ ๊ฐ์‚ฌ๋“œ๋ฆฝ๋‹ˆ๋‹ค.

1๊ฐœ์˜ ์ข‹์•„์š”

CustomControl์˜ ์กด์žฌ๋ฅผ UserControl ๋ณด๋‹ค ๋Šฆ๊ฒŒ ์•Œ์•„๋ฒ„๋ ธ๋„ค์š”โ€ฆ ๋‹ค์Œ์—๋Š” ๋ง์”€ ํ•ด์ฃผ์‹  ๋‚ด์šฉ ๋ฐ˜์˜ํ•ด์„œ ๊ฐœ๋ฐœํ•ด๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. โ€ฆ ๋ง์”€ ๊ฐ์‚ฌ๋“œ๋ฆฝ๋‹ˆ๋‹ค.

2๊ฐœ์˜ ์ข‹์•„์š”

command ๊ฐ€ ๋™์ž‘ํ•˜๋Š” ์ง€์— ๋Œ€ํ•œ ๊ฒƒ๋งŒ ํ•œ์ •ํ•ด์„œ์šค.

  1. ์šฐ์„  ์ด๊ฒƒ๋ถ€ํ„ฐ ํ™•์ธํ•ด์•ผํ•  ๊ฑฐ ๊ฐ™์•„์š”. ๋‹ค๋ฅธ view ์— ๋ง‰ํ˜€์„œ ์•„์˜ˆ mouse down ์ด ์ „๋‹ฌ ์•ˆ ๋์„ ์ˆ˜๋„ ์žˆ์–ด์š”. ์ •์ƒ์ ์œผ๋กœ click ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ–ˆ๋Š”์ง€ ํ™•์ธ๋ถ€ํ„ฐ ํ•ด์•ผํ•  ๊ฑฐ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  2. ToggleButton ์ด Checked / Unchecked ์ด๋ฒคํŠธ๋ฅผ ๋”ฐ๋กœ ์ง€์›ํ•˜๊ธดํ•˜๋Š”๋ฐ view ์—์„œ ์ง์ ‘ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ๋ถ™์—ฌ์„œ ์‚ฌ์šฉํ•˜๋Š” ์ƒํ™ฉ์ด ์•„๋‹ˆ๋ผ๋ฉด ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์„ ์ฃผ๋กœ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
    ์ด๋ฏธ command ๋ฅผ ๋ถ™์—ฌ์„œ ๊ตฌํ˜„ํ–ˆ๋‹ค๋Š” ๊ฑด toggle ์ƒํƒœ๊ฐ€ ๋ณ€ํ•˜๋Š” ๊ฒƒ์„ ๋ฐ›์•„์„œ ViewModel ์—์„œ ๋ญ”๊ฐ€ ์ฒ˜๋ฆฌํ•˜๊ณ  ์‹ถ๋‹ค๋Š” ๊ฑธ๋กœ ๋ณด์ด๋Š”๋ฐ์š”.
    ๊ทธ๋Ÿผ ๋‹จ์ˆœํžˆ click ์ด๋ฒคํŠธ์— ๋Œ€์‘ํ•˜๋Š” Command ์†์„ฑ์„ ์—ฐ๊ฒฐํ•ด ์ฒ˜๋ฆฌํ•˜๊ธฐ๋ณด๋‹ค๋Š” IsChecked ์†์„ฑ์„ binding ํ•ด ViewModel ์—์„œ ์ง์ ‘ ๋ฐ›์•„์„œ ์‚ฌ์šฉํ•˜๋Š” ๊ฒŒ ๋” ๋‚˜์€ ์„ ํƒ ๊ฐ™์•„์š”.(์ €๋ผ๋ฉด ๊ทธ๋ ‡๊ฒŒ ํ•˜๊ฒ ์ˆจโ€ฆ)

  3. ์ด๋ฒคํŠธ๋ฅผ ํ™•์ธํ•˜๋Š” ๋ฐฉ๋ฒ•์€ VS์˜ visual tree ๋‚˜โ€ฆ ์ €๋Š” snoop ์• ์šฉํ•ฉ๋‹ˆ๋‹คโ€ฆ(์˜›๋‚  ์‚ฌ๋žŒโ€ฆ ;ใ……;)

์žฌํ˜„๊ฐ€๋Šฅํ•œ ์†Œ์Šค ์ฝ”๋“œ๋Š” ๋ง ๊ทธ๋Œ€๋กœ vs ๋กœ ์—ด์—ˆ์„ ๋•Œ ๋กœ๋”ฉ ๊ฐ€๋Šฅํ•œ ์ˆ˜์ค€ ํ˜น์€ ์ ์–ด๋„ @dimohy ์˜ ์˜ˆ์ œ ์ •๋„ ์ˆ˜์ค€์„ ์–˜๊ธฐํ•ฉ๋‹ˆ๋‹ท ใ…‡ใ……ใ…‡/

2๊ฐœ์˜ ์ข‹์•„์š”

ํ™”๋ฉด๋งˆ๋‹ค ๋™์ผํ•œ ๊ธฐ๋Šฅ์„ ํ•˜๋Š” control์ด ํ•„์š”ํ•ด์„œ ์œ ์ €์ปจํŠธ๋กค๋กœ ๋งŒ๋“ค์—ˆ๋Š”๋ฐ ๊ฐ ํ™”๋ฉดํ•˜๋‹ค ์ฒ˜๋ฆฌ๋ฅผ ์–ด์ฐŒํ•˜๋‚˜ ๊ณ ๋ฏผํ–ˆ๋Š”๋ฐ,โ€ฆ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค~!!

1๊ฐœ์˜ ์ข‹์•„์š”