WPF 日历 - 突出显示承诺日期
WPF Calendar - Highlights Dates of Commitments
我正在尝试用 "LigthPink" 颜色突出显示已安排约会的重要日期。在我的 WPF MVVM 项目中,我创建了一个代码,但我无法更新日期。
我得到了以下代码:
class ConverterHigligthdate: IValueConverter
{
static BindableCollection<DateTime> dict = new BindableCollection<DateTime>();
public event PropertyChangedEventHandler PropertyChanged;
static ConverterHigligthdate()
{
dict.Add(DateTime.Today);
dict.Add(DateTime.Today.AddDays(2));
dict.Add(DateTime.Today.AddDays(-10));
dict.Add(DateTime.Today.AddDays(-20));
dict.Add(DateTime.Today.AddDays(-15));
}
public static void AddDate(DateTime date)
{
dict.Add(date);
}
public static void RemoveDate(DateTime date)
{
dict.Remove(date);
}
public void Clear()
{
dict.Clear();
dict.Refresh();
}
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
string text = null;
if (dict.Contains((DateTime)value))
text = null;
else
text = "";
return text;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
并且在视图中:
<Window.Resources>
<local:ConverterHigligthdate x:Key="ConverterHigligthdate"/>
<Style x:Key="calendarDayButtonStyle" TargetType="{x:Type CalendarDayButton}">
<Setter Property="Margin" Value="8"/>
<Setter Property="FontSize" Value="13"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Converter={StaticResource ConverterHigligthdate}}" Value="{x:Null}">
<Setter Property="Background" Value="LightPink"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Grid Margin="5">
<Calendar SelectionMode="MultipleRange" CalendarDayButtonStyle="{DynamicResource calendarDayButtonStyle}"/>
</Grid>
result
有谁知道如何实现使这项工作有效的方法吗?
你的做法是错误的。使用 MVVM,你总是在你的视图模型层中执行业务逻辑,而不是在你的转换器中(它们是视图层的一部分)。
有很多方法可以解决这个问题,但通常您希望视图模型层以视图可以轻松使用的格式准备数据。为了提高性能,让我们将所有选定的日期包装在查找 table:
中
public class MainViewModel
{
public HashSet<DateTime> Dates { get; } = new HashSet<DateTime>();
public MainViewModel()
{
// highlight today and tomorrow
this.Dates.Add(DateTime.Today);
this.Dates.Add(DateTime.Today.AddDays(1));
}
}
现在您要在 CalendarDayButtonStyle 中添加一个 DataTrigger。当相关按钮的日期在您的 collection 中时,就是您想要更改背景颜色的时候:
<Style x:Key="CalendarDayButtonStyle" TargetType="CalendarDayButton">
<Style.Triggers>
<DataTrigger Value="True">
<DataTrigger.Binding>
<MultiBinding Converter="{StaticResource LookupConverter}">
<Binding />
<Binding Path="DataContext.Dates" RelativeSource="{RelativeSource AncestorType=Calendar}" />
</MultiBinding>
</DataTrigger.Binding>
<Setter Property="Background" Value="Pink" />
</DataTrigger>
</Style.Triggers>
</Style>
所以你现在只需要一个转换器来进行查找。我们需要传入查找 table 以及要查找的值,因此我们可以使用 MultiBinding。这实际上是逻辑,如果我们真的想的话,可以放在视图模型中,但它不引用任何 view-model 特定数据,它可以在其他地方 re-used,所以我们将稍微改变一下规则:
public class LookupConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
var date = (DateTime)values[0];
var dates = values[1] as HashSet<DateTime>;
return dates.Contains(date);
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
这就是您所需要的。结果:
我正在尝试用 "LigthPink" 颜色突出显示已安排约会的重要日期。在我的 WPF MVVM 项目中,我创建了一个代码,但我无法更新日期。
我得到了以下代码:
class ConverterHigligthdate: IValueConverter
{
static BindableCollection<DateTime> dict = new BindableCollection<DateTime>();
public event PropertyChangedEventHandler PropertyChanged;
static ConverterHigligthdate()
{
dict.Add(DateTime.Today);
dict.Add(DateTime.Today.AddDays(2));
dict.Add(DateTime.Today.AddDays(-10));
dict.Add(DateTime.Today.AddDays(-20));
dict.Add(DateTime.Today.AddDays(-15));
}
public static void AddDate(DateTime date)
{
dict.Add(date);
}
public static void RemoveDate(DateTime date)
{
dict.Remove(date);
}
public void Clear()
{
dict.Clear();
dict.Refresh();
}
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
string text = null;
if (dict.Contains((DateTime)value))
text = null;
else
text = "";
return text;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
并且在视图中:
<Window.Resources>
<local:ConverterHigligthdate x:Key="ConverterHigligthdate"/>
<Style x:Key="calendarDayButtonStyle" TargetType="{x:Type CalendarDayButton}">
<Setter Property="Margin" Value="8"/>
<Setter Property="FontSize" Value="13"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Converter={StaticResource ConverterHigligthdate}}" Value="{x:Null}">
<Setter Property="Background" Value="LightPink"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Grid Margin="5">
<Calendar SelectionMode="MultipleRange" CalendarDayButtonStyle="{DynamicResource calendarDayButtonStyle}"/>
</Grid>
result
有谁知道如何实现使这项工作有效的方法吗?
你的做法是错误的。使用 MVVM,你总是在你的视图模型层中执行业务逻辑,而不是在你的转换器中(它们是视图层的一部分)。
有很多方法可以解决这个问题,但通常您希望视图模型层以视图可以轻松使用的格式准备数据。为了提高性能,让我们将所有选定的日期包装在查找 table:
中public class MainViewModel
{
public HashSet<DateTime> Dates { get; } = new HashSet<DateTime>();
public MainViewModel()
{
// highlight today and tomorrow
this.Dates.Add(DateTime.Today);
this.Dates.Add(DateTime.Today.AddDays(1));
}
}
现在您要在 CalendarDayButtonStyle 中添加一个 DataTrigger。当相关按钮的日期在您的 collection 中时,就是您想要更改背景颜色的时候:
<Style x:Key="CalendarDayButtonStyle" TargetType="CalendarDayButton">
<Style.Triggers>
<DataTrigger Value="True">
<DataTrigger.Binding>
<MultiBinding Converter="{StaticResource LookupConverter}">
<Binding />
<Binding Path="DataContext.Dates" RelativeSource="{RelativeSource AncestorType=Calendar}" />
</MultiBinding>
</DataTrigger.Binding>
<Setter Property="Background" Value="Pink" />
</DataTrigger>
</Style.Triggers>
</Style>
所以你现在只需要一个转换器来进行查找。我们需要传入查找 table 以及要查找的值,因此我们可以使用 MultiBinding。这实际上是逻辑,如果我们真的想的话,可以放在视图模型中,但它不引用任何 view-model 特定数据,它可以在其他地方 re-used,所以我们将稍微改变一下规则:
public class LookupConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
var date = (DateTime)values[0];
var dates = values[1] as HashSet<DateTime>;
return dates.Contains(date);
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
这就是您所需要的。结果: