블로그 이미지
Kanais
Researcher & Developer 퍼즐을 완성하려면 퍼즐 조각들을 하나 둘씩 맞춰나가야 한다. 인생의 퍼즐 조각들을 하나 둘씩 맞춰나가다 보면 인생이란 퍼즐도 완성되는 날이 오려나...?

calendar

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

Notice

2024. 1. 4. 15:39 Programming/WPF

개발환경

OS : Window 10 x64 ver.22H2

DevTool : VS2019  ver.16.11.29

Framework : .NET Framework 4.8

Other : DevExpress 22.2

 

Canvas에 동적으로 TextBlock을 생성하고, 생성된 TextBlock을 마우스 Drag & Drop으로 위치 변경을 할 수 있는 코드

 

View.xaml

   <ScrollViewer Height="550" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
      <Grid>
          <Canvas x:Name="xRulerCanvas" />
          <ItemsControl x:Name="xItemsControl_Preview" Width="{Binding Width_ItemsControl, UpdateSourceTrigger=PropertyChanged}"
                       Height="{Binding Height_ItemsControl, UpdateSourceTrigger=PropertyChanged}"
                       ItemsSource="{Binding ItemCollection, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                       HorizontalAlignment="Left" VerticalAlignment="Top" Background="White"
                       BorderThickness="1" BorderBrush="DarkGray" Margin="40,40,10,10">
            <ItemsControl.ItemsPanel>
               <ItemsPanelTemplate>
                  <Canvas x:Name="xCanvas_Preview" ClipToBounds="True">
                      <Canvas.Background>
                          <VisualBrush TileMode="Tile" Viewport="{Binding CanvasGridViewport, UpdateSourceTrigger=PropertyChanged}" ViewportUnits="Absolute"
                                       Viewbox="{Binding CanvasGridViewport, UpdateSourceTrigger=PropertyChanged}" ViewboxUnits="Absolute">
                              <VisualBrush.Visual>
                                  <Rectangle Height="{Binding CanvasGridLength, UpdateSourceTrigger=PropertyChanged}"
                                             Width="{Binding CanvasGridLength, UpdateSourceTrigger=PropertyChanged}" Stroke="{StaticResource NormalBorderColor}"
                                             StrokeThickness="1" StrokeDashArray="5 3" />
                              </VisualBrush.Visual>
                          </VisualBrush>
                       </Canvas.Background>
                       <dxmvvm:Interaction.Behaviors>
                           <dxmvvm:EventToCommand Command="{Binding MouseCommand, UpdateSourceTrigger=PropertyChanged}"
                                                  EventName="MouseLeftButtonDown" PassEventArgsToCommand="True"/>
                           <dxmvvm:EventToCommand Command="{Binding MouseCommand, UpdateSourceTrigger=PropertyChanged}"
                                                  EventName="PreviewMouseMove" PassEventArgsToCommand="True"/>
                           <dxmvvm:EventToCommand Command="{Binding MouseCommand, UpdateSourceTrigger=PropertyChanged}"
                                                  EventName="PreviewMouseUp" PassEventArgsToCommand="True"/>
                        </dxmvvm:Interaction.Behaviors>
                     </Canvas>
                  </ItemsPanelTemplate>
               </ItemsControl.ItemsPanel>
               <ItemsControl.ItemContainerStyle>
                  <Style TargetType="ContentPresenter">
                     <Setter Property="Canvas.Left" Value="{Binding Canvas_X}"/>
                     <Setter Property="Canvas.Top" Value="{Binding Canvas_Y}"/>
                  </Style>
               </ItemsControl.ItemContainerStyle>
               <ItemsControl.ItemTemplate>
                  <DataTemplate>
                     <Border BorderBrush="Black" BorderThickness="{Binding TextBorderThick}">
                        <TextBlock Text="{Binding Text}" FontFamily="{Binding FontName}" FontSize="{Binding FontSize}" Margin="{Binding Margin}"
                                   Width="{Binding BarcodeWidth}" Height="{Binding BarcodeHeight}"/>
                     </Border>
                  </DataTemplate>
               </ItemsControl.ItemTemplate>
               <dxmvvm:Interaction.Behaviors>
                  <models:MouseBehavior MouseX="{Binding MouseX, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" 
                                        MouseY="{Binding MouseY, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
               </dxmvvm:Interaction.Behaviors>
            </ItemsControl>
       </Grid>
    </ScrollViewer>

 

 

위 코드의 dxmvvm:Interaction.Behaviors 부분은 아래와 같이 변경해서 사용할 수 있음.

xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" 
<i:Interaction.Triggers> 
   <i:EventTrigger EventName="MouseLeftButtonDown" > 
      <i:InvokeCommandAction Command="{Binding MouseCommand}" /> 
   </i:EventTrigger> 
</i:Interaction.Triggers>

 

 

ViewModel.cs

public class ViewModel : INotifyPropertyChanged
{
    public ObservableCollection<CanvasItem> ItemCollection { get; set; }

    public double MouseX
    {
        get => GetValue<double>();
        set => SetValue(value);
    }

    public double MouseY
    {
        get => GetValue<double>();
        set => SetValue(value);
    }

    public double Width_ItemsControl
    {
        get => GetValue<double>();
        set => SetValue(value);
    }

    public double Height_ItemsControl
    {
        get => GetValue<double>();
        set => SetValue(value);
    }

    public double CanvasGridLength
    {
        get => GetValue<double>();
        set => SetValue(value);
    }

    public Rect CanvasGridViewport
    {
        get => GetValue<Rect>();
        set => SetValue(value);
    }


    private double originMouseX = -1, originMouseY = -1;
    private int mouseSelectedIndex = -1;
    private bool isMove = false;
    
    public ICommand<object> MouseCommand => new DelegateCommand<object>(MouseCommandMethod);
    
    public PamProPrintManagementViewModel()
    {
        InitData();
        ItemCollection = new ObservableCollection<CanvasItem>();
    }
    
    private void InitData()
    {
        Width_ItemsControl = MAXIMUM_X_POSITION;
        Height_ItemsControl = MAXIMUM_Y_POSITION;
        CanvasGridLength = 50;
        CanvasGridViewport = new Rect(0, 0, 50, 50);
    }
    
    private void MouseCommandMethod(object obj)
    {
        try
        {
            if (obj != null)
            {
                MouseEventArgs param = obj as MouseButtonEventArgs;
                if (param == null)
                {
                    param = obj as MouseEventArgs;
                }

                if (param != null)
                {
                    switch (param.RoutedEvent.Name)
                    {
                        case "MouseLeftButtonDown": MouseDownCommand(param); break;
                        case "PreviewMouseMove": MouseMoveCommand(param); break;
                        case "PreviewMouseUp": MouseUpCommand(); break;
                        default: break;
                    }
                }
            }
        }
        catch (Exception e)
        {
            Log.Error(e.Message);
        }
    }

    private void MouseDownCommand(MouseEventArgs param)
    {
        try
        {
            int index = SearchSelectedControlIndex(param);

            if (index == -1)
            {
                mouseSelectedIndex = -1;
                return;
            }

            if (index != -1)
            {
                mouseSelectedIndex = index;
                isMove = true;
            }

        }
        catch (Exception e)
        {
            Log.Error(e.Message);
        }
    }

    private int SearchSelectedControlIndex(MouseEventArgs param)
    {
        try
        {
            if (ItemCollection != null && ItemCollection.Count > 0)
            {
                TextBlock control = param.Source as TextBlock;
                double x, y, width, height;

                string key = ((CanvasItem)((FrameworkElement)param.Source).DataContext).Item_key;

                if (control != null)
                {
                    for (int i = 0; i < ItemCollection.Count; i++)
                    {
                        if (ItemCollection[i].Item_key == key)
                        {
                            x = (int)PrintDataCollection[i].Canvas_X;
                            y = (int)PrintDataCollection[i].Canvas_Y;
                            width = control.ActualWidth;
                            height = control.ActualHeight;

                            if (x <= MouseX && y <= MouseY)
                            {
                                if (x + width >= MouseX && y + height >= MouseY)
                                {
                                    originMouseX = MouseX;
                                    originMouseY = MouseY;
                                    return i;
                                }
                            }
                        }
                    }
                }
            }
        }
        catch (Exception e)
        {
            Log.Error(e.Message);
        }

        return -1;
    }

    private void MouseMoveCommand(MouseEventArgs param)
    {
        try
        {
            if (mouseSelectedIndex == -1)
            {
               return;
            }

            if (isMove)
            {
                double t_x = MouseX - originMouseX;
                double t_y = MouseY - originMouseY;
                originMouseX = MouseX;
                originMouseY = MouseY;
                ItemCollection[mouseSelectedIndex].Canvas_X += t_x;
                ItemCollection[mouseSelectedIndex].Canvas_Y += t_y;

                if (ItemCollection[mouseSelectedIndex].Canvas_Y < 0)
                {
                    ItemCollection[mouseSelectedIndex].Canvas_Y = 0;
                }
                else if (ItemCollection[mouseSelectedIndex].Canvas_Y >= Height_ItemsControl - 20)
                {
                    ItemCollection[mouseSelectedIndex].Canvas_Y = Height_ItemsControl - 20;
                }
                if (ItemCollection[mouseSelectedIndex].Canvas_X < 0)
                {
                    ItemCollection[mouseSelectedIndex].Canvas_X = 0;
                }
                else if (ItemCollection[mouseSelectedIndex].Canvas_X >= Width_ItemsControl - 20)
                {
                    ItemCollection[mouseSelectedIndex].Canvas_X = Width_ItemsControl - 20;
                }
            }
        }
        catch (Exception e)
        {
            Log.Error(e.Message);
        }
    }

    private void MouseUpCommand()
    {
        isMove = false;
        originMouseX = 0;
        originMouseY = 0;
    }    
    
}

 

CanvasItem.cs

    public class CanvasItem
    {
        public string Item_key
        {
            get => GetValue<string>();
            set => SetValue(value);
        }
        public double Canvas_X
        {
            get => GetValue<double>();
            set => SetValue(value);
        }
        public double Canvas_Y
        {
            get => GetValue<double>();
            set => SetValue(value);
        }
        public string Text
        {
            get => GetValue<string>();
            set => SetValue(value);
        }
        public string FontName
        {
            get => GetValue<string>();
            set => SetValue(value);
        }
        public FontWeight Bold
        {
            get => GetValue<FontWeight>();
            set => SetValue(value);
        }
        public double FontSize
        {
            get => GetValue<double>();
            set => SetValue(value);
        }
        public Thickness TextBorderThick
        {
            get => GetValue<Thickness>();
            set => SetValue(value);
        }
        public Thickness Margin
        {
            get => GetValue<Thickness>();
            set => SetValue(value);
        }
    }
posted by Kanais
2024. 1. 4. 10:57 Programming/WPF

개발환경

OS : Window 10 x64 ver.22H2

DevTool : VS2019  ver.16.11.29

Framework : .NET Framework 4.8

Other : DevExpress 22.2

 

ScrollViewer에 ListBox를 배치하고 동적으로 CustomControl을 생성 및 삭제 하는 방법에 대한 글임.

CustromControl은 Label을 2개 가지고 있는 Control이며, MultiTrigger를 사용해서 Selected, Focused Conditions을 추가함

 

WPF MVVM 패턴을 사용함.

 

View.xaml

<ScrollViewer VerticalScrollBarVisibility="Auto">
   <ListBox Width="320" Height="400" BorderThickness="0"
            SelectedItem="{Binding SelectedItem, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
            SelectedIndex="{Binding SelectedIndex, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
            ItemsSource="{Binding ItemCollection, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
      <ListBox.Resources>
         <Style TargetType="ListBoxItem">
            <Setter Property="Template">
               <Setter.Value>
                  <ControlTemplate TargetType="ListBoxItem">
                     <Border BorderThickness="{TemplateBinding Border.BorderThickness}"
                             Padding="{TemplateBinding Control.Padding}"
                             BorderBrush="{StaticResource BorderBrushColor}"
                             CornerRadius="5" Height="50" Margin="0,5,0,5"
                             Name="Bd" SnapsToDevicePixels="True">
                        <ContentPresenter x:Name="content" Content="{TemplateBinding ContentControl.Content}" 
                                          ContentTemplate="{TemplateBinding ContentControl.ContentTemplate}"
                                          ContentStringFormat="{TemplateBinding ContentControl.ContentStringFormat}"
                                          HorizontalAlignment="{TemplateBinding Control.HorizontalContentAlignment}"
                                          VerticalAlignment="{TemplateBinding Control.VerticalContentAlignment}"
                                          SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" />
                      </Border>
                      <ControlTemplate.Triggers>
                         <MultiTrigger>
                            <MultiTrigger.Conditions>
                               <Condition Property="Selector.IsSelectionActive" Value="False"/>
                               <Condition Property="Selector.IsSelected" Value="True"/>
                            </MultiTrigger.Conditions>
                            <Setter Property="Panel.Background" TargetName="Bd" Value="{StaticResource TwoLableBGColor_mouseOver}"/>
                            <Setter Property="Border.BorderBrush" TargetName="Bd" Value="Transparent"/>
                         </MultiTrigger>
                         <MultiTrigger>
                            <MultiTrigger.Conditions>
                                <Condition Property="Selector.IsSelectionActive" Value="True"/>
                                <Condition Property="Selector.IsSelected" Value="True"/>
                            </MultiTrigger.Conditions>
                            <Setter Property="Panel.Background" TargetName="Bd" Value="{StaticResource TwoLableBGColor_checked}"/>
                            <Setter Property="Foreground" Value="{StaticResource TwoLableFontColor_checked}"/>
                            <Setter Property="Border.BorderBrush" TargetName="Bd" Value="Transparent"/>
                         </MultiTrigger>
                         <Trigger Property="UIElement.IsMouseOver" Value="True">
                            <Setter Property="Panel.Background" TargetName="Bd" Value="{StaticResource TwoLableBGColor_mouseOver}"/>
                            <Setter Property="Foreground" Value="{StaticResource TwoLableFontColor_checked}"/>
                            <Setter Property="Border.BorderBrush" TargetName="Bd" Value="Transparent"/>
                         </Trigger>
                         <Trigger Property="UIElement.IsEnabled" Value="False">
                            <Setter Property="TextElement.Foreground" TargetName="Bd">
                               <Setter.Value>
                                  <DynamicResource ResourceKey="{x:Static SystemColors.GrayTextBrushKey}" />
                               </Setter.Value>
                            </Setter>
                         </Trigger>
                      </ControlTemplate.Triggers>
                   </ControlTemplate>
                </Setter.Value>
             </Setter>
          </Style>
       </ListBox.Resources>
       <dxmvvm:Interaction.Behaviors>
          <dxmvvm:EventToCommand EventName="SelectionChanged" Command="{Binding SelectedButtonCommand}" CommandParameter="{Binding SelectedItem}"/>
       </dxmvvm:Interaction.Behaviors>
   </ListBox>
</ScrollViewer>

 

 

ViewModel.cs

View의 DataContext Class

    public class ViewModel
    {
        public ObservableCollection<TwoLabel> ItemCollection { get; set; }

        public int SelectedIndex
        {
            get => GetValue<int>();
            set => SetValue(value);
        }

        public object SelectedItem
        {
            get => GetValue<object>();
            set => SetValue(value);
        }

        public ICommand ButtonCommand => new DelegateCommand<object>(ButtonCommandMethod);
        public ICommand<object> SelectedButtonCommand => new DelegateCommand<object>(SelectedButtonCommandMethod);

        public PamProUserViewModel()
        {
            ItemCollection = new ObservableCollection<PamProTwoLabel>();
        }

        private void ButtonCommandMethod(object obj)
        {
            string param = obj as string;
            switch (param)
            {
                case "add": AddUserButtonCommandMethod(); break;
                default: break;
            }
        }

        private void AddUserButtonCommandMethod()
        {
            TwoLabel button = new TwoLabel()
            {
                ButtonCode = DateTime.Now.ToString(),
                TextTitle = "Operator",
                TextDescription = "Description"
            };
            button.SetText("Operator", "Description");
            ItemCollection.Add(button);
        }

        private void SelectedButtonCommandMethod(object obj)
        {
            if (obj is TwoLabel button)
            {
                string code = button.ButtonCode;
                for (int i = 0; i < ItemCollection.Count; i++)
                {
                    if (ItemCollection[i].ButtonCode == code)
                    {
                        ItemCollection[i].SetForeground("select");
                    }
                    else
                    {
                        ItemCollection[i].SetForeground("unSelect");
                    }
                }
            }
        }
    }

 

 

CustomControl  TwoLabel

namespace CommonControls.Views
{
    [ToolboxItem(true)]
    public class TwoLabel : Label, INotifyPropertyChanged
    {
        #region properties

        [Category("버튼코드"), Description("용어코드")]
        public string ButtonCode { get; set; }
        
        [Category("TextTitle"), Description("지정할 텍스트")]
        public string TextTitle { get; set; }

        [Category("TextDescription"), Description("버튼 설명")]
        public string TextDescription { get; set; }

        #endregion

        #region Layout Controls

        private TextBlock descriptionTextBlock;
        public TextBlock DescriptionTextBlockControl
        {
            get => descriptionTextBlock;
            set
            {
                descriptionTextBlock = value;
                OnPropertyChangedMethod("DescriptionTextBlockControl");
            }
        }
        private TextBlock titleTextBlock;
        public TextBlock TitleTextBlockControl
        {
            get => titleTextBlock;
            set
            {
                titleTextBlock = value;
                OnPropertyChangedMethod("TitleTextBlockControl");
            }
        }

        #endregion

        public TwoLabel() : base()
        {
            SetDefaultProperties();
            CreateContent();
            CreateStyle();
        }

        public event PropertyChangedEventHandler PropertyChanged;

        // Set default properties of PamProIconDescriptionButton
        private void SetDefaultProperties()
        {
            HorizontalContentAlignment = HorizontalAlignment.Stretch;
            VerticalContentAlignment = VerticalAlignment.Center;
            Loaded += OnLoaded;
        }

        private void OnPropertyChangedMethod([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }

        // IconDescriptionButton Style setting
        private void CreateStyle()
        {
            Height = 50;
            MinWidth = 200;
            Margin = new Thickness(0, 5, 0, 5);
            Background = new SolidColorBrush(Colors.Transparent);
            BorderThickness = new Thickness(0);
            BorderBrush = new SolidColorBrush(Colors.Transparent);
            VerticalAlignment = VerticalAlignment.Center;
        }

        // Create the IconDescriptionButton Content layout
        private void CreateContent()
        {
            StackPanel rootStackPanel = CreateStackPanel();

            TitleTextBlockControl = CreateTitleLabelContent();
            DescriptionTextBlockControl = CreateDescLabelContent();

            _ = rootStackPanel.Children.Add(TitleTextBlockControl);
            _ = rootStackPanel.Children.Add(DescriptionTextBlockControl);

            Content = rootStackPanel;
        }

        // Create title Label control
        private TextBlock CreateTitleLabelContent()
        {
            TextBlock titleLabel = new TextBlock
            {
                Width = 80,
                FontSize = 20,
                FontWeight = FontWeights.Bold,
                Foreground = Brushes.Black,
                VerticalAlignment = VerticalAlignment.Center,
                HorizontalAlignment = HorizontalAlignment.Left,
                Margin = new Thickness(6, 0, 0, 0)
            };

            return titleLabel;
        }

        // Create StackPanel controls (root, branch)
        private StackPanel CreateStackPanel()
        {
            StackPanel stackPanel = new StackPanel
            {
                VerticalAlignment = VerticalAlignment.Center,
                Background = Brushes.Transparent
            };

            stackPanel.Orientation = Orientation.Horizontal;

            return stackPanel;
        }

        // Craete description Label control
        private TextBlock CreateDescLabelContent()
        {
            TextBlock descLabel = new TextBlock
            {
                FontSize = 12,
                TextWrapping = TextWrapping.Wrap,
                Foreground = Brushes.Black,
                VerticalAlignment = VerticalAlignment.Center,
                HorizontalAlignment = HorizontalAlignment.Stretch,
                Margin = new Thickness(15, 0, 0, 0)
            };

            return descLabel;
        }
        

        private void OnLoaded(object sender, RoutedEventArgs e)
        {
            TitleTextBlockControl.Text = TextTitle;
            DescriptionTextBlockControl.Text = TextDescription;
        }

        public void SetText(string _title, string _desc)
        {
            if (_title != null && !_title.Equals(""))
            {
                TitleTextBlockControl.Text = _title;
                TextTitle = _title;
            }
            if (_desc != null && !_desc.Equals(""))
            {
                DescriptionTextBlockControl.Text = _desc;
                TextDescription = _desc;
            }
        }

        public void SetForeground(string isSelection)
        {
            if (isSelection.Equals("select"))
            {
                DescriptionTextBlockControl.Foreground = new SolidColorBrush(Colors.White);
                TitleTextBlockControl.Foreground = new SolidColorBrush(Colors.White);
            }
            else
            {
                DescriptionTextBlockControl.Foreground = new SolidColorBrush(Colors.Black);
                TitleTextBlockControl.Foreground = new SolidColorBrush(Colors.Black);
            }
        }
    }
}

 

 

posted by Kanais
2023. 2. 17. 10:06 Programming/WPF

참고 : https://sosobaba.tistory.com/441

 

C# .Net Array.Copy() 바이트 복사

안녕하세요 마블랑입니다. 윈도우에서 소켓통신이나 시리얼 통신 등 통신 프로그램을 만들때 보통 바이트 단위로 데이터를 주고 받습니다. 그래서 바이트 단위로 데이터를 잘 다룬다면 어렵게

sosobaba.tistory.com

 

1. Array.Copy(byte[] source, int sourceIndex, byte[] destination, int destinationIndex, int length)

  - source : 복사 할 byte 배열

  - sourceIndex : 복사 할 byte 배열의 시작 index

  - destination : 저장 할 byte 배열

  - destinationIndex : 저장 할 byte 배열의 시작 index

  - length : 저장 할 data  길이

 

2. Array.Clear(byte[] array, int index, int length)

  -  array : 초기화 할 배열

  -  index : 초기화 할 배열의 시작 index

  -  length : 배열에서 초기화 할 data 길이

 

3. Array.Sort(byte[] array)

  - 오름차순 정렬

 

Array.Reverse(byte[] array) 

  - 내림차순 정렬

posted by Kanais