星期日, 12月 24, 2017

[C#] override 和 new

上課時老師提到的 override 和 new 呼叫 method 辨識方式,有點像是記憶口訣的 fu,該篇記錄算是 [C#] new 關鍵字 的延伸
  • override:根據實作
  • new:根據執行個體
簡易 Code 說明

Employ e (執行個體) = new Manager (實作)

意思就是 override 呼叫 Manager.Method(),new 呼叫 Employ.Method()

星期二, 12月 19, 2017

PDF 匯入 OneNote

嘗試要把課程 PDF 匯進 OneNote,結果都會是 PDF 每頁圖片被縮在一個頁面內,但希望效果是每一張 PDF 變成一個頁面,在 OneNote 選項內找到設定值

檔案 => 選項 => 進階 => 列印成品 => 勾選 [在多頁上插入真的列印成品]

OneNote-1

匯入效果

OneNote-2

勾選設定後,匯入的 PDF 頁數要多一些才會有上述效果,有試過只指定匯入 5 頁,這 5 頁匯進 OneNote 內還是通通在同一個頁面內

Office 版本:Office 2016 家用版,非 OneNote App 版本

星期五, 9月 22, 2017

[git] detached Head

上 git 課程的內容,主要是說明 Detached Head 如何發生和修正

此為預設 git 線圖

[git] detach Head-1

對 Commit G 進行 git checkout,從下圖就知道,Detached Head 已經產生啦,該狀態是不在任何 branch 上的喔,應該建議應該下 git checkout -b BranchName 來建立 branch,讓該 commit 有所屬

[git] detach Head-2

假設使用者忽略上圖訊息,就直接寫 Code 且又 commit ,commit 名稱為 DetactHeadCommit

[git] detach Head-3

透過 TortoiseGit 來觀察線圖變化

[git] detach Head-4

假設在 Detacted Head 上完成,準備要切回 master 上來進行合併,切回 master 當下會有下面訊提醒,遺留一個 commit,要建立一個 branch 來保留它喔

[git] detach Head-5

利用 TortoiseGit 來觀察線圖,發現 DetactHeadCommit 不在線圖上啦

[git] detach Head-6

此時利用 git reflog 指令來找出 DetachHeadCommit 的 SHA1

[git] detach Head-7

利用 git checkout -b efa879 來讓 DetactHeadCommit 有所屬 branch

[git] detach Head-8

再利用 TotoiseGit 來顯示該 branch,就會看見 efea987 的 Parent Commit 是 Commit G 囉,DetactHeadCommit 並沒有消失不見,Code 還在

[git] detach Head-9

而 ToroiseGit 在這部分有防呆,當要 git checkout commit 時,option 內會預設要建立 branch

[git] detach Head-10

星期日, 9月 10, 2017

[git] 檔案刪除衝突

7天學會Git版本控制 書籍的解說範例,以往看到的解決衝突例子,都是 Code 同行更改來說明,這次看到是檔案被刪除,就想 try 一下,在 VSTS 上刪除該檔案,在 VS 上修改該檔案並進行同步

同步會發生衝突確認

[git] 檔案刪除衝突-1

進行衝突解決判斷

[git] 檔案刪除衝突-2

書籍內容說明
  • 保留檔案,利用 git add 把檔案再加入
  • 刪除檔案,利用 git rm 把檔案移除
在 Team Explore 內,只要點選保留檔案或刪除就可以做到囉

星期日, 9月 03, 2017

[git] 格式化 git log 查詢


內容中,都有介紹到格式化 git log 的設定,筆記一下
  • 原本 git log 結果
[git] 格式化 git log 查詢-1
  • 7天學會Git版本控制內容介紹
git config --global alias.lg "log --graph --decorate --pretty=oneline --abbrev-commit"
[git] 格式化 git log 查詢-2
  • SITCON Workshop - Git 版本控制入門課程介紹
git config --global alias.lg "log --color --graph --all --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit --"
[git] 格式化 git log 查詢-3

星期二, 8月 29, 2017

[X.Form] ListView - 更新資料

根據
的筆記,重點簡單記就是,ListView 資料來源有變更時,要透過 ObservableCollection 來通知,這樣 ListView 操作時才不會拋出 Exception

Model
namespace ListViewUpdate
{
    public class Product
    {
        public string Name { get; set; }

        public override string ToString()
        {
            return Name;
        }

        public static List<Product> GetData()
        {
            return new List<Product>
            {
                new Product() { Name = "楓葉" } ,
                new Product() { Name = "樹" } ,
                new Product() { Name = "花" } ,
                new Product() { Name = "煙火" } ,
                new Product() { Name = "夜景" }
            };
        }
    }
}
ViewModel
using System.ComponentModel;
using System.Windows.Input;
using Xamarin.Forms;
// ObservableCollection 所在的 namespace
using System.Collections.ObjectModel;

namespace ListViewUpdate
{
    public class ViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        // 引發錯誤版本
        public List<Product> Source { get; set; }

        public ICommand CmdInsert
        {
            get
            {
                return new Command(() => Source.Add(new Product() { Name = "植物" }));
            }
        }

        // 可更新版本
        public ObservableCollection<Product> UpdatableSource { get; set; }

        public ICommand CmdUpdatableInsert
        {
            // 上課內容是用 List.Insert 插到第一個順位
            get
            {
                return new Command(() => UpdatableSource.Add(new Product() { Name = "植物" }));
            }
        }

        public ViewModel()
        {
            // 引發錯誤版本
            Source = Product.GetData();

            // 可更新版本
            ObservableCollection<Product> ProdList = new ObservableCollection<Product>();
            foreach (var item in Product.GetData())
            {
                ProdList.Add(item);
            }

            UpdatableSource = ProdList;
        }
    }
}

星期五, 8月 25, 2017

[X.Form] ListView

根據教學影片 - 用 Listview 展現集合資料 的練習,重點在於
  • ItemSource:ListView 的資料來源
  • ToString():ListView Item 內容顯示
  • SelectedItem:指定預設值
  • SeparatorVisibility 和 SeparatorColor:分隔線和分隔線顏色
Xaml
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:ListViewBase"
             x:Class="ListViewBase.Base">

    <ContentPage.BindingContext>
        <local:ViewModel/>
    </ContentPage.BindingContext>

    <ContentPage.Content>
        <StackLayout>
            <ListView 
                ItemsSource="{Binding ItemsSource}"
                SelectedItem="{Binding SelectedItem ,Mode=TwoWay}"
                SeparatorVisibility="Default"
                SeparatorColor="Green"/>
        </StackLayout>
    </ContentPage.Content>

</ContentPage>
ViewModel
using System.Linq;
using System.ComponentModel;
namespace ListViewBase
{
    public class ViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        void OnPropertyChanged(string PropertyName)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(PropertyName));
        }

        public IList<Product> ItemsSource { get; set; }

        public ViewModel()
        {
            ItemsSource = Product.GetData();
            // 預設值為第三筆
            // SelectedItem = ItemsSource.Skip(2).FirstOrDefault();
            // 指定預設值為 "煙火"
            SelectedItem = ItemsSource.Where(w => w.Name == "煙火").FirstOrDefault();
        }

        public Product SelectedItem { get; set; }
    }
}
Model
namespace ListViewBase
{
    public class Product
    {
        public string Name { get; set; }

        public override string ToString()
        {
            return Name;
        }

        public static List<Product> GetData()
        {
            return new List<Product>
            {
                new Product() { Name = "楓葉" } ,
                new Product() { Name = "樹" } ,
                new Product() { Name = "花" } ,
                new Product() { Name = "煙火" } ,
                new Product() { Name = "夜景" }
            };
        }
    }
}
執行結果

[X.Form] ListView

星期四, 8月 24, 2017

[SQL] Trigger 狀態查詢

利用 TSQL 語法來查詢 Trigger 和其狀態
SELECT 
    T.name AS TableName ,
    tr.name AS TriggerName ,
    tr.is_ms_shipped ,
    tr.is_disabled ,
    tr.is_not_for_replication ,
    tr.is_instead_of_trigger
FROM sys.triggers AS tr
    JOIN sys.objects AS O ON tr.[object_id] = O.[object_id]
    JOIN sys.tables AS T ON O.parent_object_id = T.[object_id]
[SQL] Trigger 狀態查詢

星期二, 8月 22, 2017

[X.Form] MVVM - Command - 參數傳遞

[X.Form] MVVM 簡易練習 內 Entry 是 Binding 到 ViewModel 內,Button Command 直接抓 ViewModel Property 來呈現資料,該篇文章 Simplifying Events with Commanding 是 Button Command 直接抓 Entry View 來呈現資料,練習一下

View Model
using System.ComponentModel;
using System.Windows.Input;
using Xamarin.Forms;

namespace MVVMPractice
{
    public class XF42_CommandViewModel : INotifyPropertyChanged
    {
        public ICommand CmdSave { get; set; }

        public string ShowUserInputMessage { get; set; }

        public XF42_CommandViewModel()
        {
            CmdSave = new Command<string>(UserInputMessage);
        }

        private void UserInputMessage(string Value)
        {
            ShowUserInputMessage = $"使用者輸入為 {Value}";
            OnPropertyChanged(nameof(ShowUserInputMessage));
        }

        public event PropertyChangedEventHandler PropertyChanged;

        public void OnPropertyChanged(string PropertyName)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(PropertyName));
        }
    }
}
Xaml
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="MVVMPractice.XF42_Command">
    <ContentPage.Content>
        <StackLayout VerticalOptions="Center">
            <Entry x:Name="entry" Text="Xamarin Command 練習"/>
            <Button Text="顯示使用者輸入"
                Command="{Binding CmdSave}"
                CommandParameter="{Binding Source={x:Reference entry} , Path=Text}">
            </Button>
            <Label Text="{Binding ShowUserInputMessage}" FontSize="Large"></Label>
        </StackLayout>
    </ContentPage.Content>
</ContentPage>

[X.Form] Command - 參數傳遞
  • 練習烏龍事件
因為是在練習,所以就直接從上個練習中把 PropertyChangedEventHandler 和 OnPropertyChanged() Copy 過來使用,實際測試時,發現 ViewModel 內呼叫 OnPropertyChanged(),View 上竟然都不會變化,用中斷點觀察才發現到,原來 PropertyChangedEventHandler 為 null,原因是該 ViewModel 忘記實作 INotifyPropertyChanged Interface,偷懶的下場,Orz

[X.Form] Command - 參數傳遞-2

星期一, 8月 21, 2017

HP 印表機和標楷體

使用者回報,為什麼 HP M501dn 列印標楷體竟然會異常,畫面如下,>.<

HP 印表機和標楷體-標楷體

解決方法有兩種
  1. 更新印表機韌體,請參考:HP LaserJet Pro 400 M401 韌體更新
  2. 修改印表機喜好設定
TrueType 字型:用裝置字型替換改為下載成軟體字型

HP 印表機和標楷體-印表機設定1

以點陣的方式列印 True Type 字型:停用改為啟用

HP 印表機和標楷體-印表機設定2

星期四, 8月 17, 2017

[X.Form] MVVM 簡易練習

根據這教學 Xamrin Forms with Visual Studio Part 13 的練習,內容為使用者在 Entry 內輸入資料後,點選 Buuton 來顯示輸入資料,重點在於

INotifyPropertyChanged
public interface INotifyPropertyChanged
{
    event PropertyChangedEventHandler PropertyChanged;
}
ICommand
public interface ICommand
{
    void Execute(object arg);
    bool CanExecute(object arg)
    event EventHandler CanExecuteChanged; 
} 
Model
namespace MVVMPractice
{
    public class XF4_CommandModel
    {
        public string DemoData { get; set; }
    }
}
ViewModel
// ICommand Interface 在該 namespace
using System.Windows.Input;
// Command 在該 namepspace
using Xamarin.Forms;
// INotifyPropertyChanged 在該 namespace
using System.ComponentModel;

namespace MVVMPractice
{
    public class XF4_CommandViewModel : INotifyPropertyChanged
    {
        private XF4_CommandModel _model = new XF4_CommandModel();

        public string DemoData
        {
            get { return _model.DemoData; }
            set { _model.DemoData = value; }
        }

        public string _result;
        public string Result
        {
            get { return _result; }
            set
            {
                _result = value;
                // 要有 OnPropertyChanged lblResult 才會顯示資料喔
                OnPropertyChanged(nameof(Result));
            }
        }

        public ICommand CmdSave
        {
            get
            {
                return new Command(() =>
                {
                    Result = $"使用者輸入資料為:{_model.DemoData}";
                });
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        public void OnPropertyChanged(string PropertyName)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(PropertyName));
        }
    }
}
Xaml
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:MVVMPractice"
             x:Class="MVVMPractice.XF4_Command">
    <ContentPage.Content>
        <StackLayout VerticalOptions="Center">
            <!--Entry.Mode 預設就是為 TwoWay-->
            <Entry Placeholder="請輸入資料" Text="{Binding DemoData}"/>
            <Button Command="{Binding CmdSave}" Text="顯示輸入資料"/>
            <Label x:Name="lblResult" Text="{Binding Result}" FontSize="Large"/>
        </StackLayout>
    </ContentPage.Content>
</ContentPage>
執行結果

[X.Form] MVVM 簡易練習

星期三, 8月 16, 2017

[git] 衝突解決

看該影片時 Git Fundamentals 發現介紹解決合併這部分有收穫,紀錄衝突解決的內容

該範例在專案中建立 class1.Add() 方法,並在 VS 和 VSTS 內進行修改,讓兩者發生衝突

在 VSTS 上把 int 宣告,改為 var 後進行 commit

[VSTS] 衝突解決-2


[VSTS] 衝突解決-3

星期二, 8月 15, 2017

[SQL] 複合索引效能

接獲同事訊問,為什麼這段 TSQL 短短的,竟然要跑到 8 秒以上,>.<
SELECT
    A.物料識別碼 ,
    ISNULL(k.物料識別碼, '') AS checked
FROM 
    (
        SELECT
            M.物料識別碼 ,
            ISNULL(Q.總庫存量, 0) AS 總庫存量
        FROM 物料資料表 AS M
            JOIN vw庫存數量 AS Q ON M.物料識別碼 = Q.物料識別碼
            JOIN vw物料主管單位 AS P ON M.物料識別碼 = P.物料識別碼
        WHERE M.物料使用狀態 = ''
            AND P.部門單位 = 倉庫單位編號
            AND Q.總庫存量 > 0
    ) AS A
    LEFT JOIN 物料盤點 AS k ON A.物料識別碼 = k.物料識別碼 AND k.年度 = '106' AND k.是否完成 = 1
查看執行計畫和 Logical Read 發現,[物料主管單位 Table] 的資料輸出爆量了

[SQL] 複合索引效能-1
確認 [物料主管單位 Table] 上的 Index,發現 PK 是複合欄位,且竟然設反了,應該是 [物料 + 組別],設成 [組別 + 物料],修正順序後,再執行語法確認,結案

[SQL] 複合索引效能-2
附上該 [物料主管單位 Table] Logical Read 和語法執行時間資訊

修正前修正後
時間8,237ms140ms
Logical Read217,824456

星期一, 8月 14, 2017

[git] push 現有 repo

看該影片時 Git Fundamentals 發現把現有 repo push 到 GitHub 或 VSTS 上還蠻陌生的,筆記一下

在 VSTS 上建立新的 repo,會提供參考語法,方便把現有 repo push 上來,習慣開 repo 時都會一併建立 readme 和 gitignore,似乎都只 focus 在最下面建立 readme 和 gitignore,自動忽略上面的參考語法,Orz

[VSTS] push 現有 repo-2

建立一個有版控的 console 專案,並利用 git remote 語法建立 remote,再利用 git push 把 repo push 到 VSTS

[VSTS] push 現有 repo-3

在 VSTS 上就可以看見

[VSTS] push 現有 repo-4

星期日, 8月 13, 2017

[X.Form] Gorilla Player - 連線問題

閱讀這兩份教學影片和文章
基本上 Gorilla Player 安裝步驟就是
  1. 在 PC 上安裝 Gorilla Player 程式
  2. 在模擬器上安裝 Gorilla Player 程式
  3. 建立 PC 和 模擬器連線
該篇筆記紀錄 PC 和模擬器連線中遇到的問題

[X.Form] Gorilla Player - 連線問題-1
  • 20170810 網路連線
家中的 PC 是 wifi,安裝時沒有注意到模擬器網路沒有通,所以模擬器一直連不到 PC,大金剛的預覽撥放器 內還有提到要在同一個網段內,跨網段是無法連線的喔,
  • 20170811 防火牆
在 Office PC 上安裝時,理論上都會詢問開防火牆提示,不知道是手殘還是怎樣,防火牆 Port 竟然沒有開,手動開啟後,連線才正常

[X.Form] Gorilla Player - 連線問題-2

官方關於連線文章 - Troubleshooting Connectivity,內容有開防火牆語法,可以直接使用
netsh advfirewall firewall add rule name="Gorilla Player" dir=in action=allow protocol=TCP localport=9014
netsh advfirewall firewall add rule name="Gorilla Player" dir=out action=allow protocol=TCP localport=9014

netsh advfirewall firewall add rule name="Gorilla Auto-discovery" dir=in action=allow protocol=UDP localport=14578
netsh advfirewall firewall add rule name="Gorilla Auto-discovery" dir=out action=allow protocol=UDP localport=14578

星期五, 8月 11, 2017

[LINQ] 群組字串連結

用 LINQ 做到該筆記 [SQL] 群組字串連結 的效果,分別用
  • GroupBy + string.Join
  • GroupBy + Aggregate
來做到
namespace ConsolePractice
{
    class Program
    {
        static void Main(string[] args)
        {
            List<LeaveApply> Data = new List<LeaveApply>();
            Data.Add(new LeaveApply() { Date = new DateTime(2017, 8, 8), EmpName = "張三" });
            Data.Add(new LeaveApply() { Date = new DateTime(2017, 8, 8), EmpName = "李四" });
            Data.Add(new LeaveApply() { Date = new DateTime(2017, 8, 8), EmpName = "王五" });
            Data.Add(new LeaveApply() { Date = new DateTime(2017, 8, 9), EmpName = "王五" });
            Data.Add(new LeaveApply() { Date = new DateTime(2017, 8, 10), EmpName = "趙六" });
            Data.Add(new LeaveApply() { Date = new DateTime(2017, 8, 10), EmpName = "蔡七" });

            // 方法一:string.join
            var result = Data
                    .GroupBy(g => g.Date)
                    .Select(g => new
                    {
                        Date = g.Key,
                        Description = string.Join(",", g.Select(s => s.EmpName))
                    });
                        
            // 方法二:Aggregate
            var result = Data
                .GroupBy(g => g.Date)
                .Select(s => new
                {
                    Date = s.Key,
                    Description = s.Aggregate(string.Empty, (c, n) => c + (string.IsNullOrEmpty(c)?string.Empty:",")+ n.EmpName)
                });

            foreach (var i in result)
            {
                Console.WriteLine($"{i.Date.ToString("yyyy/MM/dd")} - {i.Description}");
            }
        }
    }

    public class LeaveApply
    {
        public DateTime Date { get; set; }
        public string EmpName { get; set; }
    }
}
[LINQ] 群組字串連結

星期四, 8月 10, 2017

[Win10] Windows Essentials 2012

公司品管還蠻依賴 Windows Essentials 2012 內的影像中心,在 OS 為 Windows 10 的 1703 版本上要安裝時,出現下面錯誤訊息

[Win10] Windows Essentials 2012-1

拜讀這兩篇文章
發現手邊的是線上安裝檔案,必須是離線安裝版本才能安裝,官方載點都已經失效,有在網路上找到離線安裝檔案並在測試環境上安裝成功

[Win10] Windows Essentials 2012-2

星期三, 8月 09, 2017

[X.Form] Multi Trigger - 皆須輸入

根據這篇官方文章 Triggers 的練習,該篇筆記的延伸 - [X.Form] Multi Trigger - 任一輸入

Multi Trigger 說明
A MultiTrigger looks similar to a Trigger or DataTrigger except there can be more than one condition. All the conditions must be true before the Setters are triggered.
MultiTriggerConverter Class
// IValueConverter 需引用該 namespace
using Xamarin.Forms;

namespace MVVMPractice
{
    public class MultiTriggerConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if ((int)value > 0)
            {
                return true; 
            }
            else
            {
                return false;
            }
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
}
Xaml
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:MVVMPractice"
             x:Class="MVVMPractice.XF3_MultiTrigger2">

    <ContentPage.Resources>
        <ResourceDictionary>
            <local:MultiTriggerConverter x:Key="dataHasBeenEntered"/>
        </ResourceDictionary>
    </ContentPage.Resources>

    <ContentPage.Content>
        <StackLayout HorizontalOptions="Center" VerticalOptions="Center">
            <Entry x:Name="txtUser" Text="" Placeholder="使用者名稱"/>
            <Entry x:Name="txtPWD" Text="" Placeholder="密碼" IsPassword="True"/>
            <Button x:Name="btnLogin" Text="登錄" IsEnabled="False">
                <Button.Triggers>
                    <MultiTrigger TargetType="Button">
                        <MultiTrigger.Conditions>
                            <BindingCondition Binding="{Binding Source={x:Reference txtUser},
                                                                   Path=Text.Length,
                                                                   Converter={StaticResource dataHasBeenEntered}}"
                                                                   Value="true" />
                            <BindingCondition Binding="{Binding Source={x:Reference txtPWD},
                                                                   Path=Text.Length,
                                                                   Converter={StaticResource dataHasBeenEntered}}"
                                                                   Value="true" />
                        </MultiTrigger.Conditions>
                        <Setter Property="IsEnabled" Value="True" />
                    </MultiTrigger>
                </Button.Triggers>
            </Button>
        </StackLayout>
    </ContentPage.Content>
</ContentPage>
執行結果-1

[X.Form] Multi Trigger - 皆須輸入-1

執行結果-2

[X.Form] Multi Trigger - 皆須輸入-3

執行結果-3

[X.Form] Multi Trigger - 皆須輸入-2

星期二, 8月 08, 2017

[X.Form] Multi Trigger - 任一輸入

根據這篇官方文章 Triggers 的練習,該範例和筆記
都很類似,該範例是任一個 Entry 內有輸入,Button 就可以啟用

Xaml
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:MVVMPractice"
             x:Class="MVVMPractice.XF3_MultiTrigger">
 
    <ContentPage.Content>
        <StackLayout HorizontalOptions="Center" VerticalOptions="Center">
            <Entry x:Name="email" Placeholder="請輸入Email" Text="" WidthRequest="150"></Entry>
            <Entry x:Name="phone" Placeholder="請輸入電話" Text="" WidthRequest="150"></Entry>
            <Button Text="OK" IsEnabled="True">
                <Button.Triggers>
                    <MultiTrigger TargetType="Button">
                        <MultiTrigger.Conditions>
                            <BindingCondition Binding="{Binding Source={x:Reference email} , Path=Text.Length}" Value="0"></BindingCondition>
                            <BindingCondition Binding="{Binding Source={x:Reference phone} , Path=Text.Length}" Value="0"></BindingCondition>
                        </MultiTrigger.Conditions>
                        <Setter Property="IsEnabled" Value="False"></Setter>
                    </MultiTrigger>
                </Button.Triggers>
            </Button>
        </StackLayout>
    </ContentPage.Content>
</ContentPage>

執行結果-1

[X.Form] Multi Trigger -1

執行結果-2

[X.Form] Multi Trigger -2

執行結果-3

[X.Form] Multi Trigger -3

星期一, 8月 07, 2017

[X.Form] Event Trigger

根據這篇官方文章 Triggers 的練習

Event Trigger 說明
occurs when an event occurs on the control.
C#

需要建立一個 Class 繼承 TriggerAction<T> 且必須覆寫 invoke
namespace MVVMPractice
{
    public class NumericValidationTriggerAction : TriggerAction<Entry>
    {
        protected override void Invoke(Entry entry)
        {
            bool isValid = Double.TryParse(entry.Text, out double result);
            entry.TextColor = isValid ? Color.Green : Color.Red;
        }
    }
}
Xaml
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:MVVMPractice"
             x:Class="MVVMPractice.XF3_EventTrigger">
    <ContentPage.Content>
        <StackLayout VerticalOptions="Center" HorizontalOptions="Center">
            <Entry Placeholder="請輸入資料">
                <Entry.Triggers>
                   <EventTrigger Event="TextChanged">
                       <local:NumericValidationTriggerAction/>
                   </EventTrigger>
                </Entry.Triggers>
            </Entry>
        </StackLayout>
    </ContentPage.Content>
</ContentPage>
執行結果-1

[X.Form] EventTrigger-1

執行結果-2

[X.Form] EventTrigger-2

星期日, 8月 06, 2017

[X.Form] Data Trigger

根據這篇官方文章 Triggers 的練習,該範例和筆記
[X.Form] IValueConverter - Entry 必填
是相同範例,只是作法不同而已

Data Trigger 說明
uses data binding to trigger based on the properties of another control.
Xaml
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:MVVMPractice"
             x:Class="MVVMPractice.XF3_DataTrigger">
 
    <ContentPage.Content>
        <StackLayout VerticalOptions="Center" HorizontalOptions="Center">
            <Entry x:Name="entry" Text="" Placeholder="required field"></Entry>
            <Button Text="Save" FontSize="Large" HorizontalOptions="Center">
                <Button.Triggers>
                    <DataTrigger
                        TargetType="Button"
                        Binding="{Binding Source={x:Reference entry},Path=Text.Length}"
                        Value="0">
                            <Setter Property="IsEnabled" Value="False"></Setter>
                    </DataTrigger>
                </Button.Triggers>
            </Button>
        </StackLayout>
    </ContentPage.Content>
</ContentPage>
執行結果-1

[X.Form] DataTrigger-1

執行結果-2

[X.Form] DataTrigger-2

星期六, 8月 05, 2017

[X.Form] Property Trigger

根據這篇官方文章 Triggers 的練習,利用 Style 來統一設定 Entry 取的 Focus 後的顏色變化

Property Trigger 說明
occurs when a property on a control is set to a particular value.
Xaml
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="MVVMPractice.XF3_PropertyTrigger">

    <ContentPage.Resources>
        <ResourceDictionary>
            <Style TargetType = "Entry">
                <Style.Triggers>
                    <Trigger 
                        TargetType ="Entry"
                        Property="IsFocused"
                        Value="True">
                            <Setter Property="BackgroundColor" Value="#6699CC"></Setter>
                            <Setter Property="PlaceholderColor" Value="#99CCFF" />
                            <Setter Property="TextColor" Value="#FFFFFF" />
                    </Trigger>
                </Style.Triggers>
            </Style>
        </ResourceDictionary>
    </ContentPage.Resources>

    <ContentPage.Content>
        <StackLayout HorizontalOptions="Center" VerticalOptions="Center">
            <Entry Placeholder="請輸入 Email" WidthRequest="300"></Entry>
            <Entry Placeholder="請輸入密碼" WidthRequest="300" IsPassword="True"></Entry>
        </StackLayout>
    </ContentPage.Content>
</ContentPage>
執行結果-1

[X.Form] Property Trigger-1

執行結果-2

[X.Form] Property Trigger-2

執行結果-3

[X.Form] Property Trigger-3