jz87

I was building a DatePicker control to test out some ideas, here's the XAML template

<Setter Property="Template">

<Setter.Value>

<ControlTemplate TargetType="{x:Type local:DatePicker}">

<Border

Background="{TemplateBinding Background}"

BorderBrush="{TemplateBinding BorderBrush}"

BorderThickness="{TemplateBinding BorderThickness}">

<DockPanel LastChildFill="True">

<DockPanel x:Name="TopPane" DockPanel.Dock="Top" LastChildFill="False">

<Button x:Name="Prev" Content="&lt;"/>

<Button x:Name="Next" Content="&gt;" DockPanel.Dock="Right"/>

<Label Content="{TemplateBinding DisplayMonth}"/>

</DockPanel>

<UniformGrid x:Name="LabelPane" DockPanel.Dock="Top" Columns="7" Rows="1" TextBlock.TextAlignment="Center">

<TextBlock Text="S"/>

<TextBlock Text="M"/>

<TextBlock Text="T"/>

<TextBlock Text="W"/>

<TextBlock Text="R"/>

<TextBlock Text="F"/>

<TextBlock Text="S"/>

</UniformGrid>

<UniformGrid x:Name="ContentPane"

Columns="7"

FirstColumn="{TemplateBinding StartDay, Converter={StaticResource DayOfWeekConverter}}"

attached:ItemsGenerator.Items="{TemplateBinding IntProp}"

>

</UniformGrid>

</DockPanel>

</Border>

</ControlTemplate>

</Setter.Value>

</Setter>

public class DatePicker : ItemsControl {

static DatePicker() {

DefaultStyleKeyProperty.OverrideMetadata(typeof(DatePicker), new FrameworkPropertyMetadata(typeof(DatePicker)));

}

public DateTime DisplayMonth {

get { return (DateTime)GetValue(DisplayMonthProperty); }

set { SetValue(DisplayMonthProperty, value); }

}

public static readonly DependencyProperty DisplayMonthProperty =

DependencyProperty.Register("DisplayMonth", typeof(DateTime), typeof(DatePicker), new FrameworkPropertyMetadata(DateTime.Now, DisplayMonthChanged));

private static void DisplayMonthChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) {

if (e.NewValue == e.OldValue)

return;

Debug.Assert(e.NewValue is DateTime);

Debug.Assert(sender is DatePicker);

DateTime date = (DateTime)(e.NewValue);

if (date.Day != 1)

date = new DateTime(date.Year, date.Month, 1);

DatePicker datePicker = (DatePicker)sender;

datePicker.Days = new List<int>(1.Range(30));

datePicker.StartDay = date.DayOfWeek;

}

private static readonly DependencyPropertyKey DaysPropertyKey =

DependencyProperty.RegisterReadOnly("Days", typeof(List<int>), typeof(DatePicker), new UIPropertyMetadata(null));

public static readonly DependencyProperty DaysProperty = DaysPropertyKey.DependencyProperty;

public List<int> Days {

get { return (List<int>)GetValue(DaysProperty); }

private set { SetValue(DaysPropertyKey, value); }

}

private static readonly DependencyPropertyKey StartDayPropertyKey =

DependencyProperty.RegisterReadOnly("StartDay", typeof(DayOfWeek), typeof(DatePicker), new PropertyMetadata(DayOfWeek.Sunday));

public static readonly DependencyProperty StartDayProperty = StartDayPropertyKey.DependencyProperty;

public DayOfWeek StartDay {

get { return (DayOfWeek)GetValue(StartDayProperty); }

private set { SetValue(StartDayPropertyKey, value); }

}

public ArrayList IntProp {

get { return (ArrayList)GetValue(IntPropProperty); }

set { SetValue(IntPropProperty, value); }

}

// Using a DependencyProperty as the backing store for IntProp. This enables animation, styling, binding, etc...

public static readonly DependencyProperty IntPropProperty =

DependencyProperty.Register("IntProp", typeof(ArrayList), typeof(DatePicker), new UIPropertyMetadata(new ArrayList() { 1, 2, 3 }));

}

If I bind to the non generic ArrayList, it works, it I bind to List<int> it doesn't, with no errors or anything.



Re: Windows Presentation Foundation (WPF) WPF support for generics

Dr. WPF

The binding is succeeding but the Days collection is null.

This is because you are supplying a default value of null for the Days dependency property. If you do something like the following, you should see that the binding works:

Code Snippet

private static readonly DependencyPropertyKey DaysPropertyKey

= DependencyProperty.RegisterReadOnly("Days", typeof(List<int>),

typeof(DatePicker), new UIPropertyMetadata(GetDays(30)));

public static List<int> GetDays(int max)

{

List<int> result = new List<int>();

for (int i = 1; i <= max; i++)

result.Add(i);

return result;

}

With the above declaration and default value, you should be able to use "{TemplateBinding Days}" in your template.

You can bind to any enumerable collection, but if you want the binding to be dynamic, you'll need to bind to a collection that implements INotifyCollectionChanged. The ObservableCollection<T> class is usually the best choice.






Re: Windows Presentation Foundation (WPF) WPF support for generics

jz87

I tried your solution and it works. My followup question is why.

public DateTime DisplayMonth {

get { return (DateTime)GetValue(DisplayMonthProperty); }

set { SetValue(DisplayMonthProperty, value); }

}

public static readonly DependencyProperty DisplayMonthProperty =

DependencyProperty.Register("DisplayMonth", typeof(DateTime), typeof(DatePicker), new FrameworkPropertyMetadata(DateTime.Now, DisplayMonthChanged));

private static void DisplayMonthChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) {

if (e.NewValue == e.OldValue)

return;

Debug.Assert(e.NewValue is DateTime);

Debug.Assert(sender is DatePicker);

DateTime date = (DateTime)(e.NewValue);

if (date.Day != 1)

date = new DateTime(date.Year, date.Month, 1);

DatePicker datePicker = (DatePicker)sender;

datePicker.Days = new List<int>(1.Range(30));

datePicker.StartDay = date.DayOfWeek;

}

I have a propertyChangedcallback attached to the DisplayMonth property. So when that gets initialized, it sets the Days property. I used a dummy converter (just returns the value passed in) to verify that it is actually passing in a non-null value to Items property, the List<int> with 1 to 30 in it. Yet it doesn't work.

But if I changed List<int> to ArrayList, it works with no other changes.





Re: Windows Presentation Foundation (WPF) WPF support for generics

Dr. WPF

Sorry. Can't repro.

If you have something that compiles that you can post somewhere, I'll take a look.

If I were you, I think I'd specify the Days property as an observable collection of int values (ObservableCollection<int>) and simply add or remove items from the collection based on the month. I wouldn't replace the entire collection with each month change.

Btw, your color coded sample code with the large font is very hard to follow and is probably deterring people from reading your post.