Devexpress 의 SchedulerControl 을 이용하여 Calendar 제작 하기



▼ 결과 화면


Project 명 : JScheduler



SchedulerControl 을 활용하는 연습을 하기위해 

Google Calendar와 Schedule/Task를 연동할 수 있는 App 을 제작 해 보았습니다.


현재는 간단한 기능 테스트가 목표이기 때문에 Task연동 부분을 하지는 않았고 Schedule(일정) 만 가능합니다만, 언젠가는 Task 도 해볼까 합니다. 언젠가는...


간단히, 초기 셋팅 방법과 주요 method를 살펴 보겠습니다. 

참고로 사용된 주요 소스코드는 첨부되어 있으며 소스의 출처는 : Devexpress Q&A 와 아래 링크의 Google API Guide 입니다.


1. Google 초기 셋팅 및 필요한 라이브러리 

 - https://developers.google.com/google-apps/calendar/quickstart/dotnet

  아래 Quickstart dotnet 버전을 보고 따라 하시면 어렵지 않게 완료 할 수 있습니다.

  간단히 

  -> Google에 Project 생성 후 

  -> C# Winform project 생성

  -> Nuget package 설치


2. Google API Loading

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
// If modifying these scopes, delete your previously saved credentials
// at ~/.credentials/calendar-dotnet-quickstart.json
private static string[] Scopes = { CalendarService.Scope.Calendar };    // important CalendarReadonly or Calendar
private string mApplicationName = "Google Calendar API";
 
 
private CalendarService Service = null;
/// <summary>
/// Google Calendar API loading
/// </summary>
private void LoadGoogleCalenarAPI(string user)
{
    try
    {
        UserCredential credential;
        using (var stream = new FileStream("client_secret_cal.json", FileMode.Open, FileAccess.Read))
        {
            //string credPath = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal);
            //credPath = Path.Combine(credPath, "\\credentials\\calendar-dotnet-quickstart.json");
            string credPath = System.Environment.CurrentDirectory;
            credPath = credPath + "\\credentials\\google_calendar.json";
 
            credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
                GoogleClientSecrets.Load(stream).Secrets,
                Scopes,
                user,
                CancellationToken.None,
                new FileDataStore(credPath, true)).Result;
            //Console.WriteLine("Credential file saved to: " + credPath);
        }
 
        // Create Google Calendar API Service.
        this.Service = new CalendarService(new BaseClientService.Initializer()
        {
            HttpClientInitializer = credential,
            ApplicationName = mApplicationName,
        });
    }
    catch (Exception ex)
    {
        MessageBox.Show("Connection fail");
        Application.Exit();
        //throw;
    }
}



3. Google Schedule loading 후 SchedulerControl이 인식할 수 있도록 Data Conversion

 - 달력의 날짜가 변경되면 해당 기간의 일정 자동 로딩.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
private void schedulerControl1_VisibleIntervalChanged(object sender, EventArgs e)
{
 
    if (switchToTimelineViewItem1.Checked || switchToTimelineViewItem1.Checked)
    {
 
    }
    else
    {
         
        schedulerControl1.Storage.Appointments.Clear();
        TimeIntervalCollection tic = schedulerControl1.ActiveView.GetVisibleIntervals();
        if (tic != null)
        {
            if (googleHelper != null)
            {
                Events evts = googleHelper.GetCalendarEvent(tic.Start.AddMonths(-1), tic.End.AddMonths(1), googleHelper.MaxCount);
 
                if (evts != null)
                {
                    CalendarImporter ci = new CalendarImporter(schedulerStorage1);
                    ci.Import(evts.Items);
 
                     
                }
                 
                /*
                foreach (Event item in evts.Items)
                {
                    addAppointment(item, AppointmentType.Normal);
                }
                */
            }
             
        }
              
                 
    }
}




4. JScheduler 에서 생성한 Schedule 을 Google로 보내기.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
public Event ConvertApppintmentToGoogleEvent(Appointment apt)
{
    Event evt = new Event();
    EventDateTime edt = new EventDateTime();
    EventReminder evtRem = new EventReminder();
 
    //DateTime offsetStartTime = DateTime.Today; // GetTimeZoneOffset(entry.Times[0].StartTime, "Mountain Standard Time");
 
    evt.Id = apt.Id as string;
    evt.Summary = apt.Subject;
    evt.Description = apt.Description;
    evt.Location = apt.Location;
    evt.ColorId = GoogleCalendarHelper.SwitchLabelCalor(apt.LabelId, false).ToString();
 
    try
    {
        //evt.HangoutLink = apt.CustomFields[0].ToString();
    }
    catch (Exception ex)
    {
         
    }
     
    if (apt.AllDay == true)
    {
        //offsetStartTime = GetTimeZoneOffset(apt.Start.Date, apt.TimeZoneId);
        edt = new EventDateTime();
        edt.TimeZone = "Europe/Rome"; //apt.TimeZoneId;
        edt.Date = apt.Start.Date.ToString("yyyy-MM-dd");
        evt.Start = edt;
 
        //offsetStartTime = GetTimeZoneOffset(apt.End.Date, apt.TimeZoneId);
        edt = null;
        edt = new EventDateTime();
        edt.TimeZone = "Europe/Rome";//apt.TimeZoneId;
        edt.Date = apt.End.Date.ToString("yyyy-MM-dd");
        evt.End = edt;
    }
    else
    {
        edt = new EventDateTime();
        edt.TimeZone = "Europe/Rome";//apt.TimeZoneId;
        edt.DateTime = apt.Start;
        evt.Start = edt;
 
        edt = null;
        edt = new EventDateTime();
        edt.TimeZone = "Europe/Rome";//apt.TimeZoneId;
        edt.DateTime = apt.End;
        evt.End = edt;
    }
 
 
    if (apt.IsOccurrence)
    {
        //apt.RecurrencePattern.
        //evt.Recurrence
    }
 
    if (apt.IsRecurring)
    {
        evt.RecurringEventId = apt.RecurrenceInfo.Id.ToString();
    }
 
    if(apt.Reminder != null)
    {
         
        Event.RemindersData reminder = new Event.RemindersData();
        IList<EventReminder> reminderlist = new List<EventReminder>();
 
        EventReminder er = new EventReminder();
        TimeSpan span = apt.Start.Subtract(apt.Reminder.AlertTime);
 
        er.Minutes = span.Minutes;
        er.Method = "popup";                 
                       
        reminderlist.Add(er);
        reminder.Overrides = reminderlist;
 
        evt.Reminders = reminder;
        evt.Reminders.UseDefault = false
         
    }
                
    return evt;
}




Component를 사용해 보면서 느낀점은 역시나 UI관련 기본적인 부분을 이미 대부분 구현해 놓았기 때문에 데이터 연동 부분만 신경 쓰면 되는게. 저 같은 1인 개발자 나 소규모의 개발집단에 개발 퍼포먼스 향상을 위해 아주 좋은 대안이 될거라는 생각이 듭니다. 물론 비용은 듭니다만, 비용대비 퍼포먼스는 만족할 만 합니다. 


CalendarExporter.cs

CalendarImporter.cs

GoogleCalendarHelper.cs

GoogleCalendarUtils.cs

RecurrencePatternParser.cs

MainForm.cs


'C# > WinForm' 카테고리의 다른 글

Windows Note App 만들기  (0) 2017.11.12
C# WebBrowser version 변경  (0) 2016.09.07
CefSharp install  (0) 2016.09.06
블로그 이미지

SuperNatural2

여전히 프로그래밍이 즐거운 사람 입니다

,

Bit Enum (Flag)

C#/Grammar 2017. 10. 1. 07:28
Bit 연산을 위한 Enum 을 만들수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
using System;
 
 
public class TestEnum
    {
        [Flags]
    enum BitEnum
    {
        Zero = 0,
        One = 1,
        Two = 2,
        Four = 4,
        Eight = 8
    }
        public TestEnum()
        {
            // AND operator
            BitEnum e1 = BitEnum.One & BitEnum.Four;
            Console.WriteLine(e1);
 
 
            if (e1.HasFlag(BitEnum.One))
            {
 
            }
 
 
 
            // OR operator
            BitEnum e2 = BitEnum.One | BitEnum.Four;
            Console.WriteLine(e2);
 
            // << operator
            byte e3 = 8 << 1;
            Console.WriteLine(e3);
            // >> operator
            byte e4 = 8 >> 1;
            Console.WriteLine(e4);
 
 
 
        }
    }



'C# > Grammar' 카테고리의 다른 글

C# 에서 사용되는 데이터 타입.  (0) 2017.09.25
블로그 이미지

SuperNatural2

여전히 프로그래밍이 즐거운 사람 입니다

,
Application 실행시 하나의 Machine 에서 하나의 프로세스만 실행하고 싶을경우 
C#의 Mutex 를 사용하여 제어 할 수 있다. 

1
2
3
4
5
6
7
8
9
10
11
12
string mutexID = "xxxxxx-xxxx-xxxx-xxxx-xxxxxx"; // AppName or app GUID
using (Mutex mutex = new Mutex(false, mutexID))
{
    if (!mutex.WaitOne(0, false))
    {
        MessageBox.Show("Another instance Already Running...", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
        return;
    }
    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);
    Application.Run(new MainForm());
}




Test Environments

- OS : Windows 7

- IDE : Visual Studio 2017

- .NET framework 4.5.2


'C# > Tips & Skills' 카테고리의 다른 글

C#에서 DB2 Connection  (0) 2016.09.07
블로그 이미지

SuperNatural2

여전히 프로그래밍이 즐거운 사람 입니다

,