も実装する Calendar に基づくカスタム コントロールを作成しました。その機能は、その日が Observable Collection に存在するかどうかに基づいて日を色分けできることです。
カレンダーの CalendarDayButton コンポーネントのテンプレートを作成し (Calendars ソース コードをコピーして)、背景色を表示するために使用できる四角形を追加しました。四角形の塗りつぶしプロパティは、マルチ バインディングとコンバーターを使用して、DataContext とカスタム カレンダーにバインドされます。
これは、CalendarDayButton の DataContext が変更されたときにうまく機能しますが、監視可能なコレクションに対して行われたすべての変更を完全に無視しているようです。つまり、日を追加または削除すると、カレンダーの外観が更新されません。コンバーターの Convert 関数にブレークポイントがありました。カレンダーが読み込まれると呼び出されますが、日を追加するときは呼び出されません。
カレンダーの OnPropertyChanged 関数にもブレークポイントを作成しましたが、PropertyChanged は常に null です。また、ObservableCollection を DependencyProperty にし、両方のオブジェクトに単一のバインディングを使用しようとしました。変化なし。四角形にバインドしてもリスナーが作成されないようです。
現在、カレンダーの日付を DateTime.Min に変更してから再度戻すと、この問題の回避策として各ボタンのデータ コンテキストが更新されますが、見苦しいです。
この動作をよりよく理解したいと思います。コレクションの変更によってトリガーされるカレンダーの日付ボタンの色を更新する適切なソリューションにも興味があります。
これが私のカスタムカレンダーです:
namespace Lekstuga
{
public class ColouredCalendar : Calendar, INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public DependencyProperty DoneMarkedDaysProperty =
DependencyProperty.Register("DoneMarkedDaysAttribute", typeof (ObservableCollection<DateTime>),
typeof (ColouredCalendar));
public ObservableCollection<DateTime> DoneMarkedDaysAttribute
{
get { return (ObservableCollection<DateTime>) GetValue(DoneMarkedDaysProperty); }
set { SetValue(DoneMarkedDaysProperty, value); }
}
static ColouredCalendar()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(ColouredCalendar), new FrameworkPropertyMetadata(typeof(ColouredCalendar)));
}
public ColouredCalendar()
: base()
{
SetValue(DoneMarkedDaysProperty, new ObservableCollection<DateTime>());
DoneMarkedDaysAttribute.Add(new DateTime(2013, 05, 01));
DoneMarkedDaysAttribute.Add(new DateTime(2013, 05, 02));
DoneMarkedDaysAttribute.Add(new DateTime(2013, 05, 03));
}
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
public void AddNextDay()
{
var greenDays = DoneMarkedDaysAttribute;
var nextDay = greenDays[greenDays.Count - 1].AddDays(1.0d);
DoneMarkedDaysAttribute.Add(nextDay);
OnPropertyChanged("DoneMarkedDaysAttribute");
}
public void Refresh()
{
var curDate = DisplayDate;
DisplayDate = DateTime.MinValue;
DisplayDate = curDate;
}
}
}
これが私のコンバーターです:
namespace Lekstuga
{
class DayToColorConverter : IMultiValueConverter
{
private SolidColorBrush myGreenBrush = new SolidColorBrush(Colors.Green);
private SolidColorBrush myIndigoBrush = new SolidColorBrush(Colors.Indigo);
public DayToColorConverter()
{
}
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
var tmp = (values[0] == null);
if (tmp == false)
{
tmp = (values[1] == null);
}
if (tmp == true) return null;
var day = ((DateTime) values[1]).Date;
var markedDays = (ObservableCollection<DateTime>)values[0];
if ( markedDays.Contains(day) )
{
return myGreenBrush;
}
return null;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
そして最後に、CalendarDayButton テンプレートの関連部分:
...
<Rectangle x:Name="TodayBackground" RadiusX="1" RadiusY="1" Opacity="0" Fill="#89B8FF"/>
<Rectangle x:Name="SelectedBackground" RadiusX="1" RadiusY="1" Opacity="0" Fill="{TemplateBinding Background}"/>
<Rectangle x:Name="Background" RadiusX="1" RadiusY="1" Opacity="0" Fill="{TemplateBinding Background}"/>
<Rectangle x:Name="DoneMarkingBackground" IsHitTestVisible="False" Visibility="Visible" >
<Rectangle.Fill>
<Binding Converter="{StaticResource DayToColorConv}" RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type local:ColouredCalendar}}" Mode="OneWay" />
</Rectangle.Fill>
</Rectangle>
<ContentPresenter
x:Name="NormalText"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
Margin="5,1,5,1">
<TextElement.Foreground>
<SolidColorBrush x:Name="selectedText" Color="#FF333333"/>
</TextElement.Foreground>
</ContentPresenter>
<Path x:Name="Blackout" Opacity="0" Margin="3" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" RenderTransformOrigin="0.5,0.5" Fill="#FF000000" Stretch="Fill" Data="M8.1772461,11.029181 L10.433105,11.029181 L11.700684,12.801641 L12.973633,11.029181 L15.191895,11.029181 L12.844727,13.999395 L15.21875,17.060919 L12.962891,17.060919 L11.673828,15.256231 L10.352539,17.060919 L8.1396484,17.060919 L10.519043,14.042364 z"/>
<Rectangle x:Name="DayButtonFocusVisual" Visibility="Collapsed" IsHitTestVisible="false" RadiusX="1" RadiusY="1" Stroke="#FF45D6FA"/>
...