Xamarin.Forms のドキュメント
行の詳細
コントロール > FlexGrid > 機能 > 行の詳細

FlexGrid コントロールを使用すると、各行に行の詳細セクションを追加することで階層グリッドを作成できます。行の詳細セクションを追加すると、いくつかのデータをグループ化して折りたたみ可能なテンプレートにまとめ、各行にそれらのデータのサマリーだけを表示できます。行の詳細セクションは、行をタップした場合にのみ表示されます。

次の図は、各行に行の詳細セクションを追加した FlexGrid を示します。

次のコード例は、C# および XAML で、行の詳細セクションを FlexGrid コントロールに追加する方法を示します。この例では、新しいデータソースクラス Customer.cs を使用します。

  1. 新しいデータソースクラス「Customer.cs」を作成し、それをポータブルプロジェクトに追加します。
  2. Customer.cs クラスに次のコードを追加します。
    C#
    コードのコピー
     public class Customer :
            INotifyPropertyChanged,
            IEditableObject
        {
            int _id, _countryId, _orderCount;
            string _first, _last;
            string _address, _city, _postalCode, _email;
            bool _active;
            DateTime _lastOrderDate;
            double _orderTotal;
    
            static Random _rnd = new Random();
            static string[] _firstNames = "Andy|Ben|Paul|Herb|Ed|Ted|Zeb".Split('|');
            static string[] _lastNames "Ambers|Danson|Evers|Frommer|Griswold|Orsted|Stevens".Split('|');
            static KeyValuePair<string, string[]>[] _countries = "China-Beijing,Chongqing,Chaohu|India-New Delhi,Mumbai,Delhi,Chennai,Kolkata|United States-Washington,New York,Los Angeles|Indonesia-Jakarta,South Tangerang|Brazil-Brasilia,Sao Paulo,Rio de Janeiro,|Pakistan-Islamabad,Karachi,Lahore,Quetta|Russia-Moscow,Saint Petersburg,Novosibirsk,Rostov-na-Donu|Japan-Tokyo,Yokohama,Ōsaka,Saitama|Mexico-Mexico City,Guadalajara,Monterrey".Split('|').Select(str => new KeyValuePair<string, string[]>(str.Split('-').First(), str.Split('-').Skip(1).First().Split(','))).ToArray();
            static string[] _emailServers = "gmail|yahoo|outlook|aol".Split('|');
            static string[] _streetNames = "Main|Broad|Grand|Panoramic|Green|Golden|Park|Fake".Split('|');
            static string[] _streetTypes = "ST|AVE|BLVD".Split('|');
            static string[] _streetOrientation = "S|N|W|E|SE|SW|NE|NW".Split('|');
    
    
            public Customer()
                : this(_rnd.Next(10000))
            {
            }
    
            public Customer(int id)
            {
                Id = id;
                FirstName = GetRandomString(_firstNames);
                LastName = GetRandomString(_lastNames);
                Address = GetRandomAddress();
                CountryId = _rnd.Next() % _countries.Length;
                var cities = _countries[CountryId].Value;
                City = GetRandomString(cities);
                PostalCode = _rnd.Next(10000, 99999).ToString();
                Email = string.Format({0}@{1}.com, 
                FirstName + LastName.Substring(0, 1)).ToLower(), 
                GetRandomString(_emailServers));
                LastOrderDate = DateTime.Today.AddDays(-_rnd.Next(1, 365)).AddHours(_rnd.Next(0, 24)).AddMinutes(_rnd.Next(0, 60));
                OrderCount = _rnd.Next(0, 100);
                OrderTotal = Math.Round(_rnd.NextDouble() * 10000.00, 2);
                Active = _rnd.NextDouble() >= .5;
            }
    
            public int Id
            {
                get { return _id; }
                set
                {
                    if (value != _id)
                    {
                        _id = value;
                        OnPropertyChanged("Id");
                    }
                }
            }
    
            public string FirstName
            {
                get { return _first; }
                set
                {
                    if (value != _first)
                    {
                        _first = value;
                        OnPropertyChanged("FirstName");
                        OnPropertyChanged("Name");
                    }
                }
            }
    
            public string LastName
            {
                get { return _last; }
                set
                {
                    if (value != _last)
                    {
                        _last = value;
                        OnPropertyChanged("LastName");
                        OnPropertyChanged("Name");
                    }
                }
            }
    
            public string Address
            {
                get { return _address; }
                set
                {
                    if (value != _address)
                    {
                        _address = value;
                        OnPropertyChanged("Address");
                    }
                }
            }
    
            public string City
            {
                get { return _city; }
                set
                {
                    if (value != _city)
                    {
                        _city = value;
                        OnPropertyChanged("City");
                    }
                }
            }
    
            public int CountryId
            {
                get { return _countryId; }
                set
                {
                    if (value != _countryId && value > -1 && value < _countries.Length)
                    {
                        _countryId = value;
                        //_city = _countries[_countryId].Value.First();
                        OnPropertyChanged("CountryId");
                        OnPropertyChanged("Country");
                        OnPropertyChanged("City");
                    }
                }
            }
    
            public string PostalCode
            {
                get { return _postalCode; }
                set
                {
                    if (value != _postalCode)
                    {
                        _postalCode = value;
                        OnPropertyChanged("PostalCode");
                    }
                }
            }
    
            public string Email
            {
                get { return _email; }
                set
                {
                    if (value != _email)
                    {
                        _email = value;
                        OnPropertyChanged("Email");
                    }
                }
            }
    
            public DateTime LastOrderDate
            {
                get { return _lastOrderDate; }
                set
                {
                    if (value != _lastOrderDate)
                    {
                        _lastOrderDate = value;
                        OnPropertyChanged("LastOrderDate");
                    }
                }
            }
    
            public int OrderCount
            {
                get { return _orderCount; }
                set
                {
                    if (value != _orderCount)
                    {
                        _orderCount = value;
                        OnPropertyChanged("OrderCount");
                    }
                }
            }
    
            public double OrderTotal
            {
                get { return _orderTotal; }
                set
                {
                    if (value != _orderTotal)
                    {
                        _orderTotal = value;
                        OnPropertyChanged("OrderTotal");
                    }
                }
            }
    
            public bool Active
            {
                get { return _active; }
                set
                {
                    if (value != _active)
                    {
                        _active = value;
                        OnPropertyChanged("Active");
                    }
                }
            }
    
            public string Name
            {
                get { return string.Format("{0} {1}", FirstName, LastName); }
            }
    
            public string Country
            {
                get { return _countries[_countryId].Key; }
            }
    
            public double OrderAverage
            {
                get { return OrderTotal / (double)OrderCount; }
            }
    
            // ** ユーティリティー
            static string GetRandomString(string[] arr)
            {
                return arr[_rnd.Next(arr.Length)];
            }
            static string GetName()
            {
                return string.Format("{0} {1}", GetRandomString(_firstNames), GetRandomString(_lastNames));
            }
    
            // ** 静的リストプロバイダ
            public static ObservableCollection<Customer> GetCustomerList(int count)
            {
                var list = new ObservableCollection<Customer>();
                for (int i = 0; i < count; i++)
                {
                    list.Add(new Customer(i));
                }
                return list;
            }
    
            private static string GetRandomAddress()
            {
                if (_rnd.NextDouble() > 0.9)
                    return string.Format("{0} {1} {2} {3}", _rnd.Next(1, 999), GetRandomString(_streetNames), GetRandomString(_streetTypes), GetRandomString(_streetOrientation));
                else
                    return string.Format("{0} {1} {2}", _rnd.Next(1, 999), GetRandomString(_streetNames), GetRandomString(_streetTypes));
            }
    
            // ** 静的値プロバイダ
            public static KeyValuePair<int, string>[] GetCountries() { return _countries.Select((p, index) => new KeyValuePair<int, string>(index, p.Key)).ToArray(); }
            public static string[] GetFirstNames() { return _firstNames; }
            public static string[] GetLastNames() { return _lastNames; }
    
            // インターフェースでは、境界コントロールがデータオブジェクトの変更に反応できます
            public event PropertyChangedEventHandler PropertyChanged;
    
            private void OnPropertyChanged(string propertyName)
            {
                OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
            }
    
            protected void OnPropertyChanged(PropertyChangedEventArgs e)
            {
                if (PropertyChanged != null)
                    PropertyChanged(this, e);
            }
    
            // インターフェースは取引された編集を可能にする
    
            Customer _clone;
            public void BeginEdit()
            {
                _clone = (Customer)this.MemberwiseClone();
            }
    
            public void EndEdit()
            {
                _clone = null;
            }
    
            public void CancelEdit()
            {
                if (_clone != null)
                {
                    foreach (var p in this.GetType().GetRuntimeProperties())
                    {
                        if (p.CanRead && p.CanWrite)
                        {
                            p.SetValue(this, p.GetValue(_clone, null), null);
                        }
                    }
                }
            }
    
        }
    
  3. ポータブルプロジェクトに新しい Contenet Page (RowDetails) を追加します。
  4. FlexGrid コントロールを初期化し、行の詳細セクションを追加するには、次のコードに示すように <ContentPage></ContentPage> タグ間のマークアップを編集します。

    XAML のコード

    XAML
    コードのコピー
    <ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
                 xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                 xmlns:c1="clr-namespace:C1.Xamarin.Forms.Grid;assembly=C1.Xamarin.Forms.Grid"
                 x:Class="FlexGridRowDetails.RowDetails" x:Name="page">
      <Grid RowSpacing="0">
        <Grid.RowDefinitions>
          <RowDefinition Height="Auto"/>
          <RowDefinition Height="Auto"/>
          <RowDefinition Height="Auto"/>
          <RowDefinition />
        </Grid.RowDefinitions>
        <c1:FlexGrid x:Name="grid" Grid.Row="3" AutoGenerateColumns="False">
          <c1:FlexGrid.Columns>
            <c1:GridColumn Binding="Id" Width="Auto"/>
            <c1:GridColumn Binding="FirstName" Width="*"/>
            <c1:GridColumn Binding="LastName" Width="*"/>
          </c1:FlexGrid.Columns>
          <c1:FlexGrid.Behaviors>
            <c1:FlexGridDetailProvider x:Name="details" Height="170">
              <DataTemplate>
                <Grid>
                  <Grid.RowDefinitions>
                    <RowDefinition />
                    <RowDefinition />
                    <RowDefinition />
                    <RowDefinition />
                  </Grid.RowDefinitions>
                  <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="Auto" />
                    <ColumnDefinition />
                  </Grid.ColumnDefinitions>
                  <Label Text="Country:"/>
                  <Label Text="{Binding Country}" Grid.Column="1"/>
                  <Label Text="City:" Grid.Row="1"/>
                  <Label Text="{Binding City}" Grid.Row="1" Grid.Column="1"/>
                  <Label Text="Address:" Grid.Row="2"/>
                  <Label Text="{Binding Address}" Grid.Row="2" Grid.Column="1"/>
                  <Label Text="PostalCode:" Grid.Row="3"/>
                  <Label Text="{Binding PostalCode}" Grid.Row="3" Grid.Column="1"/>
                </Grid>
              </DataTemplate>
            </c1:FlexGridDetailProvider>
          </c1:FlexGrid.Behaviors>
        </c1:FlexGrid>
      </Grid>
    </ContentPage>
    
  5. ソリューションエクスプローラーで、RowDetails.xaml ノードを展開し、Merging.xaml.cs を開いて、C# コードビハインドを開きます。
  6. RowDetails クラスのコンストラクタに次のコードを追加して、FlexGrid コントロール内に行の詳細セクションを追加します。

    C# のコード

    C#
    コードのコピー
    public partial class RowDetails : ContentPage
        {
            public RowDetails()
            {
                InitializeComponent();
                var data = Customer.GetCustomerList(1000);
                grid.ItemsSource = data;
            }
        }
    

展開ボタンと折りたたみボタンのカスタマイズ

展開および折りたたみボタンをカスタマイズすることもできます。それには、OnRowHeaderLoading イベントを使用してアイコンをイメージに置き換え、次のコード例に示すように、ExpandButton.CheckedImageSource および UncheckedImageSource プロパティを設定します。

C#
コードのコピー
private void OnRowHeaderLoading(object sender, GridRowHeaderLoadingEventArgs e) 
{ 
    e.ExpandButton.CheckedImageSource = ImageSource.FromResource("collapse.png")); 
    e.ExpandButton.UncheckedImageSource = ImageSource.FromResource("expand.png")); 
}