0

我创建了一个代表日历月视图的 UI 用户控件。该控件由以 7x6 网格排列的 42 个边框组成(每周 7 天 x 每月显示 6 周)。

接下来,我创建了一个Appointment类。它有一个DateTime AppointmentDate属性,它应该确定我控制的约会出现的边界。

我希望能够为我的 UI 控件提供一组约会,然后控件应该确定哪个边框将包含约会项,而哪个边框将保持为空。

实现这一目标的最佳方法是什么?我在想以下几点:ItemsControl在我控制的每个边框上添加一个,然后将每个边框绑定到约会集合。然后,我将创建一个过滤器并将其应用于每个 ItemControl,以显示或省略相关的约会。这是否智能、编码、内存和性能明智?有没有更好的方法来实现这一目标?

如果我希望每个边界只进行一次预约(集合中没有预约日期相同的预约)怎么办?我应该用 替换ItemsControlContentControl?是否可以对 ContentControls 应用过滤,如果可以,如何?

谢谢你的协助。

4

3 回答 3

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) });
    }
}

现在,我们创建我们正在创建并添加到 WrapPanel 的 DayViewModel 和 DayView 控件。

<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 时,它会为您显示出来。:)

<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>

MainWindow.xaml.cs 中的代码隐藏

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

我可能犯了一个或两个错误,将其从我的解决方案转移到这里。但是,我希望它传达了这个想法。这最终对我来说是这样的。

三月日历

三月日历截图

四月日历

四月日历截图

现在,将所有这些放在一起以便为您工作。这只是演示了这项技术。呈现一个有意义的控件不应该那么难。

干杯。

于 2011-03-25T22:04:45.003 回答
1

为了就您的第一个问题向您提供建议,我会将您引导至CollectionViewSource并提及

当用户将 WPF 属性绑定到数据集合时,WPF 会自动创建一个视图来包装该集合,并将该属性绑定到视图,而不是原始集合。来源

这应该可以帮助您将整个数据集和可见部分之间的关​​注点分开。

对于第二个问题,一旦您选择了过滤逻辑,您就可以更好地为您的控件建模以使用它。由于我看不到您的代码并且对您在做什么知之甚少,因此这是相当通用的。我建议将控件绑定到单个约会(因此它只显示一个约会,正如您所要求的那样)。如果它为 null 或为空,则在该日期不显示任何内容。这将允许您操纵数据(模型)而不是控件(视图),但仍能达到您想要的结果。

于 2011-03-25T19:25:01.443 回答
0

我可能会对整个事情采取不同的方法。我会为 Days 创建一个 Collection,每一天都有一个 Date、Week、DayOfWeek 的整数属性和一个约会的 Collection。

然后,我将创建一个绑定到此 Collection 的 ItemsControl。

我会将 ItemsControl.PanelTemplate 制作成 7 列 6 行的 Grid,并将 ItemsControl.ItemTemplate 制作成包含日期和 ListBox 或 ItemsControl 的边框以保存约会。我会设置 ItemsControl.ItemStyle 以便 Grid.Row 和 Grid.Column 分别绑定到 Week 和 DayOfWeek。

于 2011-03-25T18:13:39.607 回答