두 테이블 간 조인을 할때 NOT IN 조건으로 JOIN 을 할 경우 처리하는 방법이다.

아래 예제 에서는 B 테이블의 value 컬럼의 내용을 NOT IN 조건으로 처리한다.

1. 

SELECT  A.*
FROM    A LEFT JOIN B ON A.value = B.value
WHERE   B.value IS NULL


2.

SELECT  A.*
FROM    A
WHERE   value NOT IN
(
SELECT  value
FROM    B
)

3.

SELECT  A.*
FROM    A
WHERE   NOT EXISTS
(
SELECT  value
FROM    B
WHERE   B.value = A.value
)


value 컬럼이 인덱스처리가 된 경우 성능차이는 없다고 한다.

그러나 value 컬럼이 NOT NULL임을 보장하지 않는 경우 하위 쿼리 결과 집합에 NULL 값이 있는지 여부에 따라 

다른 결과가 생성되므로 NOT IN 대신 LEFT JOIN / IS NULL 또는 NOT EXISTS를 사용해야한다.

참고

https://explainextended.com/2009/09/17/not-in-vs-not-exists-vs-left-join-is-null-oracle/

아래 코드를 이용하면 캡쳐를 방지할 수 있습니다.

using System;

using System.Drawing;

using System.Runtime.InteropServices;

using System.Windows.Forms;


namespace WindowsFormsApp

{

    public partial class MainForm : Form

    {

        private const uint WDA_NONE = 0;

        private const uint WDA_MONITOR = 1;


        [DllImport("user32.dll")]

        private static extern uint SetWindowDisplayAffinity(IntPtr windowHandle, uint affinity);


        public MainForm()

        {

            InitializeComponent();


            this.onButton.Click  += OnButton_Click;

            this.offButton.Click += OffButton_Click;

        }


        private void OnButton_Click(object sender, EventArgs e)

        {

            this.onButton.BackColor  = Color.White;

            this.offButton.BackColor = Color.Transparent;


            SetWindowDisplayAffinity(this.Handle, WDA_MONITOR);

        }


        private void OffButton_Click(object sender, EventArgs e)

        {

            this.onButton.BackColor  = Color.Transparent;

            this.offButton.BackColor = Color.White;


            SetWindowDisplayAffinity(this.Handle, WDA_NONE);

        }

    }

}



* 캡쳐도구를 이용해 캡쳐방지를 하지 않고 했을 때와  캡쳐방지를 켜고 했을 때 비교

(캡쳐방지를 켠 경우에는 녹화할 때도 검게변한다^^)


반디캠, 칼무리, 캡쳐도구, Print Screen 을 이용해 캡쳐 동작을 취할경우 검은 화면으로 보이게 된다.

메서드 호출시 메서드 안에서 어디에서 호출된 것인지 알고 싶을때가 있다

특히 로그 남길 때 유용하게 쓸수 있다.

아래 코드 처럼 메서드 인자로 [CallerMemberName], [CallerFilePath], [CallerLineNumber] 를 선언해 주면 알아서 내용이 들어가게된다.


using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Windows.Forms;

namespace CompilerServicesTest
{
    public partial class TestForm : Form
    {
        public TestForm()
        {
            InitializeComponent();

            CallMethod();
        }

        private void CallMethod()
        {
            WriteLog("CompilerServices Test!!");
        }

        private void WriteLog(string message,
           [CallerMemberName] string memberName = "",
           [CallerFilePath]   string sourceFilePath = "",
           [CallerLineNumber] int sourceLineNumber = 0)
        {
            Trace.WriteLine("message: " + message);
            Trace.WriteLine("member name: " + memberName);
            Trace.WriteLine("source file path: " + sourceFilePath);
            Trace.WriteLine("source line number: " + sourceLineNumber);
        }
    }
}



참고

https://docs.microsoft.com/ko-kr/dotnet/csharp/language-reference/attributes/caller-information

일반적으로 GridView 에서 키보드로 포커스이동이 아래 처럼 포커스가 행의 끝으로 가면

다음 행으로 넘어가게 되어있다.

이를 다음행으로 넘어가지 않고 그 행에 두고 싶다면 아래 코드를 추가해 주면된다.

this.gridView.OptionsNavigation.AutoMoveRowFocus = false;

아래 처럼 포커스 이동시 다음행으로 넘어가지 않는다.


XtraGrid 의 GridView 의 KeyDown 이벤트는 Cell 내부 값을 입력하는 경우에 이벤트가 발생되지 않는다.

Cell 내부의 KeyDown 이벤트를 주고싶은때는 

GridControl 의 EditorKeyDown 이벤트를 사용하면 된다.


아래코드를 보면 알수 있지만 Cell 값 편집모드에서 GridView 의 KeyDown 이벤트는 처리 되지 않는다.

        this.gridView.KeyDown += GridView_KeyDown;


        private void GridView_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.V && e.Control)
            {
                string clipBoard = Clipboard.GetText();

                if (!string.IsNullOrEmpty(clipBoard))
                {
                    MessageBox.Show(clipBoard);
                }
            }
        }

     

하지만 아래처런 GridControl 의 EditorKeyDown 이벤트로 처리하면 Cell 값 편집모드에서 KeyDown 이벤트가 처리된다.

        this.gridControl.EditorKeyDown += GridControl_EditorKeyDown;


        private void GridControl_EditorKeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.V && e.Control)
            {
                string clipBoard = Clipboard.GetText();

                if (!string.IsNullOrEmpty(clipBoard))
                {
                    MessageBox.Show(clipBoard);
                }
            }
        }


하단에 메뉴가 있고 배경이 여러이미지로 슬라이딩되면서 변경되는 화면을 구성하는 방법을 소개한다.


우선 Grid 를 배치하고 Grid 안으로 CarouselView 를 위치하고 좌측 상단에 로고 이미지를

하단에는 메뉴 아이콘을 배치했으며 이미지가 가로로 스크롤이 되도록 CarouselView 의  ItemsLayout 속성을 "HorizontalList" 으로 설정한다.

<?xml version="1.0" encoding="utf-8" ?>

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"

             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"

             xmlns:d="http://xamarin.com/schemas/2014/forms/design"

             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"

             mc:Ignorable="d"

             x:Class="SlideImage.MainPage">


    <StackLayout Margin="0" Padding="0" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" BackgroundColor="Black">

        <Grid HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" Margin="0" Padding="0" ColumnSpacing="0" RowSpacing="0" BackgroundColor="White">

            <CarouselView  x:Name="mainView" ItemsLayout="HorizontalList" Margin="0" BackgroundColor="LightYellow" HorizontalScrollBarVisibility="Always">

                <CarouselView.ItemTemplate>

                    <DataTemplate>

                        <Image Source="{Binding ImageSrc}" Aspect="Fill"/>

                    </DataTemplate>

                </CarouselView.ItemTemplate> 

            </CarouselView>


            <Image Source="keisoft_textlogo.png" WidthRequest="100" HeightRequest="30" VerticalOptions="Start" HorizontalOptions="Start" Margin="10,0,0,0"/>


            <StackLayout VerticalOptions="End" Padding="0,0,0,20" HorizontalOptions="Center" Orientation="Horizontal" Spacing="20">

                <Image Source="main_store.png" WidthRequest="60" HeightRequest="60" >

                    <Image.GestureRecognizers>

                        <TapGestureRecognizer Tapped="StoreButton_Clicked"></TapGestureRecognizer>

                    </Image.GestureRecognizers>

                </Image>

                <Image Source="main_menu.png" WidthRequest="60" HeightRequest="60" >

                    <Image.GestureRecognizers>

                        <TapGestureRecognizer Tapped="MenuButton_Clicked"></TapGestureRecognizer>

                    </Image.GestureRecognizers>

                </Image>

                <Image Source="main_order.png" WidthRequest="60" HeightRequest="60" >

                    <Image.GestureRecognizers>

                        <TapGestureRecognizer Tapped="CartButton_Clicked"></TapGestureRecognizer>

                    </Image.GestureRecognizers>

                </Image>

                <Image Source="main_member.png" WidthRequest="60" HeightRequest="60" >

                    <Image.GestureRecognizers>

                        <TapGestureRecognizer Tapped="PersonButton_Clicked"></TapGestureRecognizer>

                    </Image.GestureRecognizers>

                </Image>

            </StackLayout>

        </Grid>

    </StackLayout>

</ContentPage>


여기에 일정 시간 간격으로 이미지가 자동으로 스크롤이 되도록 Timer 를 이용해 처리하면 아래 와 같은 화면이 완성된다.

Device.StartTimer(TimeSpan.FromSeconds(3), (Func<bool>)(() =>
{
    this.mainView.Position = (this.mainView.Position + 1) % 3;
    return true;
}));


자동으로 가로로 스크롤 되며 터치로도 슬라이드 동작을 하면 스크롤 된다.


* 이미지는 저작권이 있으므로 마음대로 쓰면 안됨.


소스

https://github.com/kei-soft/Slide-Image

Grid 에 Data 가 정형화 되어있지 않은 경우 특정 셀의 컬럼에 길이 제한을 두고 싶을 때 사용하는 방법이다.

아래는 LOT 컬럼이 5자가 넘는 경우 처리하는 방법으로 아래처럼 표시가 된다.

using System.Collections.Generic;
using System.Windows.Forms;

using DevExpress.XtraGrid.Views.Grid.ViewInfo;

namespace WindowsFormsApp
{
    public partial class MainForm : Form

    {
        public MainForm()
        {
            InitializeComponent();

            this.gridView.ValidatingEditor += GridView_ValidatingEditor;

            TestData testData1 = new TestData();
            testData1.LOT = "L001";
            testData1.WAFER = "01";

            TestData testData2 = new TestData();
            testData2.LOT = "L001";
            testData2.WAFER = "02";

            List<TestData> testDatas = new List<TestData>();
            testDatas.Add(testData1);
            testDatas.Add(testData2);
            this.gridControl.DataSource = testDatas;
        }

        void GridView_ValidatingEditor(object sender, DevExpress.XtraEditors.Controls.BaseContainerValidateEditorEventArgs e)
        {
            string value_string = e.Value.ToString();
            GridViewInfo viewInfo = gridView.GetViewInfo() as GridViewInfo;
            GridCellInfo cellInfo = viewInfo.GetGridCellInfo(gridView.FocusedRowHandle, gridView.FocusedColumn);

            if (cellInfo.Column.FieldName == "LOT")
            {
                if (value_string.Length > 5)
                {
                    e.ErrorText = "The value is too long";
                    e.Valid = false;
                }
            }
        }

        class TestData
        {
            public string LOT { get; set; }
            public string WAFER { get; set; }
        }
    }
}


TEST 테이블의 A 컬럼에 아래와 같이 데이터가 있을 때

A


A 컬럼의 데이터를 모두 ,(콤마) 로 연결하여 하나의 데이터("가,나,다")로 나타내고 싶은 경우

아래 처럼 listagg 를 이용해 쿼리하면 된다.


SELECT LISTAGG(A,' ,') RESULT FROM TEST


결과>

RESULT

가,나,다



GridView 의 BestFitColumns() 는 데이터 길이에 따라 컬럼 너비를 자동으로 조절해 준다.

하지만 데이터가 많은 경우 컬럼 길이 계산을 위해 시간을 많이 소비해서

실제 화면에 보여지는데 시간이 걸린다.

이때 아래처럼 BestFitMaxRowCount 값을 설정하게되면 

데이터 전체가 아닌 특정 Row 까지의 데이터만 가지고 처리를 하게되어

화면에 보여지는데 걸리는 시간을 줄일 수 있다.


this.gridControl.DataSource = testDatas;

this.gridView.OptionsView.BestFitMaxRowCount = 100;

this.gridView.BestFitColumns();


XtraGrid 에 데이터 바인딩을 하면 처음 Row 를 선택하고 있는데

이를 선택하지 않는 상태로 변경하기 위해서는


데이터 바인딩을 하고

this.gridContro.DataSource = testDatas;


아래처럼 GridView 의 FocusInvalidRow() 를 호출해 주면된다.

this.gridView.FocusInvalidRow();

+ Recent posts