2010-04-15 106 views
18

在我看來,我喜歡這在我的視圖模型綁定到的CollectionView一個ListView,例如:WPF MVVM:如何GridViewColumn綁定到視圖模型收集?

<ListView ItemsSource="{Binding MyCollection}" IsSynchronizedWithCurrentItem="true"> 
    <ListView.View> 
    <GridView> 
     <GridViewColumn Header="Title" DisplayMemberBinding="{Binding Path=Title}"/> 
     <GridViewColumn Header="Name" DisplayMemberBinding="{Binding Path=Name}"/> 
     <GridViewColumn Header="Phone" DisplayMemberBinding="{Binding Path=Phone}"/> 
     <GridViewColumn Header="E-mail" DisplayMemberBinding="{Binding Path=EMail}"/> 
    </GridView> 
    </ListView.View> 
</ListView> 

眼下這些GridViewColumns是固定的,但我希望能夠將它們從視圖模型改變。我想我不得不將GridViewColumn集合綁定到ViewModel中的某些東西,但是什麼以及如何?
的視圖模型不知道什麼WPF的,所以我不知道如何在MVVM實現這一目標。

這裏有什麼幫助嗎?

回答

34

Columns屬性不是依賴財產,因此不能將其綁定。但是,可能會創建一個可以綁定到ViewModel中的集合的附加屬性。這個附加屬性會爲你創建列。


UPDATE

OK,這裏有一個基本的實現...

附加屬性

using System.Collections.Generic; 
using System.Collections.Specialized; 
using System.ComponentModel; 
using System.Reflection; 
using System.Windows; 
using System.Windows.Controls; 
using System.Windows.Data; 

namespace TestPadWPF 
{ 
    public static class GridViewColumns 
    { 
     [AttachedPropertyBrowsableForType(typeof(GridView))] 
     public static object GetColumnsSource(DependencyObject obj) 
     { 
      return (object)obj.GetValue(ColumnsSourceProperty); 
     } 

     public static void SetColumnsSource(DependencyObject obj, object value) 
     { 
      obj.SetValue(ColumnsSourceProperty, value); 
     } 

     // Using a DependencyProperty as the backing store for ColumnsSource. This enables animation, styling, binding, etc... 
     public static readonly DependencyProperty ColumnsSourceProperty = 
      DependencyProperty.RegisterAttached(
       "ColumnsSource", 
       typeof(object), 
       typeof(GridViewColumns), 
       new UIPropertyMetadata(
        null, 
        ColumnsSourceChanged)); 


     [AttachedPropertyBrowsableForType(typeof(GridView))] 
     public static string GetHeaderTextMember(DependencyObject obj) 
     { 
      return (string)obj.GetValue(HeaderTextMemberProperty); 
     } 

     public static void SetHeaderTextMember(DependencyObject obj, string value) 
     { 
      obj.SetValue(HeaderTextMemberProperty, value); 
     } 

     // Using a DependencyProperty as the backing store for HeaderTextMember. This enables animation, styling, binding, etc... 
     public static readonly DependencyProperty HeaderTextMemberProperty = 
      DependencyProperty.RegisterAttached("HeaderTextMember", typeof(string), typeof(GridViewColumns), new UIPropertyMetadata(null)); 


     [AttachedPropertyBrowsableForType(typeof(GridView))] 
     public static string GetDisplayMemberMember(DependencyObject obj) 
     { 
      return (string)obj.GetValue(DisplayMemberMemberProperty); 
     } 

     public static void SetDisplayMemberMember(DependencyObject obj, string value) 
     { 
      obj.SetValue(DisplayMemberMemberProperty, value); 
     } 

     // Using a DependencyProperty as the backing store for DisplayMember. This enables animation, styling, binding, etc... 
     public static readonly DependencyProperty DisplayMemberMemberProperty = 
      DependencyProperty.RegisterAttached("DisplayMemberMember", typeof(string), typeof(GridViewColumns), new UIPropertyMetadata(null)); 


     private static void ColumnsSourceChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e) 
     { 
      GridView gridView = obj as GridView; 
      if (gridView != null) 
      { 
       gridView.Columns.Clear(); 

       if (e.OldValue != null) 
       { 
        ICollectionView view = CollectionViewSource.GetDefaultView(e.OldValue); 
        if (view != null) 
         RemoveHandlers(gridView, view); 
       } 

       if (e.NewValue != null) 
       { 
        ICollectionView view = CollectionViewSource.GetDefaultView(e.NewValue); 
        if (view != null) 
        { 
         AddHandlers(gridView, view); 
         CreateColumns(gridView, view); 
        } 
       } 
      } 
     } 

     private static IDictionary<ICollectionView, List<GridView>> _gridViewsByColumnsSource = 
      new Dictionary<ICollectionView, List<GridView>>(); 

     private static List<GridView> GetGridViewsForColumnSource(ICollectionView columnSource) 
     { 
      List<GridView> gridViews; 
      if (!_gridViewsByColumnsSource.TryGetValue(columnSource, out gridViews)) 
      { 
       gridViews = new List<GridView>(); 
       _gridViewsByColumnsSource.Add(columnSource, gridViews); 
      } 
      return gridViews; 
     } 

     private static void AddHandlers(GridView gridView, ICollectionView view) 
     { 
      GetGridViewsForColumnSource(view).Add(gridView); 
      view.CollectionChanged += ColumnsSource_CollectionChanged; 
     } 

     private static void CreateColumns(GridView gridView, ICollectionView view) 
     { 
      foreach (var item in view) 
      { 
       GridViewColumn column = CreateColumn(gridView, item); 
       gridView.Columns.Add(column); 
      } 
     } 

     private static void RemoveHandlers(GridView gridView, ICollectionView view) 
     { 
      view.CollectionChanged -= ColumnsSource_CollectionChanged; 
      GetGridViewsForColumnSource(view).Remove(gridView); 
     } 

     private static void ColumnsSource_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) 
     { 
      ICollectionView view = sender as ICollectionView; 
      var gridViews = GetGridViewsForColumnSource(view); 
      if (gridViews == null || gridViews.Count == 0) 
       return; 

      switch (e.Action) 
      { 
       case NotifyCollectionChangedAction.Add: 
        foreach (var gridView in gridViews) 
        { 
         for (int i = 0; i < e.NewItems.Count; i++) 
         { 
          GridViewColumn column = CreateColumn(gridView, e.NewItems[i]); 
          gridView.Columns.Insert(e.NewStartingIndex + i, column); 
         } 
        } 
        break; 
       case NotifyCollectionChangedAction.Move: 
        foreach (var gridView in gridViews) 
        { 
         List<GridViewColumn> columns = new List<GridViewColumn>(); 
         for (int i = 0; i < e.OldItems.Count; i++) 
         { 
          GridViewColumn column = gridView.Columns[e.OldStartingIndex + i]; 
          columns.Add(column); 
         } 
         for (int i = 0; i < e.NewItems.Count; i++) 
         { 
          GridViewColumn column = columns[i]; 
          gridView.Columns.Insert(e.NewStartingIndex + i, column); 
         } 
        } 
        break; 
       case NotifyCollectionChangedAction.Remove: 
        foreach (var gridView in gridViews) 
        { 
         for (int i = 0; i < e.OldItems.Count; i++) 
         { 
          gridView.Columns.RemoveAt(e.OldStartingIndex); 
         } 
        } 
        break; 
       case NotifyCollectionChangedAction.Replace: 
        foreach (var gridView in gridViews) 
        { 
         for (int i = 0; i < e.NewItems.Count; i++) 
         { 
          GridViewColumn column = CreateColumn(gridView, e.NewItems[i]); 
          gridView.Columns[e.NewStartingIndex + i] = column; 
         } 
        } 
        break; 
       case NotifyCollectionChangedAction.Reset: 
        foreach (var gridView in gridViews) 
        { 
         gridView.Columns.Clear(); 
         CreateColumns(gridView, sender as ICollectionView); 
        } 
        break; 
       default: 
        break; 
      } 
     } 

     private static GridViewColumn CreateColumn(GridView gridView, object columnSource) 
     { 
      GridViewColumn column = new GridViewColumn(); 
      string headerTextMember = GetHeaderTextMember(gridView); 
      string displayMemberMember = GetDisplayMemberMember(gridView); 
      if (!string.IsNullOrEmpty(headerTextMember)) 
      { 
       column.Header = GetPropertyValue(columnSource, headerTextMember); 
      } 
      if (!string.IsNullOrEmpty(displayMemberMember)) 
      { 
       string propertyName = GetPropertyValue(columnSource, displayMemberMember) as string; 
       column.DisplayMemberBinding = new Binding(propertyName); 
      } 
      return column; 
     } 

     private static object GetPropertyValue(object obj, string propertyName) 
     { 
      if (obj != null) 
      { 
       PropertyInfo prop = obj.GetType().GetProperty(propertyName); 
       if (prop != null) 
        return prop.GetValue(obj, null); 
      } 
      return null; 
     } 
    } 
} 

視圖模型

class PersonsViewModel 
{ 
    public PersonsViewModel() 
    { 
     this.Persons = new ObservableCollection<Person> 
     { 
      new Person 
      { 
       Name = "Doe", 
       FirstName = "John", 
       DateOfBirth = new DateTime(1981, 9, 12) 
      }, 
      new Person 
      { 
       Name = "Black", 
       FirstName = "Jack", 
       DateOfBirth = new DateTime(1950, 1, 15) 
      }, 
      new Person 
      { 
       Name = "Smith", 
       FirstName = "Jane", 
       DateOfBirth = new DateTime(1987, 7, 23) 
      } 
     }; 

     this.Columns = new ObservableCollection<ColumnDescriptor> 
     { 
      new ColumnDescriptor { HeaderText = "Last name", DisplayMember = "Name" }, 
      new ColumnDescriptor { HeaderText = "First name", DisplayMember = "FirstName" }, 
      new ColumnDescriptor { HeaderText = "Date of birth", DisplayMember = "DateOfBirth" } 
     }; 
    } 

    public ObservableCollection<Person> Persons { get; private set; } 

    public ObservableCollection<ColumnDescriptor> Columns { get; private set; } 

    private ICommand _addColumnCommand; 
    public ICommand AddColumnCommand 
    { 
     get 
     { 
      if (_addColumnCommand == null) 
      { 
       _addColumnCommand = new DelegateCommand<string>(
        s => 
        { 
         this.Columns.Add(new ColumnDescriptor { HeaderText = s, DisplayMember = s }); 
        }); 
      } 
      return _addColumnCommand; 
     } 
    } 

    private ICommand _removeColumnCommand; 
    public ICommand RemoveColumnCommand 
    { 
     get 
     { 
      if (_removeColumnCommand == null) 
      { 
       _removeColumnCommand = new DelegateCommand<string>(
        s => 
        { 
         this.Columns.Remove(this.Columns.FirstOrDefault(d => d.DisplayMember == s)); 
        }); 
      } 
      return _removeColumnCommand; 
     } 
    } 
} 

XAML:

<ListView ItemsSource="{Binding Persons}" Grid.Row="0"> 
     <ListView.View> 
      <GridView local:GridViewColumns.HeaderTextMember="HeaderText" 
         local:GridViewColumns.DisplayMemberMember="DisplayMember" 
         local:GridViewColumns.ColumnsSource="{Binding Columns}"/> 
     </ListView.View> 
    </ListView> 

注意,ColumnDescriptor類實際上不需要,我只加它的清晰度,但任何類型的會做(包括匿名類型)。您只需指定哪些屬性包含標題文本和顯示成員名稱。

另外,請記住,它不是完全測試過,所以可能有一些問題解決...

+1

嗯,我不真的很確定我明白如何實現你的建議。 – Sam 2010-04-15 10:20:11

+0

查看我更新的答案 – 2010-04-15 13:11:54

+0

哇,太好了,謝謝!我正在檢查它,你沒有添加ColumnDescriptor的聲明,但正如你所說,它應該很容易創建。 只要我理解它,我會盡快通知;) – Sam 2010-04-16 13:56:17

1

我覺得這個代碼將導致一些內存泄漏問題;當你的類GridViewColumns描述,您已經定義了一個靜態辭典「_gridViewsByColumnsSource」,其中包含了GridView的及其列源引用;所以這是對增加的gridviews和列源的強烈參考;因爲這本字典是靜態的,似乎有一個靜態引用「指向」所有的時間,如果在GridView的定義屏幕關閉時,GridView不能被GC如果GC開始收集的GridView的和列的源數據;隨着越來越多類似的屏幕打開,越來越多的網格視圖和它的列源數據不能被收集,最終會有內存泄漏。

+0

我用內存分析器證實了這個問題。你可以通過設置ColumnsSource爲null來解決這個問題,當你的控件被拋棄時,這應該會導致引用被移除(在RemoveHandlers方法中),或者改變_gridViewsByColumnsSource來保存一個WeakReference對象列表併爲ICollectionView實現一個弱事件監聽器。 CollectionChanged事件。 – Snooganz 2012-02-09 16:29:38

+0

其實你不需要一個弱事件監聽器......只是一個WeakReference到GridView。 – Snooganz 2012-02-09 22:30:21

5

我把托馬斯·萊維斯克的優秀的解決方案和修改它刪除GridView的的靜態集合,並添加設置列寬和字符串格式的能力,所以想我會分享我的代碼。

修改附加屬性類:

public static class GridViewColumnCollection 
{ 
    public static readonly DependencyProperty ColumnCollectionBehaviourProperty = 
     DependencyProperty.RegisterAttached("ColumnCollectionBehaviour", typeof(GridViewColumnCollectionBehaviour), typeof(GridViewColumnCollection), new UIPropertyMetadata(null)); 

    public static readonly DependencyProperty ColumnsSourceProperty = 
     DependencyProperty.RegisterAttached("ColumnsSource", typeof(object), typeof(GridViewColumnCollection), new UIPropertyMetadata(null, GridViewColumnCollection.ColumnsSourceChanged)); 

    public static readonly DependencyProperty DisplayMemberFormatMemberProperty = 
     DependencyProperty.RegisterAttached("DisplayMemberFormatMember", typeof(string), typeof(GridViewColumnCollection), new UIPropertyMetadata(null, GridViewColumnCollection.DisplayMemberFormatMemberChanged)); 

    public static readonly DependencyProperty DisplayMemberMemberProperty = 
     DependencyProperty.RegisterAttached("DisplayMemberMember", typeof(string), typeof(GridViewColumnCollection), new UIPropertyMetadata(null, GridViewColumnCollection.DisplayMemberMemberChanged)); 

    public static readonly DependencyProperty HeaderTextMemberProperty = 
     DependencyProperty.RegisterAttached("HeaderTextMember", typeof(string), typeof(GridViewColumnCollection), new UIPropertyMetadata(null, GridViewColumnCollection.HeaderTextMemberChanged)); 

    public static readonly DependencyProperty WidthMemberProperty = 
     DependencyProperty.RegisterAttached("WidthMember", typeof(string), typeof(GridViewColumnCollection), new UIPropertyMetadata(null, GridViewColumnCollection.WidthMemberChanged)); 

    [AttachedPropertyBrowsableForType(typeof(GridView))] 
    public static GridViewColumnCollectionBehaviour GetColumnCollectionBehaviour(DependencyObject obj) 
    { 
     return (GridViewColumnCollectionBehaviour)obj.GetValue(ColumnCollectionBehaviourProperty); 
    } 

    public static void SetColumnCollectionBehaviour(DependencyObject obj, GridViewColumnCollectionBehaviour value) 
    { 
     obj.SetValue(ColumnCollectionBehaviourProperty, value); 
    } 

    [AttachedPropertyBrowsableForType(typeof(GridView))] 
    public static object GetColumnsSource(DependencyObject obj) 
    { 
     return (object)obj.GetValue(ColumnsSourceProperty); 
    } 

    public static void SetColumnsSource(DependencyObject obj, object value) 
    { 
     obj.SetValue(ColumnsSourceProperty, value); 
    } 

    [AttachedPropertyBrowsableForType(typeof(GridView))] 
    public static string GetDisplayMemberFormatMember(DependencyObject obj) 
    { 
     return (string)obj.GetValue(DisplayMemberFormatMemberProperty); 
    } 

    public static void SetDisplayMemberFormatMember(DependencyObject obj, string value) 
    { 
     obj.SetValue(DisplayMemberFormatMemberProperty, value); 
    } 

    [AttachedPropertyBrowsableForType(typeof(GridView))] 
    public static string GetDisplayMemberMember(DependencyObject obj) 
    { 
     return (string)obj.GetValue(DisplayMemberMemberProperty); 
    } 

    public static void SetDisplayMemberMember(DependencyObject obj, string value) 
    { 
     obj.SetValue(DisplayMemberMemberProperty, value); 
    } 

    [AttachedPropertyBrowsableForType(typeof(GridView))] 
    public static string GetHeaderTextMember(DependencyObject obj) 
    { 
     return (string)obj.GetValue(HeaderTextMemberProperty); 
    } 

    public static void SetHeaderTextMember(DependencyObject obj, string value) 
    { 
     obj.SetValue(HeaderTextMemberProperty, value); 
    } 

    [AttachedPropertyBrowsableForType(typeof(GridView))] 
    public static string GetWidthMember(DependencyObject obj) 
    { 
     return (string)obj.GetValue(WidthMemberProperty); 
    } 

    public static void SetWidthMember(DependencyObject obj, string value) 
    { 
     obj.SetValue(WidthMemberProperty, value); 
    } 

    private static void ColumnsSourceChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) 
    { 
     GridViewColumnCollection.GetOrCreateColumnCollectionBehaviour(sender).ColumnsSource = e.NewValue; 
    } 

    private static void DisplayMemberFormatMemberChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) 
    { 
     GridViewColumnCollection.GetOrCreateColumnCollectionBehaviour(sender).DisplayMemberFormatMember = e.NewValue as string; 
    } 

    private static void DisplayMemberMemberChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) 
    { 
     GridViewColumnCollection.GetOrCreateColumnCollectionBehaviour(sender).DisplayMemberMember = e.NewValue as string; 
    } 

    private static void HeaderTextMemberChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) 
    { 
     GridViewColumnCollection.GetOrCreateColumnCollectionBehaviour(sender).HeaderTextMember = e.NewValue as string; 
    } 

    private static void WidthMemberChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) 
    { 
     GridViewColumnCollection.GetOrCreateColumnCollectionBehaviour(sender).WidthMember = e.NewValue as string; 
    } 

    private static GridViewColumnCollectionBehaviour GetOrCreateColumnCollectionBehaviour(DependencyObject source) 
    { 
     GridViewColumnCollectionBehaviour behaviour = GetColumnCollectionBehaviour(source); 

     if (behaviour == null) 
     { 
      GridView typedSource = source as GridView; 

      if (typedSource == null) 
      { 
       throw new Exception("This property can only be set on controls deriving GridView"); 
      } 

      behaviour = new GridViewColumnCollectionBehaviour(typedSource); 

      SetColumnCollectionBehaviour(typedSource, behaviour); 
     } 

     return behaviour; 
    } 
} 

行爲(這是針對存儲每個GridView和消除了需要存儲的集合,GridView的映射集中):

public class GridViewColumnCollectionBehaviour 
{ 
    private object columnsSource; 
    private GridView gridView; 

    public GridViewColumnCollectionBehaviour(GridView gridView) 
    { 
     this.gridView = gridView; 
    } 

    public object ColumnsSource 
    { 
     get { return this.columnsSource; } 
     set 
     { 
      object oldValue = this.columnsSource; 
      this.columnsSource = value; 
      this.ColumnsSourceChanged(oldValue, this.columnsSource); 
     } 
    } 

    public string DisplayMemberFormatMember { get; set; } 

    public string DisplayMemberMember { get; set; } 

    public string HeaderTextMember { get; set; } 

    public string WidthMember { get; set; } 

    private void AddHandlers(ICollectionView collectionView) 
    { 
     collectionView.CollectionChanged += this.ColumnsSource_CollectionChanged; 
    } 

    private void ColumnsSource_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) 
    { 
     ICollectionView view = sender as ICollectionView; 

     if (this.gridView == null) 
     { 
      return; 
     } 

     switch (e.Action) 
     { 
      case NotifyCollectionChangedAction.Add: 
       for (int i = 0; i < e.NewItems.Count; i++) 
       { 
        GridViewColumn column = CreateColumn(e.NewItems[i]); 
        gridView.Columns.Insert(e.NewStartingIndex + i, column); 
       } 
       break; 
      case NotifyCollectionChangedAction.Move: 
       List<GridViewColumn> columns = new List<GridViewColumn>(); 

       for (int i = 0; i < e.OldItems.Count; i++) 
       { 
        GridViewColumn column = gridView.Columns[e.OldStartingIndex + i]; 
        columns.Add(column); 
       } 

       for (int i = 0; i < e.NewItems.Count; i++) 
       { 
        GridViewColumn column = columns[i]; 
        gridView.Columns.Insert(e.NewStartingIndex + i, column); 
       } 
       break; 
      case NotifyCollectionChangedAction.Remove: 
       for (int i = 0; i < e.OldItems.Count; i++) 
       { 
        gridView.Columns.RemoveAt(e.OldStartingIndex); 
       } 
       break; 
      case NotifyCollectionChangedAction.Replace: 
       for (int i = 0; i < e.NewItems.Count; i++) 
       { 
        GridViewColumn column = CreateColumn(e.NewItems[i]); 

        gridView.Columns[e.NewStartingIndex + i] = column; 
       } 
       break; 
      case NotifyCollectionChangedAction.Reset: 
       gridView.Columns.Clear(); 
       CreateColumns(sender as ICollectionView); 
       break; 
      default: 
       break; 
     } 
    } 

    private void ColumnsSourceChanged(object oldValue, object newValue) 
    { 
     if (this.gridView != null) 
     { 
      gridView.Columns.Clear(); 

      if (oldValue != null) 
      { 
       ICollectionView view = CollectionViewSource.GetDefaultView(oldValue); 

       if (view != null) 
       { 
        this.RemoveHandlers(view); 
       } 
      } 

      if (newValue != null) 
      { 
       ICollectionView view = CollectionViewSource.GetDefaultView(newValue); 

       if (view != null) 
       { 
        this.AddHandlers(view); 

        this.CreateColumns(view); 
       } 
      } 
     } 
    } 

    private GridViewColumn CreateColumn(object columnSource) 
    { 
     GridViewColumn column = new GridViewColumn(); 

     if (!string.IsNullOrEmpty(this.HeaderTextMember)) 
     { 
      column.Header = GetPropertyValue(columnSource, this.HeaderTextMember); 
     } 

     if (!string.IsNullOrEmpty(this.DisplayMemberMember)) 
     { 
      string propertyName = GetPropertyValue(columnSource, this.DisplayMemberMember) as string; 

      string format = null; 

      if (!string.IsNullOrEmpty(this.DisplayMemberFormatMember)) 
      { 
       format = GetPropertyValue(columnSource, this.DisplayMemberFormatMember) as string; 
      } 

      if (string.IsNullOrEmpty(format)) 
      { 
       format = "{0}"; 
      } 

      column.DisplayMemberBinding = new Binding(propertyName) { StringFormat = format }; 
     } 

     if (!string.IsNullOrEmpty(this.WidthMember)) 
     { 
      double width = (double)GetPropertyValue(columnSource, this.WidthMember); 
      column.Width = width; 
     } 

     return column; 
    } 

    private void CreateColumns(ICollectionView collectionView) 
    { 
     foreach (object item in collectionView) 
     { 
      GridViewColumn column = this.CreateColumn(item); 

      this.gridView.Columns.Add(column); 
     } 
    } 

    private object GetPropertyValue(object obj, string propertyName) 
    { 
     object returnVal = null; 

     if (obj != null) 
     { 
      PropertyInfo prop = obj.GetType().GetProperty(propertyName); 

      if (prop != null) 
      { 
       returnVal = prop.GetValue(obj, null); 
      } 
     } 

     return returnVal; 
    } 

    private void RemoveHandlers(ICollectionView collectionView) 
    { 
     collectionView.CollectionChanged -= this.ColumnsSource_CollectionChanged; 
    } 
} 
+0

細胞模板呢? – AgentFire 2015-09-01 14:21:31

+0

如果要在創建的GridViewColumns上設置其他屬性,請修改附加的行爲類以包含新屬性,並相應地修改行爲類(特別是CreateColumn)。要開始,請嘗試查看附加行爲類(例如WidthMember)上的屬性值發生變化時發生的情況,然後從中繼續。 – 2015-09-02 15:10:15