星期二, 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

星期五, 8月 04, 2017

[X.Form] Button - 計數

就根據這一篇 - Xamarin.Forms.Button Class 來練習,該範例是點擊 Buuton 計數

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="XFViewPractice.XF_Button">
    <ContentPage.Content>
        <StackLayout HorizontalOptions="Center" VerticalOptions="Center">
            <Label Text="Button Demo" FontSize="Large" HorizontalOptions="Center"></Label>
            <Button 
                Text="Click Me!"
                FontSize="Large"
                BorderWidth="1"
                HorizontalOptions="Center"
                VerticalOptions="CenterAndExpand"
                Clicked="Button_Clicked"></Button>
            <Label 
                x:Name="lblResult"
                Text="0 Button clicks" 
                FontSize="Large" 
                HorizontalOptions="Center" 
                VerticalOptions="CenterAndExpand"></Label>
        </StackLayout>
    </ContentPage.Content>
</ContentPage>
C#
namespace XFViewPractice
{
    [XamlCompilation(XamlCompilationOptions.Compile)]
    public partial class XF_Button : ContentPage
    {
        public XF_Button ()
        {
            InitializeComponent ();
            SetResult();
        }

        private int clickTotal = 0;
        private void Button_Clicked(object sender, EventArgs e)
        {
            clickTotal++;
            SetResult();
        }

        private void SetResult()
        {
            string s = clickTotal <= 1 ? "" : "s";
            lblResult.Text = $"{clickTotal} button click{s}";
        }
    }
}
執行結果-1

[X.Form] Button-1

執行結果-2

[X.Form] Button-2

星期四, 8月 03, 2017

[X.Form] IValueConverter - Entry 必填

電子書 Creating Mobile Apps with Xamarin.Forms Book First Edition BindingConverter 章節範例,把 Code 複製下來跑跑看,順道筆記一下

建立 IntToBoolConverter
// 要使用 IValueConverter 要引用該 namespace
using Xamarin.Forms;

namespace DataBindingPractice
{
    public class IntToBoolConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return (int)value != 0;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return (bool)value ? 1 : 0;
        }
    }  
}
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:DataBindingPractice"
                x:Class="DataBindingPractice.XF9_IValueConvert3">

    <ContentPage.Resources>
        <ResourceDictionary>
            <local:IntToBoolConverter x:Key="intToBool" />
        </ResourceDictionary>
    </ContentPage.Resources>

    <ContentPage.Content>
        <StackLayout Spacing="20" HorizontalOptions="Center" VerticalOptions="Center">
            <Entry 
                x:Name="entry" 
                FontSize="Large"
                Text=""
                Placeholder="text to enable button" />

            <Button 
                Text="Save or Send (or something)"
                FontSize="Large" 
                HorizontalOptions="Center" 
                IsEnabled="{Binding Source={x:Reference entry}, 
                Path=Text.Length, 
                Converter={StaticResource intToBool}}" />
        </StackLayout>
    </ContentPage.Content>
</ContentPage>
執行結果-1

[X.Form] IValueConverter - Entry 必填-1

執行結果-2

[X.Form] IValueConverter - Entry 必填-2

星期三, 8月 02, 2017

[X.Form] IValueConverter - Switch 轉換

電子書 Creating Mobile Apps with Xamarin.Forms Book First Edition BindingConverter 章節範例,把 Code 複製下來跑跑看,順道筆記一下

建立 BoolToStringConverter 和 BoolToColorConverter
// 要使用 IValueConverter 要引用該 namespace
using Xamarin.Forms;

namespace DataBindingPractice
{
    public class BoolToStringConverter : IValueConverter
    {
        public string TrueText { set; get; }

        public string FalseText { set; get; }

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return (bool)value ? TrueText : FalseText;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return false;
        }
    }

    public class BoolToColorConverter : IValueConverter
    {
        public Color TrueColor { set; get; }

        public Color FalseColor { set; get; }

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return (bool)value ? TrueColor : FalseColor;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return false;
        }
    }
}
Xaml

重點:Switch1 和 Switch2 把 Converter 寫在 ResourceDictionary 內來達到共用目的,Switch3 則是單獨使用,不需要共用
<?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:DataBindingPractice"
             x:Class="DataBindingPractice.XF8_IValueConvert2">

    <ContentPage.Resources>
        <ResourceDictionary>
            <local:BoolToStringConverter 
                x:Key="boolToString" 
                TrueText="Let's od it"
                FalseText="Not Not">
            </local:BoolToStringConverter>
            <Style TargetType="Label">
                <Setter Property="FontSize" Value="Large" />
                <Setter Property="VerticalOptions" Value="Center" />
            </Style>
        </ResourceDictionary>
    </ContentPage.Resources>

    <ContentPage.Content>
        <StackLayout>
            <!-- First Switch with text. -->
            <StackLayout Orientation="Horizontal" VerticalOptions="CenterAndExpand" HorizontalOptions="Center">
                <Label Text="Learn more?"/>
                <Switch x:Name="switch1" VerticalOptions="Center" />
                <Label 
                    Text="{Binding Source={x:Reference switch1}, 
                    Path=IsToggled, 
                    Converter={StaticResource boolToString}}" 
                    HorizontalOptions="FillAndExpand" />
            </StackLayout>

            <!-- Second Switch with text. -->
            <StackLayout Orientation="Horizontal" VerticalOptions="CenterAndExpand" HorizontalOptions="Center">
                <Label Text="Subscribe?" />
                <Switch x:Name="switch2" VerticalOptions="Center" />
                <Label 
                    Text="{Binding Source={x:Reference switch2}, 
                    Path=IsToggled, 
                    Converter={StaticResource boolToString}}" 
                    HorizontalOptions="FillAndExpand" />
            </StackLayout>

            <!-- Third Switch with text and color. -->
            <StackLayout Orientation="Horizontal" VerticalOptions="CenterAndExpand" HorizontalOptions="Center">
                <Label Text="Leave page?" />
                <Switch x:Name="switch3" VerticalOptions="Center" />
                <Label HorizontalOptions="FillAndExpand">
                    <Label.Text>
                        <Binding Source="{x:Reference switch3}" Path="IsToggled">
                            <Binding.Converter>
                                <local:BoolToStringConverter TrueText="Yes" FalseText="No" />
                            </Binding.Converter>
                        </Binding>
                    </Label.Text>
                    <Label.TextColor>
                        <Binding Source="{x:Reference switch3}" Path="IsToggled">
                            <Binding.Converter>
                                <local:BoolToColorConverter TrueColor="Green" FalseColor="Red" />
                            </Binding.Converter>
                        </Binding>
                    </Label.TextColor>
                </Label>
            </StackLayout>
        </StackLayout>
    </ContentPage.Content>
</ContentPage>

執行結果1

[X.Form] IValueConverter - Switch 轉換-2

執行結果2

[X.Form] IValueConverter - Switch 轉換-1

星期二, 8月 01, 2017

[X.Form] Switch

根據這篇 Xamarin.Forms.Switch Class 的練習

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="XFViewPractice.XF_Switch">
    <ContentPage.Content>
        <StackLayout HorizontalOptions="Center" VerticalOptions="Center">
            <Label Text="Switch Demo" FontSize="Large" HorizontalOptions="Center"/>
            <Switch 
                HorizontalOptions="Center"
                x:Name="Switch1"
                WidthRequest="100"
                IsToggled="True"
                Toggled="Switch_Toggled"></Switch>
            <Label 
                HorizontalOptions="Center"
                x:Name="lblResult"
                Text="Switch 狀態" 
                FontSize="Large"></Label>
            </StackLayout>
    </ContentPage.Content>
</ContentPage>
C#
namespace XFViewPractice
{
    [XamlCompilation(XamlCompilationOptions.Compile)]
    public partial class XF_Switch : ContentPage
    {
        public XF_Switch()
        {
            InitializeComponent();

            SetToggled(Switch1.IsToggled);
        }

        private void Switch_Toggled(object sender, ToggledEventArgs e)
        {
            SetToggled(e.Value);
        }

        private void SetToggled(bool result)
        {
            lblResult.Text = $"Switch 狀態是 {result}";
        }
    }
}
執行結果

[X.Form] Switch-1

[X.Form] Switch-2