2011-03-25 137 views
0

我創建了一個表示日曆月視圖的UI用戶控件。該控件由42個邊界組成,7×6網格(每週7天,每週6個月顯示)。WPF:篩選ItemsControl和ContentControl中的項目

接下來,我創建了Appointment類。它有一個DateTime AppointmentDate屬性,它應該確定我的控件中約會的邊界。

我希望能夠向我的UI控件提供約會集合,然後控件應確定哪個邊框將包含預約項目和哪些將保持空白。

達到此目的的最佳方法是什麼?我正在考慮以下內容:在我的控件的每個邊框中添加ItemsControl,然後將每個邊框綁定到約會集合。然後,我會創建並應用篩選器到每個ItemControls以顯示或省略相關約會。這種智能,編碼,內存和性能是否明智?有沒有更好的方法來實現這一目標?

如果我希望每個邊框僅保留一個預約會怎麼樣?(集合中將沒有預約具有相同的預約日期)?我應該用ContentControl替換ItemsControl嗎?是否有可能對ContentControls應用過濾,如果是,如何?

感謝您的幫助。

回答

0

我可能會採取不同的方法來處理整個事情。我會爲Days創建一個Collection,並且每個Day都有一個Date,Week,DayOfWeek和Appointments集合的整數屬性。

然後我會創建一個綁定到這個集合的ItemsControl。

我將ItemsControl.PanelTemplate放入一個帶有7列和6行的Grid中,並將ItemsControl.ItemTemplate放入一個包含Date和ListBox或ItemsControl的Border中以容納Appointments。我將設置ItemsControl.ItemStyle,以便Grid.Row和Grid.Column分別綁定到Week和DayOfWeek。

+0

如果每天只能有一個約會,您將使用哪種控件來存儲約會? 'ListBox'對於一天約會的集合很有用,但我缺少單個約會對象的容器。 ContentControl是我正在尋找的那個? – Boris 2011-03-25 18:29:37

+0

爲什麼你需要一個或另一個?帶有一個項目的「ListBox」應該看起來與其中包含一個項目的「ContentControl」相同。唯一可能分散注意力的是ListBox選擇符,但是當列表中只有一個項目時,可以使用PropertyTrigger和style。但它看起來像你不知道你是否需要每天的約會名單。如果每天只能有一個約會,則不應該使用ItemsControl(或派生類)。在這種情況下,可以使用任何ContentControl派生類。 – 2011-03-25 19:12:47

+0

感謝您澄清戴夫。 – Boris 2011-03-25 19:16:02

1

勸你你的第一個問題,我會帶你到CollectionViewSource並註明

當用戶綁定一個WPF屬性的 收集數據,WPF自動 創建一個視圖來包裝集合 並將該屬性綁定到視圖 而不是原始集合。 Source

這應該可以幫助您區分整個數據集和可見部分之間的關​​系。

對於第二個問題,一旦你選擇了過濾邏輯,你可以更好地建模你的控件來處理它。由於我看不到你的代碼,並且對你正在做的事情一無所知,所以這是相當通用的。我會建議將控件綁定到單個約會(所以它只顯示一個約會,如您所請求的)。如果它爲空或空,則不顯示該日期。這將允許您操縱數據(模型)而不是控件(視圖),但仍可實現您想要的結果。

+0

+1,它也支持過濾器。 – 2011-03-25 23:11:13

+0

如果我爲每個包含特定日期的約會的列表實施「CollectionViewSource」並對這些列表應用過濾,那麼性能影響和內存佔用會有什麼影響?由於將會有42個列表針對收集視圖源,它將被過濾42次,所以我很少關心用戶體驗。你怎麼看? – Boris 2011-03-26 13:02:31

2

我嘲笑了一種不同於你所建議的方法。這是簡化的,我已經做出了一兩個假設,但讓我們試試這個。

我們不使用網格並將日子匹配到網格中,而是使用WrapPanel,並將其放入每個表示一天的子節點中。

在你的App.xaml.cs中,你可以放一些代碼來創建一個Day對象。

public class Day 
{ 
    public DateTime Date { get; set; } 
    public List<Appointment> Appointments { get; set; } 
} 

public partial class App : Application 
{ 
    protected override void OnActivated(EventArgs e) 
    { 
     base.OnActivated(e); 

     var daysCollection = new List<Day>(); 
     for (int i = 1; i <= 30; i++) 
     { 
      daysCollection.Add(new Day 
       { 
        // arbitrary sample data 
        Date = new DateTime(2011, 04, i), 
        Appointments = 
         new List<Appointment> 
          { 
           new Appointment 
            { 
             Date = new DateTime(2011, 04, i), 
             Description = "Some descriptive text" 
            } 
          } 
       }); 
     } 

     this.Properties.Add("DaysCollection", daysCollection); 
    } 
} 

現在我們有一個天的集合。這部分樣本的約會並不重要。

現在,我們創建一個簡單的日曆UserControl並將其綁定到CalendarViewModel。

<UserControl x:Class="DaysCalendarBinding.Views.Calendar" 
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
      mc:Ignorable="d" 
      Height="210" Width="210"> 
    <WrapPanel x:Name="wrapPanel" Orientation="Horizontal" 
       ItemHeight="30" ItemWidth="30" 
       Loaded="wrapPanel_Loaded"> 
    </WrapPanel> 
</UserControl> 

視圖模型

public class CalendarViewModel 
{ 
    public CalendarViewModel() 
    { 

    } 

    public CalendarViewModel(IEnumerable<Day> inputDays) 
    { 
     // determine first day of the month passed in 
     var firstDate = 
      (from day in inputDays 
      orderby day.Date.Day 
      select day.Date).First(); 
     var todayIs = firstDate.DayOfWeek; 
     var valueOfToday = (int) todayIs; 

     // create this many blank day children 
     DaysInMonth = new List<Day>(); 
     for (int i = valueOfToday; i > 0; i--) 
     { 
      // the start of some cheeze. I know. It's a sample. 
      DaysInMonth.Add(new Day { Date = new DateTime(1,1,1) }); 
     } 

     // add the rest ofthe days in to the collection 
     foreach(var day in inputDays) 
     { 
      DaysInMonth.Add(day); 
     } 
    } 

    public List<Day> DaysInMonth { get; private set; } 
} 

與事件處理程序時wrapPanel加載

private void wrapPanel_Loaded(object sender, RoutedEventArgs e) 
{ 
    foreach (var day in ((CalendarViewModel)DataContext).DaysInMonth) 
    { 
     wrapPanel.Children.Add(
       new DayView { 
         DataContext = new DayViewModel(day) }); 
    } 
} 

現在,我們創造,我們正在創造並增加了對DayViewModel和DayView控制WrapPanel。

<UserControl x:Class="DaysCalendarBinding.Views.DayView" 
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
      mc:Ignorable="d" 
      d:DesignHeight="30" d:DesignWidth="30"> 
    <Border BorderBrush="Black" BorderThickness="1"> 
     <StackPanel Height="30" Width="30" Background="AliceBlue"> 
      <TextBlock FontSize="7" Text="{Binding DayDate}"/> 
     </StackPanel> 
    </Border> </UserControl> 

視圖模型

public class DayViewModel 
{ 
    private Day innerDay; 

    public DayViewModel() {} 

    public DayViewModel(Day day) 
    { 
     innerDay = day; 
    } 

    public string DayDate 
    { 
     get 
     { 
      // I know this is a cheesy approach. It's a sample. :) 
      if (innerDay.Date.Year != 1) 
       // this only intended to demonstrate some content 
       return innerDay.Date.DayOfWeek.ToString().Remove(3) + 
         " " + innerDay.Date.Day; 
      return string.Empty; 
     } 
    } 
} 

如今終於,我們的主窗口,在這裏我們添加一個日曆控件,添加CalendarViewModel和希望,當我們按下F5,它顯示了你。 :)在MainWindow.xaml.cs

protected override void OnActivated(EventArgs e) 
{ 
    base.OnActivated(e); 
    calendarControl.DataContext = 
          new CalendarViewModel((IEnumerable<Day>)Application 
           .Current 
           .Properties["DaysCollection"]); 
} 

<Window x:Class="DaysCalendarBinding.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:Views="clr-namespace:DaysCalendarBinding.Views" Title="Calendar Demo" Height="350" Width="525"> 
    <Grid> 
     <Views:Calendar x:Name="calendarControl"></Views:Calendar> 
    </Grid> 
</Window> 

代碼隱藏我可能犯了一個錯誤或兩個調換到這裏這從我的解決方案。但是,我希望它能傳達這個想法。這最終會讓我看起來像這樣。

三月日曆

March Calendar Screenshot

四月日曆

April Calendar Screenshot

現在,來把所有這些組合起來,使其爲你工作的一部分。這只是演示技術。提出有意義的控制應該不那麼困難。

乾杯。

+0

+1爲深入的例子... – 2011-03-25 22:25:20

+0

真棒的例子,我也是+1。最後,我寧願避免將'WrapPanel'作爲個人選擇,但是這是一個很好的例子。乾杯! – Boris 2011-03-26 13:06:17