<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Window Presentation Foundation (WPF) &#8211; Ling&#039;s Note</title>
	<atom:link href="https://www.chunho-ling.com/category/computing/programming/window-presentation-foundation-wpf/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.chunho-ling.com</link>
	<description>Everything related IT, and me.</description>
	<lastBuildDate>Tue, 19 Jun 2018 05:52:43 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>
<site xmlns="com-wordpress:feed-additions:1">104401516</site>	<item>
		<title>[WPF] 在ViewModel 中實現Command Binding</title>
		<link>https://www.chunho-ling.com/wpf-%e5%9c%a8viewmodel-%e4%b8%ad%e5%af%a6%e7%8f%becommand-binding/</link>
					<comments>https://www.chunho-ling.com/wpf-%e5%9c%a8viewmodel-%e4%b8%ad%e5%af%a6%e7%8f%becommand-binding/#respond</comments>
		
		<dc:creator><![CDATA[C.H. Ling]]></dc:creator>
		<pubDate>Tue, 19 Jun 2018 05:49:50 +0000</pubDate>
				<category><![CDATA[C#]]></category>
		<category><![CDATA[Computing]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Window Presentation Foundation (WPF)]]></category>
		<guid isPermaLink="false">http://www.chunho-ling.com/?p=995</guid>

					<description><![CDATA[之前提及到在WPF 中利用Mode-View-ViewModel (MVVM) 中作EventHandling, 而一般的command binding 則須要自建class 去處理.DelegateCommand.cs public class DelegateCommand : ICommand { private readonly Predicate&#60;object&#62; _canExecute; private readonly Action&#60;object&#62; _execute; public event EventHandler CanExecuteChanged; public DelegateCommand(Action&#60;object&#62; execute) : this(execute, null) { } public <a class="mh-excerpt-more" href="https://www.chunho-ling.com/wpf-%e5%9c%a8viewmodel-%e4%b8%ad%e5%af%a6%e7%8f%becommand-binding/" title="[WPF] 在ViewModel 中實現Command Binding">[...]</a>]]></description>
										<content:encoded><![CDATA[<p><a href="https://www.chunho-ling.com/2017/09/29/wpf-%e9%80%b2%e8%a1%8cevent-binding/" target="_blank" rel="noopener">之前</a>提及到在WPF 中利用Mode-View-ViewModel (MVVM) 中作EventHandling, 而一般的command binding 則須要自建class 去處理.<span id="more-995"></span>DelegateCommand.cs</p>
<pre class="lang:c# decode:true" title="DelegateCommand.cs">public class DelegateCommand : ICommand
    {
        private readonly Predicate&lt;object&gt; _canExecute;
        private readonly Action&lt;object&gt; _execute;

        public event EventHandler CanExecuteChanged;

        public DelegateCommand(Action&lt;object&gt; execute)
                       : this(execute, null)
        {
        }

        public DelegateCommand(Action&lt;object&gt; execute,
                       Predicate&lt;object&gt; canExecute)
        {
            _execute = execute;
            _canExecute = canExecute;
        }

        public bool CanExecute(object parameter)
        {
            if (_canExecute == null)
            {
                return true;
            }

            return _canExecute(parameter);
        }

        public void Execute(object parameter)
        {
            _execute(parameter);
        }

        public void RaiseCanExecuteChanged()
        {
            if (CanExecuteChanged != null)
            {
                CanExecuteChanged(this, EventArgs.Empty);
            }
        }
    }</pre>
<p>利用 DelegateCommand Implement ICommand, 並於constructor 中加入Execute() 及CanExecute().</p>
<p>而叫用時, 在ViewModel 中則使用方法如下:&nbsp;</p>
<pre class="lang:default decode:true" title="MainWindowViewModel">public DelegateCommand SaveCommand;
        protected void SaveCommandExecute(object parameter)
        {
            // Command action.
        }
        protected bool SaveCommandCanExecute(object parameter)
        {
            // Command can execute or not.
            return true;
        }
        

        public MainWindowViewModel() : base()
        {
            // Define command and set property change handling.
            SaveCommand = new DelegateCommand(SaveCommandExecute, SaveCommandCanExecute);
            this.PropertyChanged += MainWindowViewModel_PropertyChanged;
        }

        private void MainWindowViewModel_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            // Fire event to execute CanExecute().
            SaveCommand.RaiseCanExecuteChanged();
        }</pre>
<p>&nbsp;</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.chunho-ling.com/wpf-%e5%9c%a8viewmodel-%e4%b8%ad%e5%af%a6%e7%8f%becommand-binding/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">995</post-id>	</item>
		<item>
		<title>[MVVM] 建立 Warning Control</title>
		<link>https://www.chunho-ling.com/mvvm-%e5%bb%ba%e7%ab%8b-warning-control/</link>
					<comments>https://www.chunho-ling.com/mvvm-%e5%bb%ba%e7%ab%8b-warning-control/#respond</comments>
		
		<dc:creator><![CDATA[C.H. Ling]]></dc:creator>
		<pubDate>Mon, 30 Oct 2017 09:53:59 +0000</pubDate>
				<category><![CDATA[Application Framework 程式框架]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[Computing]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Window Presentation Foundation (WPF)]]></category>
		<guid isPermaLink="false">http://www.chunho-ling.com/?p=790</guid>

					<description><![CDATA[WPF 的驗證可以透過ValidationRules 實現, 然而在實際情況中, 驗證除了Pass / Failure 外, 還可能會有severity level, warning 等. 可惜WPF 本身不支援. 若要加入的話, 最直接的方法只得從ViewModel 著手. 在示範中, 利用DataTrigger 來決定ViewModel 是否valid 及warning. 因為沒有利用WPF 內建的INotifyError 關係, 故直接不用直內置的Validation object. MainWindow.xaml &#60;Window x:Class="PoC.WpfWarning.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:PoC.WpfWarning" <a class="mh-excerpt-more" href="https://www.chunho-ling.com/mvvm-%e5%bb%ba%e7%ab%8b-warning-control/" title="[MVVM] 建立 Warning Control">[...]</a>]]></description>
										<content:encoded><![CDATA[<p>WPF 的驗證可以透過ValidationRules 實現, 然而在實際情況中, 驗證除了Pass / Failure 外, 還可能會有severity level, warning 等. 可惜WPF 本身不支援. 若要加入的話, 最直接的方法只得從ViewModel 著手.</p>
<p><span id="more-790"></span>在示範中, 利用DataTrigger 來決定ViewModel 是否valid 及warning. 因為沒有利用WPF 內建的INotifyError 關係, 故直接不用直內置的Validation object.</p>
<p>MainWindow.xaml</p>
<pre class="lang:default decode:true">&lt;Window x:Class="PoC.WpfWarning.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:PoC.WpfWarning"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525"&gt;
    &lt;Window.DataContext&gt;
        &lt;local:User /&gt;
    &lt;/Window.DataContext&gt;
    &lt;StackPanel&gt;
        &lt;TextBlock Text="User Name" /&gt;
        &lt;TextBox Text="{Binding Name, Mode=TwoWay}" Validation.ErrorTemplate="{x:Null}"&gt;
            &lt;TextBox.Style&gt;
                &lt;Style TargetType="TextBox"&gt;
                    &lt;Style.Triggers&gt;
                        &lt;DataTrigger Binding="{Binding HasWarnings}" Value="True"&gt;
                            &lt;Setter Property="Background" Value="Yellow" /&gt;
                        &lt;/DataTrigger&gt;
                        &lt;DataTrigger Binding="{Binding Errors}" Value="True"&gt;
                            &lt;Setter Property="Background" Value="Pink" /&gt;
                        &lt;/DataTrigger&gt;
                    &lt;/Style.Triggers&gt;
                &lt;/Style&gt;
            &lt;/TextBox.Style&gt;
        &lt;/TextBox&gt;
        &lt;TextBox /&gt;
    &lt;/StackPanel&gt;
&lt;/Window&gt;</pre>
<p>User.cs</p>
<pre class="lang:default decode:true ">public class User : ObservableObject
    {
        private string _name;

        public string Name
        {
            get { return _name; }
            set {
                if (_name != value)
                {
                    SetField(ref _name, value);
                    ValidateProperty(new NameValidor());
                }
            }
        }
    }</pre>
<p>NameValidator.cs</p>
<pre class="lang:default decode:true "> public class NameValidor : ValidationRule
    {
        public override ValidationResult Validate(object value, CultureInfo cultureInfo)
        {
            ValidationResult result = new WarnedValidationResult(true, false, null);
            User source = value as User;
            if (source != null)
            {
                if (string.IsNullOrEmpty(source.Name))
                    result = new ValidationResult(false, "Name could not be empty.");
                else if (source.Name == "aaa")
                    result = new WarnedValidationResult(true, true, "Message cannot be " + source.Name);
            }            
            return result;
        }
    }</pre>
<p>IDataWarningInfo.cs</p>
<pre class="lang:default decode:true ">public interface IDataWarningInfo
    {
        event EventHandler&lt;DataErrorsChangedEventArgs&gt; WarningsChanged;

        System.Collections.IEnumerable GetWarnings(string propertyName);

        bool HasWarnings { get; }
    }</pre>
<p>ObservableObject.cs</p>
<pre class="lang:default decode:true "> public class ObservableObject : INotifyPropertyChanged, INotifyDataErrorInfo, IDataWarningInfo
    {
        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
        }
        protected bool SetField&lt;T&gt;(ref T field, T value, [CallerMemberName] string propertyName = null)
        {
            field = value;
            OnPropertyChanged(propertyName);
            return true;
        }

        #region Implementation of Interfaces.
        protected Dictionary&lt;string, ICollection&lt;string&gt;&gt; _validationErrors = new Dictionary&lt;string, ICollection&lt;string&gt;&gt;();
        protected Dictionary&lt;string, ICollection&lt;string&gt;&gt; _validationWarnings = new Dictionary&lt;string, ICollection&lt;string&gt;&gt;();

        public bool HasErrors
        {
            get { return _errors; }
            set { SetField(ref _errors, value); }
        }

        private bool _errors;

        public bool Errors
        {
            get { return _errors; }
            set { SetField(ref _errors, value); }
        }
        private bool _hasWarnings;
        public bool HasWarnings
        {
            get { return _hasWarnings; }
            set { SetField(ref _hasWarnings, value); }
        }

        public event EventHandler&lt;DataErrorsChangedEventArgs&gt; ErrorsChanged;
        public event EventHandler&lt;DataErrorsChangedEventArgs&gt; WarningsChanged;

        public virtual void OnErrorsChanged(string propertyName)
        {
            if (ErrorsChanged != null)
                ErrorsChanged(this, new DataErrorsChangedEventArgs(propertyName));
        }
        public virtual void OnWarningsChanged(string propertyName)
        {
            if (WarningsChanged != null)
                WarningsChanged(this, new DataErrorsChangedEventArgs(propertyName));
        }
        protected void UpdateValidationErrors(string propertyName, ICollection&lt;string&gt; errorMessage)
        {
            if (errorMessage.Count &gt; 0)
            {
                /* Update the collection in the dictionary returned by the GetErrors method */
                _validationErrors[propertyName] = errorMessage;
                Errors = true;
            }
            else if (_validationErrors.ContainsKey(propertyName))
            {
                /* Remove all errors for this property */
                _validationErrors.Remove(propertyName);
                Errors = false;
            }
            /* Raise event to tell WPF to execute the GetErrors method */
            OnErrorsChanged(propertyName);
            OnPropertyChanged(propertyName);
        }

        public IEnumerable GetWarnings(string propertyName)
        {
            if (string.IsNullOrEmpty(propertyName) || !_validationWarnings.ContainsKey(propertyName))
                return null;
            return _validationWarnings[propertyName];
        }
        protected void UpdateValidationWarnings(string propertyName, ICollection&lt;string&gt; warningMessage)
        {
            if (warningMessage.Count &gt; 0)
            {
                /* Update the collection in the dictionary returned by the GetErrors method */
                _validationWarnings[propertyName] = warningMessage;
                HasWarnings = true;
            }
            else if (_validationWarnings.ContainsKey(propertyName))
            {
                /* Remove all errors for this property */
                _validationWarnings.Remove(propertyName);
                HasWarnings = false;
            }
            /* Raise event to tell WPF to execute the GetErrors method */
            OnWarningsChanged(propertyName);
            OnPropertyChanged(propertyName);
        }

        IEnumerable INotifyDataErrorInfo.GetErrors(string propertyName)
        {
            if (string.IsNullOrEmpty(propertyName) || !_validationErrors.ContainsKey(propertyName))
                return null;
            return _validationErrors[propertyName];
        }
        #endregion

        public bool ValidateProperty(ValidationRule validator, [CallerMemberName] string propertyName = null)
        {
            /* Call service asynchronously */
            bool result = false;
            ValidationResult validationResult = validator.Validate(this, null);
            if (validationResult != null)
            {
                ICollection&lt;string&gt; validationErrors = new List&lt;string&gt;();
                ICollection&lt;string&gt; warningMessages = new List&lt;string&gt;();
                if (validationResult.IsValid == false)
                {
                    validationErrors.Add(validationResult.ErrorContent.ToString());
                    result = validationResult.IsValid;
                }
                else if (validationResult is WarnedValidationResult)
                {
                    WarnedValidationResult warnedValidationResult = validationResult as WarnedValidationResult;
                    if (warnedValidationResult.IsWarned)
                    {       
                        warningMessages.Add(warnedValidationResult.ErrorContent.ToString());
                        result = false;
                    }
                    else
                    {
                        result = true;
                    }
                }
                UpdateValidationErrors(propertyName, validationErrors);
                UpdateValidationWarnings(propertyName, warningMessages);
            }
            return result;
        }
    }</pre>
<p>&nbsp;</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.chunho-ling.com/mvvm-%e5%bb%ba%e7%ab%8b-warning-control/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">790</post-id>	</item>
		<item>
		<title>[WPF] 進行Event Binding</title>
		<link>https://www.chunho-ling.com/wpf-%e9%80%b2%e8%a1%8cevent-binding/</link>
					<comments>https://www.chunho-ling.com/wpf-%e9%80%b2%e8%a1%8cevent-binding/#comments</comments>
		
		<dc:creator><![CDATA[C.H. Ling]]></dc:creator>
		<pubDate>Fri, 29 Sep 2017 10:29:45 +0000</pubDate>
				<category><![CDATA[Computing]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Window Presentation Foundation (WPF)]]></category>
		<guid isPermaLink="false">http://www.chunho-ling.com/?p=776</guid>

					<description><![CDATA[在建立form based application 時常常都會觸發事件, 而以往都會在code-behind 處理, 然而這樣會令測試變得難以透過Unit Test Project 自動化. 亦因此在WPF 中亦有方法去應對. 加入 System.Windows.InterActivity 作reference 後, 再於需要叫用的form 加入以下xml namespace 作叫用. xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" 使用範例: &#60;DataGrid&#62; &#60;i:Interaction.Triggers&#62; &#60;i:EventTrigger EventName="SourceUpdated"&#62; &#60;i:InvokeCommandAction Command="{Binding SelectedExternalDataUpdated}" /&#62; &#60;/i:EventTrigger&#62; &#60;i:EventTrigger EventName="SelectionChanged"&#62; &#60;i:InvokeCommandAction Command="{Binding <a class="mh-excerpt-more" href="https://www.chunho-ling.com/wpf-%e9%80%b2%e8%a1%8cevent-binding/" title="[WPF] 進行Event Binding">[...]</a>]]></description>
										<content:encoded><![CDATA[<p>在建立form based application 時常常都會觸發事件, 而以往都會在code-behind 處理, 然而這樣會令測試變得難以透過Unit Test Project 自動化. 亦因此在WPF 中亦有方法去應對.<span id="more-776"></span></p>
<p>加入 System.Windows.InterActivity 作reference 後, 再於需要叫用的form 加入以下xml namespace 作叫用.</p>
<pre class="lang:default decode:true">xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"</pre>
<p>使用範例:</p>
<pre class="lang:default decode:true">&lt;DataGrid&gt;
&lt;i:Interaction.Triggers&gt;
                        &lt;i:EventTrigger EventName="SourceUpdated"&gt;
                            &lt;i:InvokeCommandAction Command="{Binding SelectedExternalDataUpdated}" /&gt;
                        &lt;/i:EventTrigger&gt;
                        &lt;i:EventTrigger EventName="SelectionChanged"&gt;
                            &lt;i:InvokeCommandAction Command="{Binding SelectedExternalDataChanged}" /&gt;
                        &lt;/i:EventTrigger&gt;
                    &lt;/i:Interaction.Triggers&gt;
                &lt;DataGrid&gt;</pre>
<p>&nbsp;</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.chunho-ling.com/wpf-%e9%80%b2%e8%a1%8cevent-binding/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">776</post-id>	</item>
		<item>
		<title>[WPF] 自建DataGrid Column</title>
		<link>https://www.chunho-ling.com/wpf-%e8%87%aa%e5%bb%badatagrid-column/</link>
					<comments>https://www.chunho-ling.com/wpf-%e8%87%aa%e5%bb%badatagrid-column/#respond</comments>
		
		<dc:creator><![CDATA[C.H. Ling]]></dc:creator>
		<pubDate>Mon, 25 Sep 2017 06:50:13 +0000</pubDate>
				<category><![CDATA[C#]]></category>
		<category><![CDATA[Computing]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Window Presentation Foundation (WPF)]]></category>
		<guid isPermaLink="false">http://www.chunho-ling.com/?p=741</guid>

					<description><![CDATA[在WPF 的DataGrid 中, 若需要自設DataGridColumn, 可以利用XAML DataGridTemplateColumn. 然而若遇到AutoGenerateColumn為true 或須要增加其re-usability 時, 自建user control 反而比較化算.&#160; 在這裡, 會建立兩個DataGird column來分別存取數字和日期.&#160; 建立DataGrid column 時, 只須要建立一個class 並inherit DataGridBoundColumn 或其sub class 便可. 之後再implement method 分別建立View 及Edit 時的DataTemplate 便可. DateGridDateTimeColumn.cs public class DataGridDateTimeColumn : <a class="mh-excerpt-more" href="https://www.chunho-ling.com/wpf-%e8%87%aa%e5%bb%badatagrid-column/" title="[WPF] 自建DataGrid Column">[...]</a>]]></description>
										<content:encoded><![CDATA[<p>在WPF 的DataGrid 中, 若需要自設DataGridColumn, 可以利用XAML DataGridTemplateColumn. 然而若遇到AutoGenerateColumn為true 或須要增加其re-usability 時, 自建user control 反而比較化算.&nbsp;</p>
<p>在這裡, 會建立兩個DataGird column來分別存取數字和日期.&nbsp;</p>
<p><span id="more-741"></span></p>
<p>建立DataGrid column 時, 只須要建立一個class 並inherit DataGridBoundColumn 或其sub class 便可. 之後再implement method 分別建立View 及Edit 時的DataTemplate 便可.</p>
<p>DateGridDateTimeColumn.cs</p>
<pre class="lang:c# decode:true " title="DataGridDateTimeColumn.cs">public class DataGridDateTimeColumn : DataGridBoundColumn
    {
        protected override FrameworkElement GenerateEditingElement(DataGridCell cell, object dataItem)
        {
            return GenerateDatePicker(dataItem);
        }

        protected override FrameworkElement GenerateElement(DataGridCell cell, object dataItem)
        {
            return GenerateTextBlock(dataItem);
        }

        private DatePicker GenerateDatePicker(object source)
        {
            DatePicker result = new DatePicker()
            {
                Margin = new Thickness() { Bottom = 0, Left = 0, Right = 0, Top = 0 },
                Padding = new Thickness() { Bottom = -2, Left = -2, Right = -2, Top = -2 }
            };
            Binding baseBinding = this.Binding as Binding;
            Binding binding = new Binding()
            {
                Path = baseBinding.Path,
                Source = source,
                Mode = BindingMode.TwoWay,
                StringFormat = Properties.Settings.Default.DisplayDateFormat
            };
            result.SetBinding(DatePicker.SelectedDateProperty, binding);
            return result;
        }

        private TextBlock GenerateTextBlock(object source)
        {
            TextBlock result = new TextBlock()
            {
                Margin = new Thickness() { Bottom = 0, Left = 0, Right = 0, Top = 0 },
                TextAlignment = TextAlignment.Left,
                VerticalAlignment = VerticalAlignment.Top
            };
            Binding baseBinding = this.Binding as Binding;
            Binding binding = new Binding()
            {
                Path = baseBinding.Path,
                Source = source,
                Mode = BindingMode.TwoWay,
                StringFormat = Properties.Settings.Default.DisplayDateFormat
            };
            result.SetBinding(TextBlock.TextProperty, binding);
            return result;
        }
    }</pre>
<p>DataGridNumericColumn.cs</p>
<pre class="lang:default decode:true " title="DataGridNumericColumn.cs">public class DataGridNumericColumn : DataGridTextColumn
    {
        protected override object PrepareCellForEdit(System.Windows.FrameworkElement editingElement, System.Windows.RoutedEventArgs editingEventArgs)
        {
            TextBox edit = editingElement as TextBox;
            edit.PreviewTextInput += OnPreviewTextInput;

            return base.PrepareCellForEdit(editingElement, editingEventArgs);
        }

        private void OnPreviewTextInput(object sender, System.Windows.Input.TextCompositionEventArgs e)
        {
            e.Handled = (!IsDataValid(e.Text));
        }

        private void OnPaste(object sender, DataObjectPastingEventArgs e)
        {
            var data = e.SourceDataObject.GetData(DataFormats.Text);
            if (!IsDataValid(data)) e.CancelCommand();
        }

        private bool IsDataValid(object data)
        {
            return ((string)data).IsNumeric();
        }
    }</pre>
<p>叫用時, 只須設定好xml namesapace 後, 像平時用user control 般便可. 例如:</p>
<pre class="lang:xhtml decode:true ">&lt;DataGrid.Columns&gt;
                &lt;local:DataGridNumericColumn Header="Number" Binding="{Binding NumericProperty, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" /&gt;
                &lt;local:DataGridDateTimeColumn Header="Date" Binding="{Binding DateTimeProperty, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" /&gt;
&lt;/DataGrid.Columns&gt;</pre>
<p>&nbsp;</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.chunho-ling.com/wpf-%e8%87%aa%e5%bb%badatagrid-column/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">741</post-id>	</item>
		<item>
		<title>[WPF] DataGrid 對Abstract class 進行Binding</title>
		<link>https://www.chunho-ling.com/wpf-datagrid-%e5%b0%8dabstract-class-%e9%80%b2%e8%a1%8cbinding/</link>
					<comments>https://www.chunho-ling.com/wpf-datagrid-%e5%b0%8dabstract-class-%e9%80%b2%e8%a1%8cbinding/#respond</comments>
		
		<dc:creator><![CDATA[C.H. Ling]]></dc:creator>
		<pubDate>Mon, 04 Sep 2017 08:16:02 +0000</pubDate>
				<category><![CDATA[C#]]></category>
		<category><![CDATA[Computing]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Window Presentation Foundation (WPF)]]></category>
		<guid isPermaLink="false">http://www.chunho-ling.com/?p=731</guid>

					<description><![CDATA[在正常情況下, 當WPF datagrid bind abstract class 時, 只會顯示該abstract class 內容, 而implement 的attribute 則不會出現. 這是因為這個binding 過程乃在compile time 進行而非run-time 進行. 若要實現的話, 則須要進行部份設置. XAML 設定, 當欄更新時觸發事件. &#60;DataGrid AutoGenerateColumns="True" LoadingRow="DataGrid_LoadingRow"&#62; &#60;/DataGrid&#62; Code-behind, 將DataContext 每個property 重新放到UI 中. private void DataGrid_LoadingRow(object <a class="mh-excerpt-more" href="https://www.chunho-ling.com/wpf-datagrid-%e5%b0%8dabstract-class-%e9%80%b2%e8%a1%8cbinding/" title="[WPF] DataGrid 對Abstract class 進行Binding">[...]</a>]]></description>
										<content:encoded><![CDATA[<p>在正常情況下, 當WPF datagrid bind abstract class 時, 只會顯示該abstract class 內容, 而implement 的attribute 則不會出現. 這是因為這個binding 過程乃在compile time 進行而非run-time 進行. 若要實現的話, 則須要進行部份設置.<span id="more-731"></span></p>
<p>XAML 設定, 當欄更新時觸發事件.</p>
<pre class="lang:xhtml decode:true">&lt;DataGrid AutoGenerateColumns="True" LoadingRow="DataGrid_LoadingRow"&gt;
&lt;/DataGrid&gt;</pre>
<p>Code-behind, 將DataContext 每個property 重新放到UI 中.</p>
<pre class="lang:c# decode:true">private void DataGrid_LoadingRow(object sender, DataGridRowEventArgs e)
        {
            var dg = sender as DataGrid;
            var pis = e.Row.DataContext.GetType().GetProperties();
            foreach (var pi in pis)
            {
                // Check if this property already has a column in the datagrid
                string name = pi.Name;
                var q = dg.Columns.Where(_ =&gt; _.SortMemberPath == name);
                if (!q.Any())
                {
                    // No column matches, so add one
                    DataGridTextColumn c = new DataGridTextColumn();
                    c.Header = name;
                    c.SortMemberPath = name;
                    System.Windows.Data.Binding b = new Binding(name);
                    c.Binding = b;

                    // All columns don't apply to all items in the list
                    // So, we need to disable the cells that aren't applicable
                    // We'll use a converter on the IsEnabled property of the cell
                    b = new Binding();
                    b.Converter = new ReadOnlyConverter();
                    b.ConverterParameter = name;
                    // aa
                    b.ValidatesOnDataErrors = true;

                    // Can't apply it directly, so we have to make a style that applies it
                    Style s = new Style(typeof(DataGridCell));
                    s.Setters.Add(new Setter(DataGridCell.IsEnabledProperty, b));
                    // Add a trigger to the style to color the background when disabled
                    var dt = new DataTrigger() { Binding = b, Value = false };
                    dt.Setters.Add(new Setter(DataGridCell.BackgroundProperty, Brushes.Silver));
                    s.Triggers.Add(dt);
                    c.CellStyle = s;

                    // Add the column to the datagrid
                    dg.Columns.Add(c);
                }
            }
        }</pre>
<p>&nbsp;</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.chunho-ling.com/wpf-datagrid-%e5%b0%8dabstract-class-%e9%80%b2%e8%a1%8cbinding/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">731</post-id>	</item>
		<item>
		<title>[WPF] 自建Toolbar Icon</title>
		<link>https://www.chunho-ling.com/wpf-%e8%87%aa%e5%bb%batoolbar-icon/</link>
					<comments>https://www.chunho-ling.com/wpf-%e8%87%aa%e5%bb%batoolbar-icon/#respond</comments>
		
		<dc:creator><![CDATA[C.H. Ling]]></dc:creator>
		<pubDate>Thu, 22 Jun 2017 04:05:35 +0000</pubDate>
				<category><![CDATA[C#]]></category>
		<category><![CDATA[Computing]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Window Presentation Foundation (WPF)]]></category>
		<guid isPermaLink="false">http://www.chunho-ling.com/?p=718</guid>

					<description><![CDATA[Tool bar 在以往的UI 開發上, 通常都是將表格功能放在一堆中方便使用. 在WPF 中, 繼續沿用此功能. 然而, 若要將其抽離作User Control, 則會真的變了一個button, 所以須要作若干手動修正. Resource Dictionary style.xaml &#60;Style TargetType="fa:ImageAwesome" x:Key="ToolBarIcon"&#62; &#60;Setter Property="Width" Value="12" /&#62; &#60;Setter Property="Margin" Value="6" /&#62; &#60;/Style&#62; 因為Visual Studio 的XAML design 的root tag 預設只支援&#60;Window&#62;, <a class="mh-excerpt-more" href="https://www.chunho-ling.com/wpf-%e8%87%aa%e5%bb%batoolbar-icon/" title="[WPF] 自建Toolbar Icon">[...]</a>]]></description>
										<content:encoded><![CDATA[<p>Tool bar 在以往的UI 開發上, 通常都是將表格功能放在一堆中方便使用. 在WPF 中, 繼續沿用此功能. 然而, 若要將其抽離作User Control, 則會真的變了一個button, 所以須要作若干手動修正.</p>
<p><span id="more-718"></span></p>
<p>Resource Dictionary style.xaml</p>
<pre class="lang:xhtml decode:true" title="Style.xaml">  &lt;Style TargetType="fa:ImageAwesome" x:Key="ToolBarIcon"&gt;
        &lt;Setter Property="Width" Value="12" /&gt;
        &lt;Setter Property="Margin" Value="6" /&gt;
    &lt;/Style&gt;</pre>
<p>因為Visual Studio 的XAML design 的root tag 預設只支援&lt;Window&gt;, &lt;Page&gt; 和&lt;UserControl&gt;, 故沒有用&lt;Button&gt; 作Root tag, 而為了令按鈕變得更似Toolbar Button, 故將其border 及background 都透明化.</p>
<p>ToolbarButton.xaml</p>
<pre class="lang:default decode:true">&lt;UserControl x:Class="Test.UserControls.ToolBarButton"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:Test.UserControls"
             xmlns:fa="http://schemas.fontawesome.io/icons/"
             mc:Ignorable="d" 
             d:DesignHeight="30" d:DesignWidth="70"&gt;
    &lt;UserControl.Resources&gt;
        &lt;ResourceDictionary&gt;
            &lt;ResourceDictionary.MergedDictionaries&gt;
                &lt;ResourceDictionary Source="../style.xaml" /&gt;
            &lt;/ResourceDictionary.MergedDictionaries&gt;
        &lt;/ResourceDictionary&gt;
    &lt;/UserControl.Resources&gt;
    &lt;Button Command="{Binding Command, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=UserControl}, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Background="Transparent" BorderBrush="Transparent"&gt;
        &lt;StackPanel Orientation="Horizontal"&gt;
            &lt;fa:ImageAwesome Icon="{Binding Icon, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=UserControl}, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" 
                             Style="{StaticResource ToolBarIcon}"
                             /&gt;
            &lt;TextBlock Text="{Binding Text, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=UserControl}, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" /&gt;
        &lt;/StackPanel&gt;
    &lt;/Button&gt;
&lt;/UserControl&gt;
</pre>
<p>ToolbarButton.xaml.cs</p>
<pre class="lang:c# decode:true">using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;

namespace Test.UserControls
{
    /// &lt;summary&gt;
    /// Interaction logic for ToolBarButton.xaml
    /// &lt;/summary&gt;
    public partial class ToolBarButton : UserControl
    {
        public object Text
        {
            get { return GetValue(TextProperty) as object; }
            set { SetValue(TextProperty, value); }
        }
        public static readonly DependencyProperty TextProperty =
            DependencyProperty.Register("Text", typeof(object), typeof(ToolBarButton));

        public object Icon
        {
            get { return GetValue(IconProperty) as object; }
            set { SetValue(IconProperty, value); }
        }
        public static readonly DependencyProperty IconProperty =
            DependencyProperty.Register("Icon", typeof(object), typeof(ToolBarButton));

        public ICommand Command
        {
            get { return GetValue(CommandProperty) as ICommand; }
            set { SetValue(CommandProperty, value); }
        }
        public static readonly DependencyProperty CommandProperty =
            DependencyProperty.Register("Command", typeof(ICommand), typeof(ToolBarButton));

        public ToolBarButton()
        {
            InitializeComponent();
        }
    }
}
</pre>
<p>叫用時與正常手法如下:</p>
<pre class="lang:default decode:true "> &lt;ToolBarTray&gt;
            &lt;ToolBar&gt;
                &lt;Button&gt;
                    &lt;StackPanel Orientation="Horizontal"&gt;
                        &lt;fa:ImageAwesome Icon="FileOutline" Style="{StaticResource ToolBarIcon}" /&gt;
                        &lt;TextBlock Text="Import" /&gt;
                    &lt;/StackPanel&gt;
                &lt;/Button&gt;
                &lt;userControls:ToolBarButton Icon="FileOutline" Text="Import" /&gt;
            &lt;/ToolBar&gt;
        &lt;/ToolBarTray&gt;</pre>
<p>&nbsp;</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.chunho-ling.com/wpf-%e8%87%aa%e5%bb%batoolbar-icon/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">718</post-id>	</item>
		<item>
		<title>[心得] WPF MVVM vs ASP.net MVC</title>
		<link>https://www.chunho-ling.com/%e5%bf%83%e5%be%97-wpf-mvvm-vs-asp-net-mvc/</link>
					<comments>https://www.chunho-ling.com/%e5%bf%83%e5%be%97-wpf-mvvm-vs-asp-net-mvc/#respond</comments>
		
		<dc:creator><![CDATA[C.H. Ling]]></dc:creator>
		<pubDate>Mon, 29 May 2017 03:14:55 +0000</pubDate>
				<category><![CDATA[Application Framework 程式框架]]></category>
		<category><![CDATA[ASP.net MVC]]></category>
		<category><![CDATA[Computing]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Window Presentation Foundation (WPF)]]></category>
		<guid isPermaLink="false">http://www.chunho-ling.com/?p=670</guid>

					<description><![CDATA[自從轉了工種後, 做過不同類型的projects, 亦試了應用不同的平台, 然而, 技術不是重點, 最重是選擇最理想的工具. 根據經驗整理後, 重點有四項:&#160;用戶群, 是否需要跨平台, 硬件配套, Standalone / Multi-tier. 用戶群 用戶(End-user) 即是系統的最終使用者. 其實分幾種層面: 對外 (External), 用家是客戶, 重點是要方便使用, 非必要的話不用安裝軟件到&#8221;衪們&#8221;的裝置上, 而且其使用平台亦相當多變. 要覆蓋最大範圍的話, 都會選擇用Web-based 平台, 只要有瀏覽器(Browser)便可以給用家使用. 所以ASP.net MVC 會是首選. 對內 (Internal), 用家通常是公司內員工, 或者說是自己以外, 公司以內的任何人. <a class="mh-excerpt-more" href="https://www.chunho-ling.com/%e5%bf%83%e5%be%97-wpf-mvvm-vs-asp-net-mvc/" title="[心得] WPF MVVM vs ASP.net MVC">[...]</a>]]></description>
										<content:encoded><![CDATA[<p>自從轉了工種後, 做過不同類型的projects, 亦試了應用不同的平台, 然而, 技術不是重點, 最重是選擇最理想的工具. 根據經驗整理後, 重點有四項:&nbsp;用戶群, 是否需要跨平台, 硬件配套, Standalone / Multi-tier.<span id="more-670"></span></p>
<h1>用戶群</h1>
<p>用戶(End-user) 即是系統的最終使用者. 其實分幾種層面:</p>
<p>對外 (External), 用家是客戶, 重點是要方便使用, 非必要的話不用安裝軟件到&#8221;衪們&#8221;的裝置上, 而且其使用平台亦相當多變. 要覆蓋最大範圍的話, 都會選擇用Web-based 平台, 只要有瀏覽器(Browser)便可以給用家使用. 所以ASP.net MVC 會是首選.</p>
<p>對內 (Internal), 用家通常是公司內員工, 或者說是自己以外, 公司以內的任何人. 通常已經有一套標準, 較容易控制, 數量相對External 比較亦較小, 所以使用WPF MVVM 會是較佳的選擇. 然而, 若果在大企業, 多國之間都有其IT department, 而亦有workflow 須要跨國進行的話, ASP.net MVC 反而值得考慮; 總之在internal 環境中, 的確須要視乎情況決定.</p>
<p>自己 (self), 這個是自己加入的. 有時候為了加快delivery, 可能部份configuration DIY tools 未能提供, 只會加入到database / xml config 中, 這種情況就須要靠自己了. 為了不讓自己遺臭萬年以及方便將工作推卸出去, 自己都會建立一個介面去進行維護. 當然, 這個是什麼都不太重要了, 通常決定方針都嫁雞隨雞, 跟回application. 當然做in-house 有時須要維護不同模組, 自建簡陋的 MMC snap-in反而會是不錯的選擇.</p>
<h1>是否需要跨平台</h1>
<p>這裡的跨平台, 其實是用戶群的衍生, 決策重點是自己是否能夠預估End-user 是怎樣使用系統. 現在公司常用的系統都是Windows (當然, 部份公司會用Mac); 然而, 流動平台的興起也令End-user environment 出現變數. Android / iOS / Blackberry 不同的操作平台, 即使用自詡跨平台的Java 也吃不消, 這個時候, 反而 Web-based 平台將所有東西中央管理可以發揮到; WPF 的話, Linux 的Mono 也只支援WinForm, 而相類似的Silverlight 連Microsoft 也depreciated, 支援mobile device 亦因此變了場夢.</p>
<h1>硬件配套</h1>
<p>部份系統運作, 用戶端須要配合硬件, 例如醫療儀器須要透過COM / LPT / port 與電腦溝通, 生物認證須要用指模/瞳孔等傳送認證資料. 若有這種關聯的話, 則非WPF MVVM 莫屬. 若ASP.net MVC 這類web 平台須要運用的話, 則須要安裝ActiveX control / WebUSB API, 但這類則限制了用戶端平台, 而且ActiveX control 亦已depreciated 及WebUSB 仍未成熟, 暫時Web 平台, 即係ASP.net MVC 不是一個好選擇.</p>
<h1>Standalone / Multi-tier</h1>
<p>Standalone 即是單一系統, 所有東西(包括Database) 都放在自身系統中, 好處是方便部署(Deployment), 只須copy and paste 便完成. 在WPF MVVM 中, 亦具備此功能. 只要確定用戶端有安裝相對應的.net Platform 版本便可; 然而在ASP.net MVC 中, 即使使用Local DB, 但它仍須要在client 中安裝及設定IIS才可使用, 故這方面它較為輸蝕.</p>
<p>Multi-tier 是早年興起的系統架構 (Application Architecture), 即是將系統模組化 (Modulize), 並將不同模組部署在不同伺服器中(鐵 / VM / Container)執行. 從而做到管理上的 SoC (Separation of Concern). 而WPF MVVM 中, 即使用接駁 remote Database, 也只是2 tiers, 若須要設計的話, 則須要將其Controller 搬離至application server 中; 而ViewModel 和 View, 則只是控制UI部份; 而ASP.net MVC 中, 本身寄居在Web server 中的特性也使它天生支援multi-tier (包括用戶的Browser 和remote database, 已經3 tiers), 然而, 若想將View 和Controller 硬件分離的話, 則與WPF一樣, 建立web service 並配置於另外的伺服器中.</p>
<h1>總結</h1>
<p>總括而言, 其實選擇WPF MVVM 還是ASP.net MVC, 已變得像Form-based vs Web-based, 在決定時, 最重要是知道用戶條件及規劃的長遠性. 引用一句: 沒有最好的裝備, 只有最適合的裝備.</p>
<p>參考資料</p>
<ul>
<li><a href="http://www.mono-project.com/docs/gui/wpf/" target="_blank" rel="noopener noreferrer">WPF Mono,<br />
http://www.mono-project.com/docs/gui/wpf/</a></li>
<li><a href="https://blogs.windows.com/msedgedev/2015/05/06/a-break-from-the-past-part-2-saying-goodbye-to-activex-vbscript-attachevent/#RSzVEg7mXGFegkfK.97" target="_blank" rel="noopener noreferrer">A break from the past, part 2: Saying goodbye to ActiveX, VBScript, attachEvent…, Microsoft,&nbsp;<br />
https://blogs.windows.com/msedgedev/2015/05/06/a-break-from-the-past-part-2-saying-goodbye-to-activex-vbscript-attachevent/#RSzVEg7mXGFegkfK.97</a></li>
<li><a href="https://developers.google.com/web/updates/2016/03/access-usb-devices-on-the-web" target="_blank" rel="noopener noreferrer">Access USB Devices on the Web, Google Developer,&nbsp;<br />
https://developers.google.com/web/updates/2016/03/access-usb-devices-on-the-web</a></li>
</ul>
]]></content:encoded>
					
					<wfw:commentRss>https://www.chunho-ling.com/%e5%bf%83%e5%be%97-wpf-mvvm-vs-asp-net-mvc/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">670</post-id>	</item>
		<item>
		<title>[WPF] 於ListView 中自訂Key Search</title>
		<link>https://www.chunho-ling.com/wpf-%e6%96%bclistview-%e4%b8%ad%e8%87%aa%e8%a8%82key-search/</link>
					<comments>https://www.chunho-ling.com/wpf-%e6%96%bclistview-%e4%b8%ad%e8%87%aa%e8%a8%82key-search/#respond</comments>
		
		<dc:creator><![CDATA[C.H. Ling]]></dc:creator>
		<pubDate>Thu, 04 May 2017 05:14:02 +0000</pubDate>
				<category><![CDATA[Computing]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Window Presentation Foundation (WPF)]]></category>
		<guid isPermaLink="false">http://www.chunho-ling.com/?p=649</guid>

					<description><![CDATA[為了提高UX, 在ListView中輸入字符時, 通常都會跳去指定的item中, 然而用Bind 了object 後若須要指定用什麼property 進行搜尋, 則需要再作設定. 在WPF中, 無須特別去加code 作customize search, 只須於XAML 中指定attribute 便可. 例子:&#160; &#60;ListView TextSearch.TextPath="FirstName" /&#62; &#160;]]></description>
										<content:encoded><![CDATA[<p>為了提高UX, 在ListView中輸入字符時, 通常都會跳去指定的item中, 然而用Bind 了object 後若須要指定用什麼property 進行搜尋, 則需要再作設定.<span id="more-649"></span></p>
<p>在WPF中, 無須特別去加code 作customize search, 只須於XAML 中指定attribute 便可.</p>
<p>例子:&nbsp;</p>
<pre class="lang:default decode:true ">&lt;ListView 
    TextSearch.TextPath="FirstName"
/&gt;</pre>
<p>&nbsp;</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.chunho-ling.com/wpf-%e6%96%bclistview-%e4%b8%ad%e8%87%aa%e8%a8%82key-search/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">649</post-id>	</item>
		<item>
		<title>[WPF] 使用Fontawesome 圖示</title>
		<link>https://www.chunho-ling.com/wpf-%e4%bd%bf%e7%94%a8fontawesome-%e5%9c%96%e7%a4%ba/</link>
					<comments>https://www.chunho-ling.com/wpf-%e4%bd%bf%e7%94%a8fontawesome-%e5%9c%96%e7%a4%ba/#respond</comments>
		
		<dc:creator><![CDATA[C.H. Ling]]></dc:creator>
		<pubDate>Wed, 19 Apr 2017 04:06:20 +0000</pubDate>
				<category><![CDATA[Computing]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Window Presentation Foundation (WPF)]]></category>
		<guid isPermaLink="false">http://www.chunho-ling.com/?p=633</guid>

					<description><![CDATA[之前介紹過Fontawesome 是一套Bootstrap 的icon library. 然而只限於web application 中使用. 在正常情況下, 在WPF中亦須要render SVG file. Font-Awesome-WPF 是一套將fontawesome 轉至WPF 的library, 於 XMAL 中叫用方法如下: &#60;Window x:Class="Example.FontAwesome.WPF.Single" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:fa="http://schemas.fontawesome.io/icons/" Title="Single" Height="300" Width="300"&#62; &#60;Grid Margin="20"&#62; &#60;fa:ImageAwesome Icon="Flag" VerticalAlignment="Center" HorizontalAlignment="Center" /&#62; &#60;/Grid&#62; &#60;/Window&#62; <a class="mh-excerpt-more" href="https://www.chunho-ling.com/wpf-%e4%bd%bf%e7%94%a8fontawesome-%e5%9c%96%e7%a4%ba/" title="[WPF] 使用Fontawesome 圖示">[...]</a>]]></description>
										<content:encoded><![CDATA[<p>之前介紹過Fontawesome 是一套Bootstrap 的icon library. 然而只限於web application 中使用. 在正常情況下, 在WPF中亦須要render SVG file.<span id="more-633"></span></p>
<p>Font-Awesome-WPF 是一套將fontawesome 轉至WPF 的library, 於 XMAL 中叫用方法如下:</p>
<pre class="lang:default decode:true ">&lt;Window x:Class="Example.FontAwesome.WPF.Single"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:fa="http://schemas.fontawesome.io/icons/"
        Title="Single" Height="300" Width="300"&gt;
    &lt;Grid  Margin="20"&gt;
        &lt;fa:ImageAwesome Icon="Flag" VerticalAlignment="Center" HorizontalAlignment="Center" /&gt;
    &lt;/Grid&gt;
&lt;/Window&gt;</pre>
<p>&nbsp;</p>
<p>參考資料</p>
<p><a href="https://github.com/charri/Font-Awesome-WPF" target="_blank">Font-Awesome-WPF, Github, https://github.com/charri/Font-Awesome-WPF</a></p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.chunho-ling.com/wpf-%e4%bd%bf%e7%94%a8fontawesome-%e5%9c%96%e7%a4%ba/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">633</post-id>	</item>
		<item>
		<title>[WPF] 於DataGrid Binding 使用自定標題</title>
		<link>https://www.chunho-ling.com/wpf-%e6%96%bcdatagrid-binding-%e4%bd%bf%e7%94%a8%e8%87%aa%e5%ae%9a%e6%a8%99%e9%a1%8c/</link>
					<comments>https://www.chunho-ling.com/wpf-%e6%96%bcdatagrid-binding-%e4%bd%bf%e7%94%a8%e8%87%aa%e5%ae%9a%e6%a8%99%e9%a1%8c/#respond</comments>
		
		<dc:creator><![CDATA[C.H. Ling]]></dc:creator>
		<pubDate>Wed, 29 Mar 2017 07:27:55 +0000</pubDate>
				<category><![CDATA[C#]]></category>
		<category><![CDATA[Computing]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Window Presentation Foundation (WPF)]]></category>
		<guid isPermaLink="false">http://www.chunho-ling.com/?p=620</guid>

					<description><![CDATA[利用DataGrid 來列示資料是一件正常事, 然而, 在WPF中若須要列出class property, 若用原廠設定的話, 標題會用property name. 若需要自定標題, 則須要應用DomainNameAttribute 來設置. 在示範中, 會建立一個user control inherit 原廠DataGrid 去設定標題. CommonDataGrid.xaml &#60;DataGrid x:Class="WPF.CommonDataGrid.CommonDataGrid" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:WPF.CommonDataGrid" mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="300" AutoGenerateColumns="True" AutoGeneratingColumn="OnAutoGeneratingColumn" /&#62; CommonDataGrid.xaml.cs public partial class <a class="mh-excerpt-more" href="https://www.chunho-ling.com/wpf-%e6%96%bcdatagrid-binding-%e4%bd%bf%e7%94%a8%e8%87%aa%e5%ae%9a%e6%a8%99%e9%a1%8c/" title="[WPF] 於DataGrid Binding 使用自定標題">[...]</a>]]></description>
										<content:encoded><![CDATA[<p>利用DataGrid 來列示資料是一件正常事, 然而, 在WPF中若須要列出class property, 若用原廠設定的話, 標題會用property name. 若需要自定標題, 則須要應用DomainNameAttribute 來設置.<span id="more-620"></span></p>
<p>在示範中, 會建立一個user control inherit 原廠DataGrid 去設定標題.</p>
<p>CommonDataGrid.xaml</p>
<pre class="lang:default decode:true" title="CommonDataGrid.xaml">&lt;DataGrid x:Class="WPF.CommonDataGrid.CommonDataGrid"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:WPF.CommonDataGrid"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300"
             AutoGenerateColumns="True" AutoGeneratingColumn="OnAutoGeneratingColumn" /&gt;

</pre>
<p>CommonDataGrid.xaml.cs</p>
<pre class="lang:c# decode:true" title="CommonDataGrid.xaml.cs"> public partial class CommonDataGrid : DataGrid
    {
        public CommonDataGrid()
        {
            InitializeComponent();
        }

        private void OnAutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
        {
            string displayName = GetPropertyDisplayName(e.PropertyDescriptor);
            if (!string.IsNullOrEmpty(displayName))
            {
                e.Column.Header = displayName;
            }

        }

        public static string GetPropertyDisplayName(object descriptor)
        {
            PropertyDescriptor pd = descriptor as PropertyDescriptor;
            if (pd != null)
            {
                // Check for DisplayName attribute and set the column header accordingly
                DisplayNameAttribute displayName = pd.Attributes[typeof(DisplayNameAttribute)] as DisplayNameAttribute;

                if (displayName != null &amp;&amp; displayName != DisplayNameAttribute.Default)
                {
                    return displayName.DisplayName;
                }

            }
            else
            {
                PropertyInfo pi = descriptor as PropertyInfo;
                if (pi != null)
                {
                    // Check for DisplayName attribute and set the column header accordingly
                    Object[] attributes = pi.GetCustomAttributes(typeof(DisplayNameAttribute), true);
                    for (int i = 0; i &lt; attributes.Length; ++i)
                    {
                        DisplayNameAttribute displayName = attributes[i] as DisplayNameAttribute;
                        if (displayName != null &amp;&amp; displayName != DisplayNameAttribute.Default)
                        {
                            return displayName.DisplayName;
                        }
                    }
                }
            }
            return null;
        }
    }</pre>
<p>在這裡, 應用了MVVM, 為了處理PropertyChanged, 建立了Base class ObservableProperty 去實現 INotifyPropertyChanged.</p>
<pre class="lang:default decode:true " title="ObservableProperty.cs"> public class ObservableProperty : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        protected virtual void OnPropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
        }
        protected bool SetField&lt;T&gt;(ref T field, T value, [CallerMemberName] string propertyName = null)
        {
            //if (EqualityComparer&lt;T&gt;.Default.Equals(field, value)) return false;
            field = value;
            OnPropertyChanged(propertyName);
            return true;
        }
    }</pre>
<p>為了測試, 建立了一個WPF Window作叫用:</p>
<pre class="lang:default decode:true " title="MainWindow.xaml">&lt;Window x:Class="WPF.TestUI.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WPF.TestUI"
        xmlns:Common="clr-namespace:WPF.CommonDataGrid;assembly=WPF.CommonDataGrid"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525"&gt;
    &lt;Window.DataContext&gt;
        &lt;local:MainWindowViewModel /&gt;
    &lt;/Window.DataContext&gt;
    &lt;Grid&gt;
        &lt;Common:CommonDataGrid ItemsSource="{Binding TestClasses, Mode=TwoWay}" /&gt;
    &lt;/Grid&gt;
&lt;/Window&gt;
</pre>
<p>MainWindow.xaml.cs</p>
<pre class="lang:default decode:true" title="MainWindow.xaml.cs">using System.Windows;

namespace WPF.TestUI
{
    /// &lt;summary&gt;
    /// Interaction logic for MainWindow.xaml
    /// &lt;/summary&gt;
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
    }
}
</pre>
<p>TestClass.cs</p>
<pre class="lang:default decode:true" title="TestClass.cs">using System.ComponentModel;

namespace WPF.CommonDataGrid
{
    public class TestClass : ObservableProperty
    {
        private int _testID;
        [DisplayName("Test ID")]
        public int TestID
        {
            get { return _testID; }
            set
            {
                _testID = value;
                SetField(ref _testID, value);
            }
        }
        private string _testStringValue;
        [DisplayName("Test string value")]
        public string TestStringValue
        {
            get { return _testStringValue; }
            set
            {
                _testStringValue = value;
                SetField(ref _testStringValue, value);
            }
        }
    }
}
</pre>
<p>MainWindowViewModel.cs</p>
<pre class="lang:default decode:true" title="MainWindowViewModel.cs">using System.Collections.ObjectModel;
using WPF.CommonDataGrid;

namespace WPF.TestUI
{
    public class MainWindowViewModel
    {
        public ObservableCollection&lt;TestClass&gt; TestClasses { get; set; }
        public MainWindowViewModel()
        {
            TestClasses = new ObservableCollection&lt;TestClass&gt;();
            TestClasses.Add(new TestClass() { TestID = 1, TestStringValue = "aaa" });
            TestClasses.Add(new TestClass() { TestID = 2, TestStringValue = "bbb" });
        }
    }
}
</pre>
]]></content:encoded>
					
					<wfw:commentRss>https://www.chunho-ling.com/wpf-%e6%96%bcdatagrid-binding-%e4%bd%bf%e7%94%a8%e8%87%aa%e5%ae%9a%e6%a8%99%e9%a1%8c/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">620</post-id>	</item>
	</channel>
</rss>
