I'm using the XamOutlookCalendarView in conjunction with the XamDateNavigator and I would like to be able to force (possibly via MVVM) the SelectedDates.
Since the SelectedDates property is readonly I don't know how to do it.
Is there a way?
Can I persist the SelectedDates property value and reapply it?
Even if I use the binding of the SelectedDate as soon as I load the control hosting the XamDateNavigator it defaults to DateTime.Today.
Best Regards
Roberto Dalmonte
I hadn't tried using this behavior in Silverlight until now and I think I can see what the issue is. Binding updates seem to happen a bit later than they do in WPF which is resulting in the behavior's SelectedDates DependencyProperty to be null when OnAttached is called. This causes the setup for the CollectionChanged notification for the viewmodel's SelectedDates to get skipped. Since it got skipped, if you were to press the button in my sample after the application starts, it won't actually select the dates.
What I did to resolve this was to use a dispatcher in order to invoke the SubscribeToEvents method at a later time after the OnAttached method when the DependencyProperty will be updated to the viewmodel's collection. I've tested this updated behavior in both WPF and Silverlight and it's working as expected. I've attached the sample to this post.
Let me know if you have any questions on it.
Hello Rob,thank you for your time. I guess I forgot to mention that I need this to work on WPF & Silverlight as well.
I can see your sample works in a WPF application. I tried it in Silverlight and it doesn't.
This only change I made is to reference the silverlight version of system.windows.interactivity.dll and the Binding Mode=TwoWay.
<local:XamDateNavigatorSelectedDatesBehavior SelectedDates="{Binding SelectedDates, Mode=TwoWay}" />
Have you tried it as well in a Silverlight project?
Best regards.
Roberto
Hi Roberto,
I've used your behavior in a quick sample and everything looks good. The binding is working both ways. If I select dates from the XamDateNavigator the dates appear in the SelectedDates collection and if I change the dates in the SelectedDates collection the XamDateNavigator updates itself to reflect the change.
Your issue seems to be that you're not using an ObservableCollection. You're probably using a collection like List<DateTime> which doesn't support collection changed notifications. This behavior requires that your viewmodel collection produces collection changed notifications in order to update the XamDateNavigator. Changing your SelectedDates to an ObservableCollection should do the trick.
I've attached a sample that demonstrates that the binding is indeed two-way as long as the proper collection is used. Let me know if you have any questions on this.
Hello Alan,I tried what you suggested, but I couldn't make it work (the way I want it).Mimicking the samples provided I elaborated this class:
public class XamDateNavigatorSelectedDatesBehavior : Behavior<XamDateNavigator> { private XamDateNavigator DateNavigator { get { return AssociatedObject as XamDateNavigator; } }
public INotifyCollectionChanged SelectedDates { get { return (INotifyCollectionChanged)GetValue(SelectedDatesProperty); } set { SetValue(SelectedDatesProperty, value); } }
public static readonly DependencyProperty SelectedDatesProperty = DependencyProperty.Register( "SelectedDates", typeof(INotifyCollectionChanged), typeof(XamDateNavigatorSelectedDatesBehavior), null);
protected override void OnAttached() { base.OnAttached(); SubscribeToEvents(); }
private void ContextSelectedDates_CollectionChanged(Object sender, NotifyCollectionChangedEventArgs e) { UnsubscribeFromEvents(); Transfer(SelectedDates as IList, DateNavigator.SelectedDates); SubscribeToEvents(); }
private void SelectedDates_CollectionChanged(Object sender, NotifyCollectionChangedEventArgs e) { UnsubscribeFromEvents(); Transfer(DateNavigator.SelectedDates, SelectedDates as IList); SubscribeToEvents(); }
private void SubscribeToEvents() { DateNavigator.SelectedDates.CollectionChanged += SelectedDates_CollectionChanged;
if (SelectedDates != null) { SelectedDates.CollectionChanged += ContextSelectedDates_CollectionChanged; } }
private void UnsubscribeFromEvents() { DateNavigator.SelectedDates.CollectionChanged -= SelectedDates_CollectionChanged;
if (SelectedDates != null) { SelectedDates.CollectionChanged -= ContextSelectedDates_CollectionChanged; } }
public static void Transfer(IList source, IList target) { if (source == null || target == null) { return; }
target.Clear();
foreach (var o in source) { target.Add(o); } } }
On the XAML side this is the code
<ig:XamDateNavigator> <i:Interaction.Behaviors> <b:XamDateNavigatorSelectedDatesBehavior SelectedDates="{Binding SelectedDates}" /> </i:Interaction.Behaviors> </ig:XamDateNavigator>
It works only in one direction: if I select some dates on the XamDateNavigator itself, this selection triggers my SelectedDates property and I get the selected dates correctly in my ViewModel. The other way around won't work though, and this is exactly what I need: to be able to select some dates from the viewmodel.
Possibly I am missing something or just committed some errors in the implementation.
Otherwise if I have to stick with one-way only solution I certainly prefer a trigger:
<swi:Interaction.Triggers> <swi:EventTrigger EventName="SelectedDatesChanged"> <mei:CallMethodAction TargetObject="{Binding}" MethodName="OnSelectedDatesChanged" /> </swi:EventTrigger> </swi:Interaction.Triggers>
and I only need to implement one method on my viewmodel.
At the moment, the only thing that works is to pass a reference of the XamDateNavigator to the viewmodel, use the SelectedDatesChanged behind the code and keep a reference of the viewmodel behind the code as well.
Am I overlooking something?
Roberto,
One approach that you could take is to use a Behavior to provide a selected items collection that you can bind to. There is an example of this approach in Devin's blog post on Using Behaviors to Synchronize Selected Items of Infragistics Silverlight controls to a ViewModel. Note that the blog shows how to do this in Silverlight for some controls and the same approach could be used in WPF.
Let me know if you have any questions with this matter.