728x90
반응형

컨트롤의 Background 를 Transparent 로 하게되면

해당 컨트롤 뒤쪽에 배치된 컨트롤들에 마우스 오버이벤트나 툴팁처리를 한경우 작동하지 않게됩니다.

하지만 Background 를 {x:Null} 로 지정하게되면

뒤쪽에 배치된 컨트롤들의 이벤트 처리가 가능해 집니다.

 

아래처럼 {x:Null} 로 된 경우 ToolTip 이 제대로 표시되지만 

    <Grid>
        <Label Content="null 과 transoarent" ToolTip="ToolTip!!" Height="30" Width="300"/>
        <Border Name="Button1" Height="30" Width="300" BorderBrush="Yellow" Background="{x:Null}" BorderThickness="1"/>
    </Grid>

아래처럼 Transparent 로 된 경우 ToolTip 이 표시되지 않습니다.

    <Grid>
        <Label Content="null 과 transoarent" ToolTip="ToolTip!!" Height="30" Width="300"/>
        <Border Name="Button1" Height="30" Width="300" BorderBrush="Yellow" Background="Transparent" BorderThickness="1"/>
    </Grid>

728x90
반응형
728x90
반응형

Gradient 를 파랑(0) 초록(0.5) 노랑(1) 으로 표현을 한 경우

% 에 따른 색상을 구할때 사용한다.

 

        #region GetColorByOffset(double)

        /// <summary>

        /// Gradient 색의 offset 값을 구합니다.

        /// </summary>

        /// <param name="offset"></param>

        /// <returns></returns>

        private Color GetColorByOffset(double offset)

        {

            GradientStopCollection collection = new GradientStopCollection(3);

            collection.Add(new GradientStop(Colors.Blue, 0));

            collection.Add(new GradientStop(Colors.Green, 0.5));

            collection.Add(new GradientStop(Colors.Yellow, 1));

 

            GradientStop[] stops = collection.OrderBy(x => x.Offset).ToArray();

            if (offset <= 0) return stops[0].Color;

            if (offset >= 1) return stops[stops.Length - 1].Color;

            GradientStop left = stops[0], right = null;

            foreach (GradientStop stop in stops)

            {

                if (stop.Offset >= offset)

                {

                    right = stop;

                    break;

                }

                left = stop;

            }

 

            //Debug.Assert(right != null);

            offset = Math.Round((offset - left.Offset) / (right.Offset - left.Offset), 2);

            byte a = (byte)((right.Color.A - left.Color.A) * offset + left.Color.A);

            byte r = (byte)((right.Color.R - left.Color.R) * offset + left.Color.R);

            byte g = (byte)((right.Color.G - left.Color.G) * offset + left.Color.G);

            byte b = (byte)((right.Color.B - left.Color.B) * offset + left.Color.B);

            return Color.FromArgb(a, r, g, b);

        }

        #endregion

 

728x90
반응형
728x90
반응형
/// <summary>
/// Random Color
/// </summary>
/// <returns></returns>
private Brush RandomBrush()
{
    Brush result = Brushes.Transparent;

    Random random = new Random();

    Type brushesType = typeof(Brushes);

    PropertyInfo[] properties = brushesType.GetProperties();

    int randomValue = random.Next(properties.Length);
    result = (Brush)properties[randomValue].GetValue(null, null);

    return result;
}

 

728x90
반응형
728x90
반응형

UpdateSourceTrigger 속성은 바인딩 소스 업데이트 타이밍을 결정하는 값을 가져오거나 설정할때 사용되는 속성입니다.

 

Default

Text속성의 기본값은 LostFocus이지만, 대부분의 종속성 속성의 기본값은 PropertyChanged입니다.

 

PropertyChanged

바인딩 대상 속성이 변경될 때마다 바인딩 소스를 즉시 업데이트합니다.

 

LostFocus

바인딩 대상 요소가 포커스를 잃을 때마다 바인딩 소스를 업데이트합니다.

 

Explicit

UpdateSource 메서드를 호출할 때만 바인딩 소스를 업데이트합니다.


예)

 BindingExpression bindingExpression = textBox.GetBindingExpression(TextBox.TextProperty);

 bindingExpression.UpdateSource();


 

 

* 간단히 말하면 커서가 벗어난 경우(LostFocus) 속성변경 처리를 할것이냐 아니면 실시간으로(PropertyChanged) 반영할것이냐라고 보면 될것같습니다.

 

아래는 간단한 예시입니다.

 

MainWindow.xaml

<Window x:Class="UpdateSourceTriggerTest.MainWindow"

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"

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

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

        mc:Ignorable="d"

        Title="MainWindow" Height="190" Width="394.666">

    <Grid>

        <StackPanel>

            <Label Content="UpdateSourceTrigger=PropertyChanged"/>

            <TextBox Text="{Binding Name, UpdateSourceTrigger=PropertyChanged}"/>

            

            <Rectangle StrokeThickness="1" Fill="#465168" Height="1" />

            <Label Content=" UpdateSourceTrigger=Default"/>

            <TextBox Text="{Binding Name, UpdateSourceTrigger=Default}"/>

 

            <Rectangle StrokeThickness="1" Fill="#465168" Height="1" />

            <Label Content=" Value"/>

            <Label Content="{Binding Name}"/>

        </StackPanel>

    </Grid>

</Window>

 

 

MainWindow.xaml.cs

using System.Windows;

 

namespace UpdateSourceTriggerTest

{

    /// <summary>

    /// MainWindow.xaml에 대한 상호 작용 논리

    /// </summary>

    public partial class MainWindow : Window

    {

        public MainWindow()

        {

            InitializeComponent();

 

            this.DataContext = new TestData() { Name = "TEST", Order = 1 };

        }

 

        public class TestData

        {

            public string Name { get; set; }

            public int Order { get; set; }

        }

    }

}

 

 


 

예시를 보면

PropertyChanged 인 경우는 실시간으로 변경사항이 반영되지만

Default 인 경우는 커서를 벗어난 경우 변경사항이 반영됩니다.

상황에 따라 맞는걸 쓰면 되겠습니다.

 

 

728x90
반응형
728x90
반응형

테스트박스가 비어있을 때 특정한 텍스트를 표시 하고 싶을때 사용합니다

("조회할 값을 입력해 주세요" 등..)

<Window x:Class="PlaceHolder.MainWindow"

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"

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

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

        mc:Ignorable="d"

        Title="MainWindow" Height="86.638" Width="227.155">

    <StackPanel>

        <Grid>

            <TextBox Name="searchTextBox" Margin="10"  Text="" Width="180" Height="32" HorizontalAlignment="Left" VerticalAlignment="Center" VerticalContentAlignment="Center"/>

            <TextBlock Text="Search Name.." IsHitTestVisible="False" VerticalAlignment="Center" Margin="15,10,10,10" HorizontalAlignment="Left">

                <TextBlock.Style>

                    <Style TargetType="TextBlock">

                        <Setter Property="Visibility" Value="Hidden"/>

                        <Setter Property="Foreground" Value="Gray"/>

                        <Style.Triggers>

                            <DataTrigger Binding="{Binding Text, ElementName=searchTextBox}" Value="">

                                <Setter Property="Visibility" Value="Visible"/>

                            </DataTrigger>

                        </Style.Triggers>

                    </Style>

                </TextBlock.Style>

            </TextBlock>

        </Grid>

    </StackPanel>

</Window>



728x90
반응형
728x90
반응형

datacontext 의 특정 Command 를 실행하는 메서드로 Parameter 를 인자로 전달 할수 있습니다.


using System.Reflection;

using System.Windows.Input;


namespace WpfApp

{

    class TestClass

    {


        /// <summary>

        /// DataContext 의 특정 Command 를 파라미터와 함께 실행합니다.

        /// </summary>

        /// <typeparam name="T">파라미터 타입입니다.</typeparam>

        /// <param name="dataContext">DataContext 입니다.</param>

        /// <param name="command">Command 명입니다.</param>

        /// <param name="parameter">파라미터입니다.</param>

        public static void Execute<T>(object dataContext, string command, T parameter)

        {

            if (dataContext == null)

            {

                return;

            }


            if (string.IsNullOrWhiteSpace(command) == true)

            {

                return;

            }


            // Command 명으로 찾습니다.

            PropertyInfo pi = dataContext.GetType().GetProperty(command);

            if (pi == null)

            {

                return;

            }


            // Command 로 변환합니다.

            ICommand ic = pi.GetValue(dataContext, null) as ICommand;

            if (ic == null)

            {

                return;

            }


            // Command 를 호출합니다.

            ic.Execute(parameter);

        }

    }

}




728x90
반응형
728x90
반응형

        /// <summary>
        /// 이미지를 Crop 한 결과를 반환합니다.
        /// </summary>
        /// <param name="imageSource">원본이미지입니다.</param>
        /// <param name="x">잘라낼 x 축 값입니다.</param>
        /// <param name="y">잘라낼 y 축 값입니다.</param>
        /// <param name="width">잘라낼 너비값입니다.</param>
        /// <param name="height">잘라낼 높이값입니다.</param>
        /// <returns>잘라낸 이미지입니다.</returns>
        public static ImageSource CropImage(ImageSource imageSource, double x, double y, double width, double height)
        {
            return new CroppedBitmap((BitmapSource)imageSource, new Int32Rect((int)x, (int)y, (int)width, (int)height));
        }


728x90
반응형
728x90
반응형

Command 에 인자로 두가지 항목을 던지고자 할때

이를 class 로 정의하여 CommandParameter 로 던질수 있다.

 

먼저 프로젝트에 Prism.Wpf Nuget Package 를 설치한다.

 

이제 Class 구조를 잡는다.

(string, object 로 구성)

[StringObject.cs]

namespace MultiValueConverterSample

{

    public class StringObject

    {

        /// <summary>

        /// 문자열 데이터입니다.

        /// </summary>

        public string StringData;

 

        /// <summary>

        /// 오브젝트 데이터입니다.

        /// </summary>

        public object ObjectData;

 

        /// <summary>

        /// 생성자입니다.

        /// </summary>

        /// <param name="stringData">문자열 데이터입니다.</param>

        /// <param name="objectData">오브젝트 데이터입니다.</param>

        public StringObject(string stringData, object objectData)

        {

            this.StringData = stringData;

            this.ObjectData = objectData;

        }

    }

}

 

 

IMultiValueConverter 를 정의한다.

(화면에서 처리된 두개의 인자를 가지고 위에서 만들 Class 구조로 변환해 리턴)

[StringObjectConverter.cs]

using System;

using System.Globalization;

using System.Windows.Data;

 

namespace MultiValueConverterSample

{

    public class StringObjectConverter : IMultiValueConverter

    {

        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)

        {

            return new StringObject(values[0].ToString(), values[1]);

        }

 

        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)

        {

            throw new NotImplementedException();

        }

    }

}

 

 

화면에 아래 처럼 구성한다.

(조회 버튼을 클릭하면 StringObjectCommand 를 실행해

입력한 값을 string 으로 버튼 객체를 object 로 하여 CommandParameter 로 사용한다.)

[MainWindow.xaml]

<Window x:Class="MultiValueConverterSample.MainWindow"

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"

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

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

        xmlns:local="clr-namespace:MultiValueConverterSample"

        mc:Ignorable="d"

        Title="MainWindow" Height="450" Width="800">

    <Window.Resources>

        <local:StringObjectConverter x:Key="StringObjectConverter" />

    </Window.Resources>

    <Grid>

        <StackPanel>

            <TextBox Name="contentTextBlock" Width="100" Height="30" Margin="10"/>

            <Button Name="searchButton" Content="조회" Margin="10" Height="30" Width="100" Command="{Binding StringObjectCommand}">

                <Button.CommandParameter>

                    <MultiBinding Converter="{StaticResource StringObjectConverter}">

                        <Binding ElementName="contentTextBlock" Path="Text" />

                        <Binding ElementName="searchButton" />

                    </MultiBinding>

                </Button.CommandParameter>

            </Button>

        </StackPanel>

    </Grid>

</Window>

 

 

코드비하인드 단에서는 아래 처럼 처리한다.

(반드시 this.DataContext = this; 을 해야 Command 가 처리된다.)

[MainWindow.xaml.cs]

using Prism.Commands;

 

using System.Windows;

using System.Windows.Input;

 

namespace MultiValueConverterSample

{

    /// <summary>

    /// MainWindow.xaml에 대한 상호 작용 논리

    /// </summary>

    public partial class MainWindow : Window

    {

        #region StringObjectCommand

 

        /// <summary>

        /// StringObjectCommand

        /// </summary>

        public ICommand StringObjectCommand

        {

            get

            {

                if (stringObjectCommand == null)

                {

                    stringObjectCommand = new DelegateCommand<StringObject>((stringObject) =>

                    {

                        string stringData = stringObject.StringData;

                        object objectData = stringObject.ObjectData;

                    });

                }

                return stringObjectCommand;

            }

        }

        private DelegateCommand<StringObject> stringObjectCommand;

 

        #endregion

 

        public MainWindow()

        {

            InitializeComponent();

 

            this.DataContext = this;

        }

    }

}

 

 

 

조회 버튼을 누르게 되면 Command 에서 아래 처럼 해당 항목이 넘어온것을 확인할 수 있다.

 

 

 

728x90
반응형
728x90
반응형

ContextMenu 의 Item 을 선택한 경우 ContextMenu 가 닫히는데

만약 체크 박스가 있는 경우 이를 유지하고 싶을 때가 있다.

이때 MenuItem 의 StaysOpenOnClick 을 true 로 주게 되면 ContextMenu 가 닫히지 않고

클릭 이벤트가 수행된다.


                <ContextMenu>

                    <MenuItem Header="첫번째" IsCheckable="True" StaysOpenOnClick="True"/>

                </ContextMenu>



728x90
반응형
728x90
반응형

아래 예시는 각기 다른 4가지 이미지를 4분면에 그리는 코드입니다.

 

4분면에 이미지를 하나씩 그리는 예시입니다.

처음 이미지의 크기에 따라 나머지 이미지 들도 크기가 지정되며

바둑판모양으로 이미지가 달라 붙습니다.

 

        private void MergeImage(string path1, string path2, string path3, string path4, string outputFilePath)

        {

            // 이미지를 로드합니다.

            BitmapFrame frame1 = BitmapDecoder.Create(new Uri(path1), BitmapCreateOptions.None, BitmapCacheOption.OnLoad).Frames.First();

            BitmapFrame frame2 = BitmapDecoder.Create(new Uri(path2), BitmapCreateOptions.None, BitmapCacheOption.OnLoad).Frames.First();

            BitmapFrame frame3 = BitmapDecoder.Create(new Uri(path3), BitmapCreateOptions.None, BitmapCacheOption.OnLoad).Frames.First();

            BitmapFrame frame4 = BitmapDecoder.Create(new Uri(path4), BitmapCreateOptions.None, BitmapCacheOption.OnLoad).Frames.First();

 

            // 첫번째이미지 기준으로 그려질 이미지의 크기를 정의합니다.

            int imageWidth = frame1.PixelWidth;

            int imageHeight = frame1.PixelHeight;

 

            // DrawingVisual 에 전체 4분면에서 각 분면 이미지를 그립니다.

            DrawingVisual drawingVisual = new DrawingVisual();

            using (DrawingContext drawingContext = drawingVisual.RenderOpen())

            {

                drawingContext.DrawImage(frame1, new Rect(0, 0, imageWidth, imageHeight));

                drawingContext.DrawImage(frame2, new Rect(imageWidth, 0, imageWidth, imageHeight));

                drawingContext.DrawImage(frame3, new Rect(0, imageHeight, imageWidth, imageHeight));

                drawingContext.DrawImage(frame4, new Rect(imageWidth, imageHeight, imageWidth, imageHeight));

            }

 

            // RenderTargetBitmap 을 사용해 DrawingVisual 을 BitmapSource 객체로 변환합니다.

            RenderTargetBitmap renderTargetBitmap = new RenderTargetBitmap(imageWidth * 2, imageHeight * 2, 96, 96, PixelFormats.Pbgra32);

            renderTargetBitmap.Render(drawingVisual);

 

            // BitmapSource 를 PngBitmapEncoder 를 사용해 frame 에 추가합니다.

            PngBitmapEncoder encoder = new PngBitmapEncoder();

            encoder.Frames.Add(BitmapFrame.Create(renderTargetBitmap));

 

            // 이미지를 저장합니다.

            using (Stream stream = File.Create(outputFilePath))

            {

                encoder.Save(stream);

            }

        }

 

* ico 파일 지정도 가능

 

결과

728x90
반응형

+ Recent posts