WPF Toolkit - February 2010 Release

다운로드 경로

http://wpf.codeplex.com/releases/view/40535

INotifyPropertyChanged ?

속성 값이 변경되었음을 클라이언트에 알립니다.
예를 들어 UI 단에서 값이 변경되면 바인딩된 클래스의 값도 변경됩니다.
또는 INotifyPropertyChanged 를 클래스를 구현한 데이터를
A UI 와 B UI 에서 동시에 바인딩했다면 A UI 에서 값을 변경했다면 INotifyPropertyChanged 가 발생해서 자동으로 B UI 에서의 상태값도 변경됩니다.

 

예제

아래는 바인딩할 개체 입니다.
using System.ComponentModel;  사용하며 INotifyPropertyChanged 를 구현해주면 끗~

INotifyPropertyChanged 구현한 Person 클래스

using System.ComponentModel; 
namespace SDKSample
{
  // This class implements INotifyPropertyChanged
  // to support one-way and two-way bindings
  // (such that the UI element updates when the source
  // has been changed dynamically)
  public class Person : INotifyPropertyChanged
  {
      private string name;
      // Declare the event
      public event PropertyChangedEventHandler PropertyChanged;

      public Person()
      {
      }

      public Person(string value)
      {
          this.name = value;
      }
      
      public string PersonName
      {
          get { return name; }
          set
          {
              name = value;
              // Call OnPropertyChanged whenever the property is updated
              OnPropertyChanged("PersonName");
          }
      }

      // Create the OnPropertyChanged method to raise the event
      protected void OnPropertyChanged(string name)
      {
          PropertyChangedEventHandler handler = PropertyChanged;
          if (handler != null)
          {
              handler(this, new PropertyChangedEventArgs(name));
          }
      }
  }
}

WPF

<!--<SnippetInstantiation>-->
<Window
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:src="clr-namespace:SDKSample"
  SizeToContent="WidthAndHeight"
  Title="Simple Data Binding Sample">

  <!--<SnippetBindingSource>-->
  <Window.Resources>
    <src:Person x:Key="myDataSource" PersonName="Joe"/>
    <!--</SnippetInstantiation>-->
    <Style TargetType="{x:Type Label}">
      <Setter Property="DockPanel.Dock" Value="Top"/>
      <Setter Property="FontSize" Value="12"/>
    </Style>
    <Style TargetType="{x:Type TextBox}">
      <Setter Property="Width" Value="100"/>
      <Setter Property="Height" Value="25"/>
      <Setter Property="DockPanel.Dock" Value="Top"/>
    </Style>
    <Style TargetType="{x:Type TextBlock}">
      <Setter Property="Width" Value="100"/>
      <Setter Property="Height" Value="25"/>
      <Setter Property="DockPanel.Dock" Value="Top"/>
      <Setter Property="Padding" Value="3"/>
    </Style>
    <!--<Snippet2>-->
  </Window.Resources>
  <!--</Snippet2>-->
  <Border Margin="5" BorderBrush="Aqua" BorderThickness="1" Padding="8" CornerRadius="3">
    <DockPanel Width="200" Height="100" Margin="35">
      <!-- <Snippet1> -->
      <Label>Enter a Name:</Label>
      <TextBox>
        <TextBox.Text>
          <Binding Source="{StaticResource myDataSource}" Path="PersonName"
                   UpdateSourceTrigger="PropertyChanged"/>
        </TextBox.Text>
      </TextBox>
      <!-- </Snippet1> -->
      
      <!--</SnippetBindingSource>-->
      <Label>The name you entered:</Label>
      <!--<SnippetBDO1>-->
      <TextBlock Text="{Binding Source={StaticResource myDataSource}, Path=PersonName}"/>
      <!--</SnippetBDO1>-->
    </DockPanel>
  </Border>
<!--<SnippetEndWindow>-->
</Window>
<!--</SnippetEndWindow>-->  

출처 :http://usamawahabkhan.blogspot.com/2010/02/silverlight-beta-4-drag-n-drop.html

image

Silverlight 4 Beta Drag and Drop Feature to Stream content on Client like openfiledialog
download code from here

image

Drag 라고 적힌 부분이 border 컨트롤입니다.  거기를 끌면

윈도우즈 창이 움직입니다.

border1 에 이벤트주기

image

코드는 열라간단함

        private void border1_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            this.DragMove();
            e.Handled = true;
        }

e.Handle =true;로 표시하는 이유

라우트된 이벤트의 이벤트 데이터에서 Handled 속성 값을 true로 설정하는 것을 "이벤트를 처리된 것으로 표시한다"라고 표현합니다. 기존 라우트된 이벤트를 사용하거나 새 라우트된 이벤트를 구현하는 응용 프로그램 제작자나 컨트롤 제작자가 라우트된 이벤트를 처리된 것으로 표시해야 하는 시점에 대한 절대적인 규칙은 없습니다. 대부분의 경우 라우트된 이벤트의 이벤트 데이터 포함되어 있는 "처리 완료"의 개념은 WPF API로 노출되는 다양한 라우트된 이벤트뿐만 아니라 사용자 지정된 라우트된 이벤트에 대한 고유한 응용 프로그램의 응답에 제한된 프로토콜로 사용해야 합니다. "처리 완료" 문제를 생각하는 또 다른 방법은 코드에서 의미 있고 상대적으로 완전한 방법으로 라우트된 이벤트에 응답한 경우 라우트된 이벤트를 처리된 것으로 표시해야 한다는 것입니다. 일반적으로 발생한 라우트된 이벤트의 단일 인스턴스에 대해 별도의 처리기를 구현해야 하는 의미 있는 응답은 하나만 있어야 합니다. 둘 이상의 응답이 필요한 경우에는 라우트된 이벤트 시스템을 전달용으로 사용하는 대신 단일 처리기 내에서 연결되는 응용 프로그램 논리를 통해 필요한 코드를 구현해야 합니다. "의미 있는 상태"라는 개념 역시 주관적이며 응용 프로그램이나 코드에 따라 달라집니다. "의미 있는 응답" 예로는 포커스 설정, 공용 상태 수정, 시각적 표현에 영향을 미치는 속성 설정, 다른 새 이벤트 생성 등이 있습니다. 의미 없는 응답의 예로는 시각적 영향이나 프로그래밍 표현이 없는 전용 상태 수정, 이벤트 로깅, 이벤트 인수를 검사한 응답하지 않도록 선택하는 것 등이 포함됩니다.[MSDN]

image

Window 에서 WindowsStyle을 None 로 주면 메뉴바가 없어집니다.

image

 

이걸로 완성

구현모습

image

드래그도 잘됨

image

 

PreviewEvent "미리 보기"(터널링) 및 버블링 이벤트와 이벤트 처리?

라우트된 미리 보기 이벤트는 요소 트리에서 터널링 경로를 따르는 이벤트입니다. 이름에서 알 수 있듯이 "미리 보기"는 라우트된 미리 보기(터널링) 이벤트가 해당되는 라우트된 버블링 이벤트보다 먼저 발생한다는 입력 이벤트의 일반적인 원칙을 나타냅니다. 또한 터널링 및 버블링 쌍이 있는 라우트된 입력 이벤트는 고유한 처리 논리를 가집니다. 라우트된 터널링/미리 보기 이벤트가 이벤트 수신기에 의해 처리된 것으로 표시되면 라우트된 버블링 이벤트의 수신기가 이벤트를 받기 전에 라우트된 버블링 이벤트가 처리된 것으로 표시됩니다. 라우트된 터널링 및 버블링 이벤트는 기술적으로 서로 다른 이벤트이지만 동일한 이벤트 데이터 인스턴스를 공유하여 이 동작을 활성화합니다.

라우트된 터널링 및 버블링 이벤트 간의 연결은 특정 WPF 클래스가 고유하게 선언된 라우트된 이벤트를 발생시키는 방식으로 내부적으로 구현되며 이는 쌍을 이루는 라우트된 입력 이벤트의 경우에도 해당됩니다. 하지만 이 클래스 수준 구현이 존재하지 않으면 라우트된 터널링 이벤트와 라우트된 버블링 이벤트 간에 이름 지정 체계를 공유하는 연결이 없습니다. 이와 같은 구현이 없으면 이 두 이벤트는 완전히 분리된 두 개의 라우트된 이벤트이며 차례로 발생하거나 이벤트 데이터를 공유하지 않습니다.

  (MSDN)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.Common;
using System.Diagnostics;
using System.Drawing;
using System.Data.SqlClient;
using System.Windows.Forms;

// This form demonstrates using a BindingSource to bind
// a list to a DataGridView control. The list does not
// raise change notifications, however the DemoCustomer type 
// in the list does.
public class Form1 : System.Windows.Forms.Form
{
	// This button causes the value of a list element to be changed.
	private Button changeItemBtn = new Button();

	// This is the DataGridView control that displays the contents 
	// of the list.
	private DataGridView customersDataGridView = new DataGridView();

	// This is the BindingSource used to bind the list to the 
	// DataGridView control.
	private BindingSource customersBindingSource = new BindingSource();

	public Form1()
	{
		// Set up the "Change Item" button.
		this.changeItemBtn.Text = "Change Item";
		this.changeItemBtn.Dock = DockStyle.Bottom;
		this.changeItemBtn.Click +=
			new EventHandler(changeItemBtn_Click);
		this.Controls.Add(this.changeItemBtn);

		// Set up the DataGridView.
		customersDataGridView.Dock = DockStyle.Top;
		this.Controls.Add(customersDataGridView);
		this.Size = new Size(800, 200);
		this.Load += new EventHandler(Form1_Load);
	}

	private void Form1_Load(System.Object sender, System.EventArgs e)
	{
		// Create and populate the list of DemoCustomer objects
		// which will supply data to the DataGridView.
		List<DemoCustomer> customerList = new List<DemoCustomer>();
		customerList.Add(DemoCustomer.CreateNewCustomer());
		customerList.Add(DemoCustomer.CreateNewCustomer());
		customerList.Add(DemoCustomer.CreateNewCustomer());

		// Bind the list to the BindingSource.
		this.customersBindingSource.DataSource = customerList;

		// Attach the BindingSource to the DataGridView.
		this.customersDataGridView.DataSource =
			this.customersBindingSource;
	}

	// This event handler changes the value of the CompanyName
	// property for the first item in the list.
	void changeItemBtn_Click(object sender, EventArgs e)
	{
		// Get a reference to the list from the BindingSource.
		List<DemoCustomer> customerList =
			this.customersBindingSource.DataSource as List<DemoCustomer>;

		// Change the value of the CompanyName property for the 
		// first item in the list.
		customerList[0].CompanyName = "Tailspin Toys";

	}

	

	[STAThread]
	static void Main()
	{
		Application.EnableVisualStyles();
		Application.Run(new Form1());
	}
}

// This class implements a simple customer type 
// that implements the IPropertyChange interface.
public class DemoCustomer : INotifyPropertyChanged
{
	// These fields hold the values for the public properties.
	private Guid idValue = Guid.NewGuid();
	private string customerName = String.Empty;
	private string companyNameValue = String.Empty;
	private string phoneNumberValue = String.Empty;

	public event PropertyChangedEventHandler PropertyChanged;
	
	private void NotifyPropertyChanged(String info)
	{
		if (PropertyChanged != null)
		{
			PropertyChanged(this, new PropertyChangedEventArgs(info));
		}
	}

	// The constructor is private to enforce the factory pattern.
	private DemoCustomer()
	{
		customerName = "no data";
		companyNameValue = "no data";
		phoneNumberValue = "no data";
	}

	// This is the public factory method.
	public static DemoCustomer CreateNewCustomer()
	{
		return new DemoCustomer();
	}

	// This property represents an ID, suitable
	// for use as a primary key in a database.
	public Guid ID
	{
		get
		{
			return this.idValue;
		}
	}

	public string CompanyName
	{
		get
		{
			return this.companyNameValue;
		}

		set
		{
            if (value != this.companyNameValue)
            {
                this.companyNameValue = value;
                NotifyPropertyChanged("CompanyName");
            }
		}
	}

	public string PhoneNumber
	{
		get
		{
			return this.phoneNumberValue;
		}

		set
		{
            if (value != this.phoneNumberValue)
            {
                this.phoneNumberValue = value;
                NotifyPropertyChanged("PhoneNumber");
            }
		}
	}
}

Get Started with Silverlight for Windows Phone

 

image

동영상 URL

http://www.silverlight.net/learn/videos/all/get-started-with-silverlight-for-windows-phone/

HTML  Convert

In this case both properties are of type string, so the converter trick is not really needed. However, here we use the converter to strip out HTML markup and clean up the text to display. Again, the converter class needs to be declared as a resource, as shown above.

public class HtmlSanitizer : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
   {
// Remove HTML tags and empty newlines and spaces
string returnString = Regex.Replace(value as string, "<.*?>", "");
      returnString = Regex.Replace(returnString, @"\n+\s+", "\n\n");

// Decode HTML entities
returnString = HttpUtility.HtmlDecode(returnString);

return returnString;
   }

   public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
   {
throw new NotImplementedException();
   }
}

ObservableCollection<(Of <(T>)>) Class

    [SerializableAttribute]
    public class ObservableCollection<T> : Collection<T>,
    INotifyCollectionChanged, INotifyPropertyChanged

    In many cases the data that you work with is a collection of objects. For example, a common scenario in data binding is to use an ItemsControl such as a ListBox, ListView, or TreeView to display a collection of records.

    You can enumerate over any collection that implements the IEnumerable interface. However, to set up dynamic bindings so that insertions or deletions in the collection update the UI automatically, the collection must implement the INotifyCollectionChanged interface. This interface exposes the CollectionChanged event, an event that should be raised whenever the underlying collection changes.

    WPF provides the ObservableCollection<(Of <(T>)>) class, which is a built-in implementation of a data collection that implements the INotifyCollectionChanged interface.

    Before implementing your own collection, consider using ObservableCollection<(Of <(T>)>) or one of the existing collection classes, such as List<(Of <(T>)>), Collection<(Of <(T>)>), and BindingList<(Of <(T>)>), among many others. If you have an advanced scenario and want to implement your own collection, consider using IList, which provides a non-generic collection of objects that can be individually accessed by index. Implementing IList provides the best performance with the data binding engine.

    Note:

    To fully support transferring data values from binding source objects to binding targets, each object in your collection that supports bindable properties must implement an appropriate property changed notification mechanism such as the INotifyPropertyChanged interface.

    For more information, see "Binding to Collections" in Data Binding Overview.

    Notes on XAML Usage

    ObservableCollection<(Of <(T>)>) can be used as a XAML object element in Windows Presentation Foundation (WPF), in versions 3.0 and 3.5. However, the usage has substantial limitations.

    • ObservableCollection<(Of <(T>)>) must be the root element, because the x:TypeArguments attribute that must be used to specify the constrained type of the generic ObservableCollection<(Of <(T>)>) is only supported on the object element for the root element.
    • You must declare an x:Class attribute (which entails that the build action for this XAML file must be Page or some other build action that compiles the XAML).
    • ObservableCollection<(Of <(T>)>) is in a namespace and assembly that are not initially mapped to the default XML namespace. You must map a prefix for the namespace and assembly, and then use that prefix on the object element tag for ObservableCollection<(Of <(T>)>).

    A more straightforward way to use ObservableCollection<(Of <(T>)>) capabilities from XAML in an application is to declare your own non-generic custom collection class that derives from ObservableCollection<(Of <(T>)>), and constrains it to a specific type. Then map the assembly that contains this class, and reference it as an object element in your XAML.

    This example

    This example shows how to create and bind to a collection that derives from the ObservableCollection<(Of <(T>)>) class, which is a collection class that provides notifications when items get added or removed.

    The following example shows the implementation of a NameList collection:

    public class NameList : ObservableCollection<PersonName>

    {

    public NameList() : base()

    {

    Add(new PersonName("Willa", "Cather"));

    Add(new PersonName("Isak", "Dinesen"));

    Add(new PersonName("Victor", "Hugo"));

    Add(new PersonName("Jules", "Verne"));

    }

    }

    public class PersonName

    {

    private string firstName;

    private string lastName;

    public PersonName(string first, string last)

    {

    this.firstName = first;

    this.lastName = last;

    }

    public string FirstName

    {

    get { return firstName; }

    set { firstName = value; }

    }

    public string LastName

    {

    get { return lastName; }

    set { lastName = value; }

    }

    }

INotifyPropertyChanged

using System;
using System.ComponentModel;
namespace DGRowDetails
{
public class Task : System.ComponentModel.INotifyPropertyChanged
{
// The Task class implements INotifyPropertyChanged so that
// the datagrid row will be notified of changes to the data
// that are made in the row details section.
// Private task data.
private string m_Name;
private DateTime m_DueDate;
private bool m_Complete;
private string m_Notes;
// Define the public properties.
public string Name
{
get { return this.m_Name; }
set
{
if (value != this.m_Name)
{
this.m_Name = value;
NotifyPropertyChanged("Name");
}
}
}
public DateTime DueDate
{
get { return this.m_DueDate; }
set
{
if (value != this.m_DueDate)
{
this.m_DueDate = value;
NotifyPropertyChanged("DueDate");
}
}
}
public bool Complete
{
get { return this.m_Complete; }
set
{
if (value != this.m_Complete)
{
this.m_Complete = value;
NotifyPropertyChanged("Complete");
}
}
}
public string Notes
{
get { return this.m_Notes; }
set
{
if (value != this.m_Notes)
{
this.m_Notes = value;
NotifyPropertyChanged("Notes");
}
}
}
// Implement INotifyPropertyChanged interface.
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}

Using Value Converters

This column is pretty much exactly what we want, but there is a finishing touch missing.  If you look at the text, it has an annoying 12:00:00 AM after each date.  Since we only care about the date itself and not the time, let's reformat this string to the short date format that matches what is shown in the DatePicker.

Add a new class to your Silverlight project and name it "DateTimeConverter".  Then add:

C#

using System.Windows.Data;
using System.Globalization;

public class DateTimeConverter: IValueConverter
{
    public object Convert(object value, 
                       Type targetType, 
                       object parameter, 
                       CultureInfo culture)
    {
        DateTime date = (DateTime)value;
        return date.ToShortDateString();
    }

    public object ConvertBack(object value, 
                              Type targetType, 
                              object parameter, 
                              CultureInfo culture)
    {
        string strValue = value.ToString();
        DateTime resultDateTime;
        if (DateTime.TryParse(strValue, out resultDateTime))
        {
            return resultDateTime;
        }
        return value;
    }
}
 
 
 

If you look at the code, a converter is a class that implements IValueConverter and as part of that provides two methods:

Convert and ConvertBack.  These two methods are where you can perform your custom logic, in this case parsing a DateTime

to and from a short date string format.

Now that you have your reusable converter class you can use it in data binding.

Back in your Page.xaml add a local xmlns.  To do this add the following in the UserControl tag next to the other xmlns

declarations:

xmlns:local="clr-namespace:_____________"

Where the _________ is the name of your Application.  IntelliSense should provide the correct syntax as an option in

the dropdown.  Next add the converter to your UserControl as a static resource.

<UserControl.Resources>
    <local:DateTimeConverter x:Key="DateConverter" />
</< span>UserControl.Resources>

Finally use the converter in the TextBox's binding in the DataGridTemplateColumn. 

<TextBlock 
    Text="{Binding Birthday, Converter={StaticResource DateConverter}}" 
    FontFamily="Trebuchet MS" FontSize="11" 
    Margin="5,4,5,4"/>
 
 

+ Recent posts