블로그 이미지
Sunny's

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 31

Notice

2010. 3. 15. 13:23 WPF, Silverlight

WPF를 처음 사용하시는 분들~ ^^
쉽지 않으셨으리라 생각됩니다. 관련된 테마별로 소스와 문서가 잘 정리되어 있는 링크를 공유합니다.
Visual Studio 2010과 함께 WPF도 4.0으로 업그레이드 될 예정입니다.

http://code.msdn.microsoft.com/wpfsamples 
posted by Sunny's
2009. 4. 16. 11:22 WPF, Silverlight

This is the way how I implemented paging among a wrap panel in WPF. For this example I used simple buttons inside the wrap panel. My example dynamically takes the height of the control inside the wrap panel to determine the quantity of controls that the wrap panel must show.

In this example the columns always stay static, 1 column Min and 2 columns Max. You can also create a column function to show dynamically the quantity of columns you want.

The result is this:

This is the window when is loaded:

App sin resize

This is the window when is resized:

App when resized


XAML:

<Window x:Class=”PagingWrapPanel.PagingWithDuff”

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

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

Title=”PagingWithDuff” Height=”250″ Loaded=”Window_Loaded”

MaxHeight=”500″ MinHeight=”120″ MaxWidth=”500″ MinWidth=”500″>

<Grid>

<Grid.RowDefinitions>

<RowDefinition />

<RowDefinition Height=”24″ />

<RowDefinition Height=”26″ />

</Grid.RowDefinitions>

<ItemsControl Grid.Row=”0″ Name=”RowsContainer” Background=”Transparent” ItemsSource=”{Binding}” SizeChanged=”RowsContainer_SizeChanged” >

<ItemsControl.ItemTemplate>

<DataTemplate>

<Label />

</DataTemplate>

</ItemsControl.ItemTemplate>

<ItemsControl.ItemsPanel>

<ItemsPanelTemplate>

<WrapPanel Orientation=”Vertical” IsItemsHost=”True”

Width=”Auto” HorizontalAlignment=”Center” />

</ItemsPanelTemplate>

</ItemsControl.ItemsPanel>

</ItemsControl>

<Grid Grid.Row=”1″ HorizontalAlignment=”Center” >

<Label Name=”label1″ VerticalAlignment=”Top” Height=”Auto” >Page 1 out of 1</Label>

</Grid>

<Grid Grid.Row=”2″ >

<Grid.ColumnDefinitions>

<ColumnDefinition Width=”*”/>

<ColumnDefinition Width=”*” />

</Grid.ColumnDefinitions>

<Button Grid.Column=”0″ x:Name=”btnBack” Click=”btnBack_Click” MaxHeight=”25″ >Back</Button>

<Button Grid.Column=”1″ x:Name=”btnNext” Click=”btnNext_Click” MaxHeight=”25″ >Next</Button>

</Grid>

</Grid>

</Window>

By the way, you must change in the App.xaml the StartupUri string to - StartupUri=”PagingWrapPanel.xaml” -

using System;
using
System.Collections.Generic;
using
System.Linq;
using
System.Text;
using
System.Windows;
using
System.Windows.Controls;
using
System.Windows.Data;
using
System.Windows.Documents;
using
System.Windows.Input;
using
System.Windows.Media;
using
System.Windows.Media.Imaging;
using
System.Windows.Navigation;
using
System.Windows.Shapes;
using
System.Collections.ObjectModel;

namespace PagingWrapPanel

{

///

/// Interaction logic for Window1.xaml

///

public partial class PagingWithDuff : Window

{

ObservableCollection<Label> collection;

WrapPanel currentPanel;

int rowsInPanel, pagingPressed;

double height;

//RowsContainer SizeChanged event is raised before the Loaded event for this class

//We need to raise Loaded event first, using this variable

bool isLoaded;

public PagingWithDuff()

{

InitializeComponent();

collection = new ObservableCollection<Label>();

isLoaded = false;

//Generate 100 Labels to Page

for (int generator = 1; generator <= 100; generator++)

{

Label newLbl = new Label();

newLbl.Name = “Label” + generator;

newLbl.Content = “Label “ + generator;

newLbl.Width = 160;

newLbl.Background = Brushes.Black;

newLbl.Foreground = Brushes.White;

newLbl.HorizontalContentAlignment = HorizontalAlignment.Center;

collection.Add(newLbl);

}

btnBack.IsEnabled = false;

btnNext.IsEnabled = false;

pagingPressed = 1;

RowsContainer.DataContext = collection;

}

//Calculate how many rows will be showed in the container

public int rowsToShow()

{

currentPanel = VisualTreeHelper.GetChild(VisualTreeHelper.GetChild(VisualTreeHelper.GetChild(RowsContainer, 0), 0), 0) as WrapPanel;

int rows = 0;

height = this.currentPanel.ActualHeight;

double RowControlHeight = 0.0;

//Get the first Visible Label in the Panel and get its Height

for (int iterator = 0; iterator <= collection.Count - 1; iterator++)

{

Visibility isVisible = (Visibility)(currentPanel.Children[iterator] as Label).Visibility;

//If is visible get height and break iteration

if (isVisible == Visibility.Visible)

{

RowControlHeight = (double)(currentPanel.Children[iterator] as Label).ActualHeight;

break;

}

}

rows = (int)Math.Floor((decimal)height / (decimal)RowControlHeight);

return rows;

}

//Shows the controls inside the wrap panel

public void setRowsControlsToShow()

{

bool endOfList = false;

bool startOfList = false;

bool medOfList = false;

bool overflow = false;

int collectionCount = 0;

collectionCount = collection.Count;

//Once the datacontext is displayed, we need to show up only the labels in this case we need

if (RowsContainer.Items.Count > 0)

{

int start = PagingWithDuff.startFromIndex(rowsToShow(), pagingPressed);

int end = PagingWithDuff.endInIndex(start, rowsToShow() * 2);

if (start > collectionCount - 1)

//If this happens, means that the panel have no content to show

{

end = collectionCount - 1;

start = (collectionCount - 1) - rowsToShow();

overflow = true;

}

if (start == 0) startOfList = true;

if (end > collectionCount)

{

end = collectionCount - 1;

endOfList = true;

}

else

{

if (!startOfList && !endOfList) { medOfList = true; }

}

for (int iter = 0; iter <= collectionCount - 1; iter++)

{

Label currentRow = currentPanel.Children[iter] as Label;

if ((iter < start) || (iter > end))

{

currentRow.Visibility = Visibility.Collapsed;

}

else

{

currentRow.Visibility = Visibility.Visible;

}

}

if (endOfList)

{

btnNext.IsEnabled = false;

if (pagingPressed > 1) btnBack.IsEnabled = true;

}

else

btnNext.IsEnabled = true;

if (medOfList)

{

if (end <= collectionCount - 1)

{

btnBack.IsEnabled = true;

}

}

if (startOfList)

{

btnBack.IsEnabled = false;

if ((rowsInPanel * 2) <= collectionCount)

btnNext.IsEnabled = true;

}

if (overflow)

{

btnNext.IsEnabled = false;

pagingPressed -= 1;

}

}

else

{

btnNext.IsEnabled = false;

btnBack.IsEnabled = false;

}

}

public void setPagingInfo()

{

int totalQty = collection.Count;

rowsInPanel = rowsToShow();

int totalPages = (int)Math.Floor((double)totalQty / rowsInPanel);

if (totalPages == 0)

{

totalPages = 1;

btnNext.IsEnabled = false;

btnBack.IsEnabled = false;

}

if (pagingPressed > totalPages)

this.label1.Content = “Page “ + totalPages + ” out of “ + totalPages;

else

this.label1.Content = “Page “ + pagingPressed + ” out of “ + totalPages;

}

private static int startFromIndex(int qtyToShow, int page)

{

if (page == 1) return 0;

return ((page - 1) * qtyToShow);

}

private static int endInIndex(int start, int qtyToShow)

{

return (start + qtyToShow) - 1;

}

private void Window_Loaded(object sender, RoutedEventArgs e)

{

setRowsControlsToShow();

setPagingInfo();

isLoaded = true;

}

private void RowsContainer_SizeChanged(object sender, SizeChangedEventArgs e)

{

if (isLoaded)

{

setRowsControlsToShow();

setPagingInfo();

}

}

private void btnNext_Click(object sender, RoutedEventArgs e)

{

pagingPressed++;

setRowsControlsToShow();

setPagingInfo();

}

private void btnBack_Click(object sender, RoutedEventArgs e)

{

pagingPressed -= 1;

setRowsControlsToShow();

setPagingInfo();

}

}

}

posted by Sunny's
2009. 3. 31. 15:20 WPF, Silverlight
프로그램이 중복 실행되는 것을 막는 가장 일반적인 방법은 Mutex를 사용하여 프로세스를 확인하는 방법입니다.
C#에서 사용되는 방법은 msdn에도 Mutex의 예제로 아래와 같이 나와 있습니다.
msdn에 나온 Mutex의 기본 사용법을 보시고 싶으신 분은 아래 소스를 펼쳐 보시면 됩니다.

하지만 WPF에서 위에 방법을 App.xaml.cs 에 적용시켜도 원하는 데로 동작하지 않습니다.
그래서 오늘은 WPF에서 사용할 수 있는 방법을 올려드리겠습니다.
아래 예제는 뮤텍스를 사용한 중복 방지 소스를 구글링해서 힘들게 찾은 소스입니다.
제가 잘 동작하는 것은 확인 하였습니다. 이 밖에 다른 예제 소스도 보여드리겠습니다만 아래 예제를 쓰시는 것이 가장 좋습니다.

01.using System;
02.using System.Threading;
03.using System.Windows; 
04.namespace WpfKorea
05.{
06.    /// <summary>
07.    /// Interaction logic for App.xaml
08.    /// </summary>
09.    public partial class App : Application
10.    {
11.        Mutex mutex = null;
12.        protected override void OnStartup(StartupEventArgs e)
13.        {            
14.            string mutexName = "wpfkorea.com";
15.            try
16.            {                
17.                mutex = new Mutex(false, mutexName);
18.            }
19.            catch (Exception ex)
20.            {
21.                MessageBox.Show(    ex.Message + "\n\n"  +   ex.StackTrace + "\n\n"  +   "Application Exiting…",   "Exception thrown");
22.                Application.Current.Shutdown();
23.            }
24.            if (mutex.WaitOne(0, false))
25.            {
26.                base.OnStartup(e);
27.            }
28.            else
29.            {
30.                MessageBox.Show("Application already startet.", "Error", MessageBoxButton.OK, MessageBoxImage.Information);
31.                Application.Current.Shutdown();
32.            }
33.        }
34.    }
35.}


위에 예제는 OnStartUp이벤트와 Mutex의 WaitOne을 이용하여 중복방지를 구현하였습니다.



그럼 이번에는 약간 다른 방법으로 구현해 보겠습니다.
이 방법은 WPF 초기화를 C# 코드로 직접 구현하는 방식입니다.

 

01.private static bool isNew;
02.[System.STAThreadAttribute()]
03.public static void Main()
04.{
05.    using (Mutex m = new Mutex(true, "ThisIsTheStringMutexValueThatMustBeUnique", out isNew))
06.    {
07.        if (isNew)
08.        {
09.            MyWPFApplication.App app = new MyWPFApplication.App();
10.            app.InitializeComponent();
11.            app.Run();
12.        }
13.        else
14.        {
15.            MessageBox.Show("MyWPFApplication is already running!", "MyWPFApplication", MessageBoxButton.OK, MessageBoxImage.Information, MessageBoxResult.OK);
16.        }
17.    }
18.}


이 방법을 사용하면 App.xaml의 Build Action 속성을 ApplicationDefinition 에서 Page로 변경해 주어야 합니다.
WPF가 구성해주는 진입점을 직접 작성하셔야 하므로 여러가지로 귀찮은 일이 생길 수 있을 거 같습니다.

마지막으로 소개해 드릴 방법은 프로세서의 네임 중복을 체크하는 방법입니다. 
이 방법은 잘 동작하지만 실행파일의 이름을 바꾸기만 해도 쉽게 중복 실행이 가능해 집니다.

01.public partial class App : Application
02.{
03.    public App() : base()
04.    {
05.        System.Diagnostics.Process[] process = System.Diagnostics.Process.GetProcessesByName(System.Diagnostics.Process.GetCurrentProcess().ProcessName);
06.        if (process.Length > 1)
07.        {
08.            MessageBox.Show("MyApplication is already running ...", "MyApplication Launch", MessageBoxButton.OK, MessageBoxImage.Information);
09.                this.Shutdown();
10.       }
11.    }
12.}

이런 방법들을 사용하시면 WPF에서 중복방지를 구현하실수 있습니다.
길게 읽지 않으시고 첫번째 소개해 드린 방법을 사용하시면 됩니다.
나머지는 참고만 하셔도 될 것 같습니다.

출처 : http://wpfkorea.com/?document_srl=3047#0

posted by Sunny's
prev 1 next