SurenSaluka
SurenSaluka

Reputation: 1591

How to read only the CalendarView control in UWP

On my UWP app, I have added a CalendarView and programmatically selected several dates. Now I want to make it read only to the end user. But the control does not provide such functionality and making IsEnabled = False is not an option. Please let me know a way of making the control read only. Thanks.

NOTE: I get this problem with the keyboard. When a user hits enter key or space bar key, Calender changes its view. I want to make it static.

Upvotes: 2

Views: 437

Answers (4)

shawnseanshaun
shawnseanshaun

Reputation: 1107

I know this is late, but assuming that you want the user to still be able to select and scroll through months, etc. this is all you should need to do:

<CalendarView SelectionMode="Multiple">
    <CalendarView.Resources>
        <Style TargetType="CalendarViewDayItem">
            <Setter Property="IsHitTestVisible"
                    Value="False" />
            <Setter Property="IsTabStop"
                    Value="False" />
        </Style>
    </CalendarView.Resources>
</CalendarView>

The IsHitTestVisible setter will ensure that the DayViewItem cannot be clicked or tapped, and the IsTabStop setter prevents keyboard focus on it.

This allows you to keep the full CalendarView functionality while simply disabling user date-selection.

Upvotes: 1

SurenSaluka
SurenSaluka

Reputation: 1591

For anyone who's looking for a complete code here it is. All this is thanks to Justin XL.

static int minOne = -1;
    static int plsOne = 1;
    public static async Task ManipCalenderUserInterface(List<CalendarView> calenders, List<List<DateTime>> datesListByMonth)
    {
        try
        {

                CoreDispatcher coreDispatcher = Window.Current.Dispatcher;
                await Task.Run(async () =>
                {
                    await Task.Delay(1000);
                    //coreDispatcher is required since you're not on the main thread and you can't manip UI from worker threads
                    await coreDispatcher.RunAsync(CoreDispatcherPriority.Normal,
                        () =>
                        {
                            int cnt = 0;
                            bool cont = false;
                            bool stop = false;
                            //Highlight color. I get it from my resource file
                            SolidColorBrush colorBrush = (SolidColorBrush)Application.Current.Resources["FgBlue1"];

                            //This code wrote to manipulate multiple calenders
                            foreach (var item in calenders)
                            {
                                var dayItems = item.Children().OfType<CalendarViewDayItem>();
                                var firstDayOfMonth = new DateTime(dayItems.Skip(15).First().Date.Year, dayItems.Skip(15).First().Date.Month, plsOne);
                                var lastDayOfMonth = firstDayOfMonth.AddMonths(plsOne).AddDays(minOne);

                                foreach (var dayItem in dayItems)
                                {
                                    var textBlock = dayItem.Children().OfType<TextBlock>().Single();

                                    int dayNum = System.Convert.ToInt32(textBlock.Text);
                                    if (dayNum == 1 && !stop) cont = true;

                                    if (cont && dayNum >= 1 && dayNum <= lastDayOfMonth.Day)
                                    {
                                        textBlock.Foreground = new SolidColorBrush(Colors.Black);
                                        //Bold the today date on this month's calender
                                        if (dayItem.Date == DateTime.Now.Date)
                                        {
                                            textBlock.FontWeight = FontWeights.Bold;
                                        }

                                        //datesListByMonth: contains all the dates need to be highlighted on th calender
                                        if (datesListByMonth[cnt] != null && datesListByMonth[cnt].Contains(dayItem.Date.Date))
                                            dayItem.Background = colorBrush;
                                    }
                                    if (cont && dayNum == lastDayOfMonth.Day)
                                    {
                                        cont = false;
                                        stop = true;
                                    }
                                }
                                cnt++;
                                cont = false;
                                stop = false;
                            }
                        });
                });

        }
        catch (Exception ex)
        {

        }
    }

Upvotes: 1

Justin XL
Justin XL

Reputation: 39006

Setting IsEnabled to False is the right way to go. I guess the reason that you don't want to use it is because doing so would dim the whole control. So the real question comes down to - how to disable the control while making its appearance unchanged?

Generally, the appearance of a disabled (i.e. IsEnabled="False") control is defined in the Disabled state inside its style. In your case though things will get a little bit more complicated because you need to update more than one styles as the CalendarView is a complex control.

Here is how it can be done.

First, you need to find the default style of the CalendarView control and put it inside your App.xaml. Then, search for <VisualState x:Name="Disabled"> and comment out everything within this visual state. There should be two of them 'cause the first one is for the up/down button and second one is for all the day of week text.

Apart from this, you also need to manually update the color of each CalendarViewDayItem simply because the TextBlock which is used to display the day number doesn't live inside its style.

To do this in code, go to my answer here and copy overChildren extension method, then you just need to run the following code in your Loaded event. Note you might want to give it a little bit delay so the Disabled state is applied properly.

Loaded += async (s, e) =>
{
    await Task.Delay(100);
    var dayItems = MyCalendarView.Children().OfType<CalendarViewDayItem>();
    foreach (var dayItem in dayItems)
    {
        var textBlock = dayItem.Children().OfType<TextBlock>().Single();
        textBlock.Foreground = new SolidColorBrush(Colors.Black);
    }
};

After doing all this, your CalendarView control will now appear just as normal when it's actually disabled.

Hope this helps!

Upvotes: 2

Jessica
Jessica

Reputation: 2067

You could also try

YourCalendarView.IsHitTestVisible = false;

or

<CalendarView IsHitTestVisible="False" />

Upvotes: 1

Related Questions