A.exe에서 B.dll을 컴파일시 참조하지 않고  동적으로 참조할 때,

 

B.dll에 있는 특정 클래스 메서드의 파라미터(Delegate)를 넘길때 방법입니다. 

 

리플렉션을 이용해서 대리자 개체를 생성 후 Invoke 파라미터에 넘겨주었습니다.

 

A.exe

 

 

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.Linq;

using System.Reflection;

using System.Text;

using System.Threading.Tasks;

using System.Windows.Forms;

 

namespace DelegateReflaction

{

    public partial class Form1 : Form

    {

        public Form1()

        {

            InitializeComponent();

            InvokeTest();

        }

 

        private void InvokeTest()

        {

            string dllFilePath = @"D:\Work\Project\Test\DelegateReflaction\TestLibrary\bin\Debug\TestLibrary.dll";

            Assembly assembly = Assembly.LoadFile(dllFilePath);

 

            Type formType = assembly.GetType("TestLibrary.ChiForm");

 

            //Child 델리게이트 타입 가져오기

            Type deleType = assembly.GetTypes().Single(a => a.Name == "CallbackDelegate");

 

 

            //현재 클래스의 Callback 메서드 정보 가져오기

            MethodInfo callBackMethodInfo = this.GetType().GetMethod("Callback", BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] { typeof(string) }, null);

 

            //Child CallbackDelegate Delegate를 이용해서 Deleagte 생성

            Delegate callbackMethod = Delegate.CreateDelegate(deleType, this, callBackMethodInfo);

 

            //Child 폼 생성

            Form form = Activator.CreateInstance(formType) as Form;

 

            //Child DoWork 메서드 가져오기

            MethodInfo doworkMethodInfo = formType.GetMethod("DoWork");

 

            //파라미터 생성

            object[] parameters = new object[2];

            parameters[0] = "test~";

            parameters[1] = callbackMethod;

 

            //Child Dowork 메서드 호출

            doworkMethodInfo.Invoke(form, parameters);

 

            form.Show();

        }

 

        void Callback(string msg)

        {

            MessageBox.Show(msg);

        }

    }

}

  

 

 

B.dll

 

 

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

using System.Windows.Forms;

 

namespace TestLibrary

{

    public class ChiForm : Form

    {

        public delegate void CallbackDelegate(string status);

 

        public ChiForm()

        {

            InitializeComponent();

        }

 

        public void DoWork(string param, CallbackDelegate callback)

        {

            callback("status");

        }

 

        private void InitializeComponent()

        {

            this.SuspendLayout();

            //

            // ChiForm

            //

            this.ClientSize = new System.Drawing.Size(284, 262);

            this.Name = "ChiForm";

            this.Text = "ChildForm";

            this.ResumeLayout(false);

 

        }

    }

} 

 

 

프로젝트 (vs2015 작성) :  DelegateReflaction.zip

 

'.Net > C#' 카테고리의 다른 글

C# 실행파일 안에 DLL 넣기  (0) 2016.05.16
C# Undo Redo 기능 구현하기  (3) 2015.10.20
C# 원문자 구하기  (0) 2015.10.05
SerialPort Read Blocking 시키기  (0) 2015.08.05
문자열 비교 테스트 (대소문자 무시)  (0) 2015.07.02

Undo 기능에 쓰일 스택과 Redo 기능에 쓰일 스택을 이용해서 Undo, Redo 기능을 구현해보았다.

 

UndoRedoHistory 클래스에서는 특정 타입의 상태를 저장할 수 있고, Undo, Redo를 통해 상태 값을 가져온다.

 

 

/// <summary>

    /// Undo Redo 내역을 기록하는 클래스

    /// </summary>

    /// <typeparam name="T">기록할 타입</typeparam>

    public class UndoRedoHistory<T>

    {

        const int DefaultUndoCount = 10;

        RimitedStack<T> undoStack;

        RimitedStack<T> redoStack;

 

        /// <summary>

        /// Undo 기능을 사용할 수 있는지 여부를 가져온다.

        /// </summary>

        public bool IsCanUndo

        {

            get

            {

                //맨 초기 상태때문에 1보다 커야한다.

                return this.undoStack.Count > 1;

            }

        }

 

        /// <summary>

        /// Redo 기능을 사용할 수 있는지 여부를 가져온다.

        /// </summary>

        public bool IsCanRedo

        {

            get { return this.redoStack.Count > 0; }

        }

 

        public UndoRedoHistory()

            :this(DefaultUndoCount)

        {

 

        }

 

        public UndoRedoHistory(int defaultUndoCount)

        {

            undoStack = new RimitedStack<T>(defaultUndoCount);

            redoStack = new RimitedStack<T>(defaultUndoCount);

        }

 

        /// <summary>

        /// 이전 상태를 가져온다.

        /// </summary>

        /// <returns></returns>

        public T Undo()

        {

            T state = this.undoStack.Pop();

            this.redoStack.Push(state);

            return this.undoStack.Peek();

        }

 

        /// <summary>

        /// 이후 상태를 가져온다.

        /// </summary>

        /// <returns></returns>

        public T Redo()

        {

            T state = this.redoStack.Pop();

            this.undoStack.Push(state);

            return state;

        }

 

        /// <summary>

        /// 상태를 추가한다.

        /// </summary>

        /// <param name="state"></param>

        public void AddState(T state)

        {

            this.undoStack.Push(state);

            this.redoStack.Clear();

        }

 

        /// <summary>

        /// 상태를 모두 제거한다.

        /// </summary>

        internal void Clear()

        {

            this.undoStack.Clear();

            this.redoStack.Clear();

        }

    }

 

 

 

 

ReimetedStack은 개수 제한이 있는 스택이다.

 

개수 제한이 걸렸을 때, 맨 처음 삽입한 상태를 제거해야하므로, 내부 자료구조는 사실 Stack이 아닌 List로 구현해놓았다.

 

/// <summary>

/// 개수 제한이 있는 스택 클래스

/// </summary>

internal class LimitedStack<T>

{

    List<T> list = new List<T>();

    readonly int capacity;

    /// <summary>

    /// 개수를 가져온다.

    /// </summary>

    public int Count

    {

        get { return this.list.Count; }

    }

 

    /// <summary>

    /// 생성자

    /// </summary>

    /// <param name="capacity"></param>

    public LimitedStack(int capacity)

    {

        this.capacity = capacity;

    }

 

    /// <summary>

    /// 맨위의 개체를 반환하고 제거한다.

    /// </summary>

    /// <returns></returns>

    internal T Pop()

    {

        T t = this.list[0];

        this.list.RemoveAt(0);

        return t;

    }

 

    /// <summary>

    /// 개체를 맨위에 삽입한다.

    /// </summary>

    /// <param name="state"></param>

    internal void Push(T state)

    {

        this.list.Insert(0, state);

        if (this.list.Count > capacity)

        {

            this.list.RemoveAt(this.list.Count - 1);

        }

    }

 

    /// <summary>

    /// 맨위의 개체를 제거하지 않고 반환한다.

    /// </summary>

    /// <returns></returns>

    internal T Peek()

    {

        return this.list[0];

    }

 

    /// <summary>

    /// 개체를 모두 제거한다.

    /// </summary>

    internal void Clear()

    {

        this.list.Clear();

    }

}

 

 

 

 

아래는 텍스트 박스의 내용을 저장하는 기능을 구현한 데모 코드이다.

 

public partial class Form1 : Form

{

UndoRedoHistory<string> undoRedoHistory = new UndoRedoHistory<string>(10);

 

public Form1()

{

    InitializeComponent();

    SaveCurrentState();

    this.textBox1.KeyDown += TextBox1_KeyDown;

}

 

private void TextBox1_KeyDown(object sender, KeyEventArgs e)

{

    Keys keyData = e.KeyData;

    if ((keyData & Keys.Control) == Keys.Control)

    {

        if ((keyData & Keys.Z) == Keys.Z)

        {

            this.Undo();

        }

        else if ((keyData & Keys.Y) == Keys.Y)

        {

            this.Redo();

        }

    }

}

 

private void Redo()

{

    if (this.undoRedoHistory.IsCanRedo)

    {

        this.textBox1.Text = this.undoRedoHistory.Redo();

    }

}

 

private void Undo()

{

    if (this.undoRedoHistory.IsCanUndo)

    {

        this.textBox1.Text = this.undoRedoHistory.Undo();

    }

}

 

private void btnSave_Click(object sender, EventArgs e)

{

    this.SaveCurrentState();

}

 

/// <summary>

/// 현재 상태를 저장한다.

/// </summary>

private void SaveCurrentState()

{

    undoRedoHistory.AddState(this.textBox1.Text);

}

 

 

 

샘플 프로젝트 :KDYFramework.UndoRedo.zip

 

 

'.Net > C#' 카테고리의 다른 글

C# 실행파일 안에 DLL 넣기  (0) 2016.05.16
C# 리플렉션을 이용한 Delegate 넘기기  (0) 2016.05.11
C# 원문자 구하기  (0) 2015.10.05
SerialPort Read Blocking 시키기  (0) 2015.08.05
문자열 비교 테스트 (대소문자 무시)  (0) 2015.07.02

 

 

위와 같이 PictureBox의 이미지를 투명하게 만드는 코드이다.

 

1. 불러올 파일의 경로의 Image 개체를 생성 

 

2. ChangeOpacity 메서드를 통해 이미지의 알파값을 변경하여 새로운 비트맵 개체 생성

 

3. 생성한 비트맵 개체를 PictureBox Image 속성으로 설정

 

4. 생성한 Image 개체 제거

 

 

public partial class Form1 : Form

{

    public Form1()

    {

        InitializeComponent();

    }

 

    private void btnLoad_Click(object sender, EventArgs e)

    {

        OpenFileDialog of = new OpenFileDialog();

 

        if (of.ShowDialog() == DialogResult.OK)

        {

            try

            {

                this.SetImage(of.FileName);

            }

            catch (Exception ex)

            {

                MessageBox.Show(ex.Message);

            }

        }

    }

 

    private void SetImage(string fileName)

    {

        try

        {

            Image img = Image.FromFile(fileName);

            this.pictureBox1.Image = ChangeOpacity(img, 0.5f);

            img.Dispose();

        }

        catch (Exception ex)

        {

            throw ex;

        }

    }

 

    /// <summary>

    /// 해당 이미지의 투명도를 변경한다.

    /// </summary>

    /// <param name="img"></param>

    /// <param name="opacityvalue"></param>

    /// <returns></returns>

    public Bitmap ChangeOpacity(Image img, float opacityvalue)

    {

        Bitmap bmp = new Bitmap(img.Width, img.Height);

        Graphics graphics = Graphics.FromImage(bmp);

        ColorMatrix colormatrix = new ColorMatrix();

        colormatrix.Matrix33 = opacityvalue;

        ImageAttributes imgAttribute = new ImageAttributes();

        imgAttribute.SetColorMatrix(colormatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);

        graphics.DrawImage(img, new Rectangle(0, 0, bmp.Width, bmp.Height), 0, 0, img.Width, img.Height, GraphicsUnit.Pixel, imgAttribute);

        graphics.Dispose();

        return bmp;

    }

}

 

 

 

vs2015 프로젝트 :  PictureBox투명도.zip

 

출처 : https://raviranjankr.wordpress.com/2011/05/25/change-opacity-of-image-in-c/

+ Recent posts