블로그 이미지
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