2011-10-11 63 views
2

我想知道是否有人知道如何僅顯示ItemsControl中的綁定集合中的幾個項目。無論是通過過濾ICollectionView還是其他方式。我確信我可以自己想出一個冗長的解決方案,但我想看看那裏已經有了什麼。如何在ItemsControl中只顯示一個集合的幾個項目 - Silverlight

基本上,我有一個ItemsControl綁定到模型中包含的對象的集合。我想要做的只是顯示其中一些項目,然後有一個「查看更多」的超鏈接/按鈕。這將顯示整個項目的集合。我一直希望能夠使用VSM發出'摺疊'和'擴展'狀態的信號,但是我在如何初始化列表時遇到了問題。由於綁定是在XAML中創建的,因此我試圖避免在代碼隱藏中使用Linq手動修改ItemsSource集合,如果其他所有集合都失敗,這可能是一個解決方案。

如果需要,我可以顯示一些代碼,但我認爲這不會比我的解釋更有幫助。再次,我只是希望有人在那裏做了類似的事情,然後我嘗試了太多,最終打破了我的viewmodel哈哈。

在此先感謝。

[更新] - 這是我經過頭腦風暴(對於其他人希望做同樣的事情)後想出的解決方案。感謝AnthonyWJones的想法。

我所做的是將一個通用「模型」放在一起,充當模型的源集合和「視圖」集合之間的橋樑。預期目的(對我而言)是擴展由WCF RIA服務生成的任何模型類,在使用相同的UI(控件和模板)時可能有與其相關的註釋,因此期望的集合是一個EntityCollection,其中T是「

// this is so we can reference our model without generic arguments 
public interface ICommentModel : INotifyPropertyChanged 
{ 
    Int32 TotalComments { get; } 
    Int32 VisibleComments { get; } 

    Boolean IsExpanded { get; set; } 
    Boolean IsExpandable { get; } 

    ICommand ExpandCommand { get; } 

    IEnumerable Collection { get; } 
} 

// the command we'll use to expand our collection 
public class ExpandCommand : ICommand 
{ 
    ICommentModel model; 

    public ExpandCommand(ICommentModel model) { 
     this.model = model; 
     this.model.PropertyChanged += ModelPropertyChanged; 
    } 

    public bool CanExecute(object parameter) { 
     return this.model.IsExpandable; 
    } 

    public void Execute(object parameter) { 
     this.model.IsExpanded = !this.model.IsExpanded; 
    } 

    private void ModelPropertyChanged(object sender, PropertyChangedEventArgs e) { 
     if (e.PropertyName == "IsExpandable") 
      RaiseCanExecuteChanged(); 
    } 

    private void RaiseCanExecuteChanged() { 
     var execute = CanExecuteChanged; 
     if (execute != null) execute(this, EventArgs.Empty); 
    } 

    public event EventHandler CanExecuteChanged; 
} 

// and finally.. the big guns 
public class CommentModel<TEntity> : ICommentModel 
    where TEntity : Entity 
{ 
    Boolean isExpanded; 

    ICommand expandCommand; 

    IEnumerable<TEntity> source; 
    IEnumerable<TEntity> originalSource; 


    public Int32 TotalComments { get { return originalSource.Count(); } } 

    public Int32 VisibleComments { get { return source.Count(); } } 

    public Boolean IsExpanded { 
     get { return isExpanded; } 
     set { isExpanded = value; OnIsExpandedChanged(); } 
    } 

    public Boolean IsExpandable { 
     get { return (!IsExpanded && originalSource.Count() > 2); } 
    } 

    public ICommand ExpandCommand { 
     get { return expandCommand; } 
    } 

    public IEnumerable Collection { get { return source; } } 


    public CommentModel(EntityCollection<TEntity> source) { 
     expandCommand = new ExpandCommand(this); 

     source.EntityAdded += OriginalSourceChanged; 
     source.EntityRemoved += OriginalSourceChanged; 

     originalSource = source; 
     UpdateBoundCollection(); 
    } 


    private void OnIsExpandedChanged() { 
     OnPropertyChanged("IsExpanded"); 
     UpdateBoundCollection(); 
    } 

    private void OriginalSourceChanged(object sender, EntityCollectionChangedEventArgs<TEntity> e) { 
     OnPropertyChanged("TotalComments"); 
     UpdateBoundCollection(); 
    } 

    private void UpdateBoundCollection() { 
     if (IsExpanded) 
      source = originalSource.OrderBy(s => PropertySorter(s)); 
     else 
      source = originalSource.OrderByDescending(s => PropertySorter(s)).Take(2).OrderBy(s => PropertySorter(s)); 

     OnPropertyChanged("IsExpandable"); 
     OnPropertyChanged("VisibleComments"); 
     OnPropertyChanged("Collection"); 
    } 

    // I wasn't sure how to get instances Func<T,TRet> into this class 
    // without some dirty hacking, so I used some reflection to run "OrderBy" queries 
    // All entities in my DataModel have 'bigint' Id columns 
    private long PropertySorter(TEntity s) { 
     var props = from x in s.GetType().GetProperties() 
        where x.Name == "Id" 
        select x; 

     if (props.Count() > 0) 
      return (long)props.First().GetValue(s, null); 

     return 0; 
    } 


    protected virtual void OnPropertyChanged(string propName) { 
     var x = PropertyChanged; 
     if (x != null) x(this, new PropertyChangedEventArgs(propName)); 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 
} 

現在,我們需要使用它:實體」

以下類的所有在Silverlight客戶端項目

首先一點水暖聲明。 WCF RIA Services會生成標記爲「部分」的類(我不知道是否有情況,但從我看到的情況來看)。所以我們將擴展它生成的實體類以包含我們的新模型。

// this must be inside the same namespace the classes are generated in 
// generally this is <ProjectName>.Web 
public partial class Timeline 
{ 
    ICommentModel model; 

    public ICommentModel CommentModel { 
     get { 
      if (model == null) 
       model = new CommentModel<TimelineComment>(Comments); 

      return model; 
     } 
    } 
} 

現在我們可以在'時間軸'類是數據/綁定上下文的綁定中引用評論模型。

例子:

<UserControl x:Class="Testing.Comments" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    mc:Ignorable="d" 
    d:DesignHeight="291" d:DesignWidth="382"> 

    <Border CornerRadius="2" BorderBrush="{StaticResource LineBrush}" BorderThickness="1"> 
     <Grid x:Name="LayoutRoot"> 
      <Grid.RowDefinitions> 
       <RowDefinition Height="Auto"/> 
       <RowDefinition/> 
      </Grid.RowDefinitions> 

      <StackPanel Visibility="{Binding Path=CommentModel.IsExpandable, Converter={StaticResource BooleanToVisibility}}"> 
       <HyperlinkButton 
        FontSize="10" 
        Command="{Binding Path=CommentModel.ExpandCommand}" 
        Background="{StaticResource BackBrush}"> 
        <TextBlock> 
         <Run Text="View all"/> 
         <Run Text="{Binding Path=CommentModel.TotalComments}"/> 
         <Run Text="comments"/> 
        </TextBlock> 
       </HyperlinkButton> 
       <Rectangle Height="1" Margin="0,1,0,0" Fill="{StaticResource LineBrush}" VerticalAlignment="Bottom"/> 
      </StackPanel> 

      <ItemsControl 
       Grid.Row="1" 
       ItemsSource="{Binding Path=CommentModel.Collection}" 
       ItemTemplate="{StaticResource CommentTemplate}" /> 
     </Grid> 
    </Border> 
</UserControl> 
+0

所以基本上你想分頁的結果? – CodingGorilla

+0

不是真的在術語的定義。假設集合中有10個項目,並且最初加載時只顯示前2個,如果用戶點擊「全部顯示」或「查看更多」,則顯示全部10個而不顯示下一個2 – SilverX

+0

I不要以爲有什麼可以重複使用的東西;這聽起來像是你需要實現自己的東西。但也許有人會證明我錯了。 =) – CodingGorilla

回答

2

這是您的視圖模型的工作。在內部你有一個完整的物品收集。然而,最初ViewModel應該公開一個IEnumerable,這將只有少數可用。

ViewModel還將公開名爲「ListAll」的ICommand屬性。執行該命令時,將用一個將列出所有項目的掩碼替換公開的IEnumerable

現在,您已經在做一個綁定ItemsControl的簡單案例,並且添加一個「More」按鈕來綁定「ListAll」命令。

+0

比我的解決方案簡單得多(我現在不會打擾發佈)。 – ChrisF

+0

是的,這聽起來就像我在尋找感謝。我會問,如果你的模型是由RIA Services生成的,你會怎麼做,但部分類聲明對這種類型的事情變得非常有用。 – SilverX

相關問題