Design an Airfare Calendar to Display the Lowest Fares Using the WinUI Scheduler
Detailed Blog page Skeleton loader
Design an Airfare Calendar to Display the Lowest Fares Using the WinUI Scheduler

It is human nature to look for products with the lowest prices. In the same way, most people search for the lowest airfares among airlines while booking their tickets.

The Syncfusion WinUI Scheduler, with its comprehensive feature set, allows users to design an airfare calendar to display the lowest fares by customizing the month cells.

In this blog, we will see the steps to design an airfare calendar to display the lowest fares using the WinUI Scheduler control with code examples.

Designing a Lowest Airfare Calendar Using the WinUI Scheduler
Designing a Lowest Airfare Calendar Using the WinUI Scheduler

Note: If you are new to our control, then refer to the WinUI Scheduler getting started documentation before proceeding.

Designing an airfare calendar using the WinUI Scheduler

To design an airfare calendar, we have to customize the WinUI Scheduler’s month cells using the MonthCellTemplate or MonthCellTemplateSelector properties of the MonthViewSettings. The DataContext of the MonthCellTemplate or MonthCellTemplateSelector properties should be MonthCell. You can use the MonthCell class properties, such as DateText, Appointments, and Data, to bind the airfare details in the month cell data template.

Let’s see the steps to implement it!

Step 1: Create an airline data model

First, you need to create a custom data model Airline with the required airline data, such as airline name or ID, date, color, and fare details.

using Syncfusion.UI.Xaml.Core;
 
/// <summary>
/// Represents the airline data properties.
/// </summary>
public class Airline : NotificationObject
{
  private DateTime from;
  private Brush color;
  private string name;
  private double fare;
  private string cost;
 
  public string Name
  {
    get { return name; }
    set
    {
      name = value;
      RaisePropertyChanged(nameof(Name));
    }
  }
 
  public DateTime Date
  {
    get { return from; }
    set
    {
      from = value;
      RaisePropertyChanged(nameof(Date));
    }
  }
 
  public double Fare
  {
    get { return fare; }
    set
    {
      fare = value;
      RaisePropertyChanged(nameof(Fare));
    }
  }
 
  public string Cost
  {
    get { return cost; }
    set
    {
      cost = value;
      RaisePropertyChanged(nameof(Cost));
    }
  }
 
  public Brush Color
  {
    get { return color; }
    set
    {
      color = value;
      RaisePropertyChanged(nameof(Color));
    }
  }
}

Step 2: Create airline data collection

Then, create the collection of airline data objects and calculate the lowest airfare for each day by comparing the lowest fares of all the airlines.

/// <summary>
/// The airlines view model.
/// </summary>
public class AirlinesViewModel
{
  /// <summary>
  /// Gets or sets the lowest airfares.
  /// </summary>
  public List<Airline> LowestFares { get; set; }
 
  /// <summary>
  /// Initializes a new instance of the AirlinesViewModel class.
  /// </summary>
  public AirlinesViewModel()
  {
    GetLowestFares();
  }
 
  /// <summary>
  /// Methods to get the lowest airfares.
  /// </summary>
  private void GetLowestFares()
  {
    this.LowestFares = new List<Airline>();
    List<Airline> fares = GetAllFares();
 
    var currentDate = DateTime.Now.Date;
    for (int startdate = -100; startdate < 100; startdate++)
    {
      var currentDateFares = fares.Where(x => x.Date == currentDate.AddDays(startdate)).ToList();
      //Add only lowest fare for the day.
      double minimumFare = Math.Min(currentDateFares[0].Fare, Math.Min(currentDateFares[1].Fare, currentDateFares[2].Fare));
      this.LowestFares.Add(currentDateFares.Where(x => x.Fare == minimumFare).FirstOrDefault());
    }
  }
 
  /// <summary>
  /// Method to get all the airways fare.
  /// </summary>
  /// <returns>returns all airways fares</returns>
  private List<Airline> GetAllFares()
  {
    var random = new Random();
    var fares = new List<Airline>();
    var airwaysFares = new List<double>()
    {
      90.50, 95.00, 102.66, 200.09, 180.20, 122.10, 138.83,
      134.50, 305.00, 152.66, 267.09, 189.20, 212.10, 238.83,
      100.17, 101.72, 332.48 ,100.17, 449.68, 378.44, 273.45,
    };
 
    for (int startdate = -100; startdate < 100; startdate++)
    {
      for (int j = 1; j <= 3; j++)
      {
        var airline = new Airline();
        airline.Name = "Airways " + j.ToString();
        //// Adding random fares for airways.
        airline.Fare = airwaysFares[random.Next(0, 20)];
        airline.Cost = "$" + airline.Fare.ToString();
        airline.Color = GetAirlineColor(airline.Name);
        airline.Date = DateTime.Now.Date.AddDays(startdate);
        fares.Add(airline);
      }
    }
 
    return fares;
  }
 
  /// <summary>
  /// Methods to get the airline color.
  /// </summary>
  /// <param name="airlineName"></param>
  /// <returns></returns>
  private Brush GetAirlineColor(string airlineName)
  {
    if (airlineName == "Airways 1")
      return new SolidColorBrush(Colors.Red);
    else if (airlineName == "Airways 2")
      return new SolidColorBrush(Colors.Green);
    else
      return new SolidColorBrush(Colors.Gray);
  }
}

Step 3: Map the custom airline data object properties

Now, map the custom airline data object properties to the Scheduler by configuring the AppointmentMapping property. Then, assign the collection of airline data objects to the ItemsSource property to generate the details of Appointments in the MonthCell, which displays the airfare details of the day.

<Window
 ...
 xmlns:Scheduler="using:Syncfusion.UI.Xaml.Scheduler" >
 
<Scheduler:SfScheduler x:Name="scheduler"
                         ItemsSource="{Binding LowestFares}"
                         ShowBusyIndicator="True"
                         AppointmentEditFlag="None">
 <Scheduler:SfScheduler.AppointmentMapping>
  <Scheduler:AppointmentMapping Subject="Name"
                                Notes="Cost"
                                StartTime="Date"
                                AppointmentBackground="Color" />
 </Scheduler:SfScheduler.AppointmentMapping>
 <Scheduler:SfScheduler.MonthViewSettings>
  <Scheduler:MonthViewSettings AppointmentDisplayMode="None"
                               MonthCellTemplateSelector="{StaticResource monthCellTemplateSelector}"/>
 </Scheduler:SfScheduler.MonthViewSettings>
</Scheduler:SfScheduler>

Step 4: Design the airfare calendar using DataTemplateSelector in WinUI Scheduler

Now, create a data template selector class to select different custom month cell data templates based on the airfare and assign it to the MonthCellTemplateSelector property of the MonthViewSettings.

As I said before, you can use the MonthCell data context class properties, such as DateText, Appointments, and Data, to bind the airfare details in the month cell data template.

Refer to the following code example.

public class MonthCellTemplateSelector : DataTemplateSelector
{
  public DataTemplate MonthCellWithBestPriceTemplate { get; set; }
 
  public DataTemplate MonthCellWithoutBestPriceTemplate { get; set; }
 
  /// <summary>
  /// Template selection method.
  /// </summary>
  protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
  {
    var appointments = item as List<ScheduleAppointment>;
    foreach (var app in appointments)
    {
      var ailrline = app.Data as Airline;
      if (ailrline.Fare <= 100.0)
        return MonthCellWithBestPriceTemplate;
      else
        return MonthCellLowestPriceTemplate;
    }
    return MonthCellLowestPriceTemplate;
  }
}

Now, set the AppointmentEditFlag property as None in the Scheduler to restrict editor opening, and set the AppointmentDisplayMode property as None to keep appointments from displaying on month cells.

<Grid>
 <Grid.DataContext>
  <local:AirlinesViewModel/>
 </Grid.DataContext>
 <Grid.Resources>
  <DataTemplate x:Key="listViewItemTemplate">
   <StackPanel>
    <TextBlock
       Text="{Binding Data.Cost}"
       HorizontalAlignment="Center" FontWeight="Medium" Foreground="{ThemeResource SystemListAccentHighColor}" Margin="5"/>
    <StackPanel Orientation="Horizontal">
     <Viewbox>
       <Path Data="M13.4002 12.48L12.1402 9.05999L12.6502 8.54999C12.6925 8.50814 12.7262 8.4583 12.7491 8.40337C12.772 8.34845 12.7838 8.28951 12.7838 8.22999C12.7838 8.17046 12.772 8.11153 12.7491 8.0566C12.7262 8.00167 12.6925 7.95184 12.6502 7.90999C12.564 7.82389 12.4471 7.77553 12.3252 7.77553C12.2034 7.77553 12.0865 7.82389 12.0002 7.90999L11.8002 8.10999L11.5402 7.39999L12.1702 6.77999C12.2563 6.69374 12.3047 6.57686 12.3047 6.45499C12.3047 6.33312 12.2563 6.21623 12.1702 6.12999C12.0833 6.04916 11.9689 6.00423 11.8502 6.00423C11.7315 6.00423 11.6172 6.04916 11.5302 6.12999L11.1902 6.46999L10.8102 5.46999C11.1902 5.09999 11.5802 4.71999 11.9502 4.33999C12.4847 3.8419 12.9065 3.2354 13.1877 2.56109C13.4688 1.88678 13.6026 1.1602 13.5802 0.429988C13.573 0.335197 13.5314 0.2463 13.4633 0.180007C13.3952 0.113714 13.3052 0.0745895 13.2102 0.0699876C12.481 0.0509533 11.7561 0.187352 11.0837 0.470117C10.4112 0.752883 9.80669 1.17554 9.31022 1.70999L8.31022 2.78999L7.01022 2.26999L7.35022 1.92999C7.39255 1.88814 7.42615 1.8383 7.44909 1.78338C7.47202 1.72845 7.48383 1.66951 7.48383 1.60999C7.48383 1.55046 7.47202 1.49153 7.44909 1.4366C7.42615 1.38167 7.39255 1.33184 7.35022 1.28999C7.26398 1.20389 7.14709 1.15553 7.02522 1.15553C6.90335 1.15553 6.78646 1.20389 6.70022 1.28999L6.06022 1.91999L5.35022 1.65999L5.55022 1.45999C5.63632 1.37374 5.68468 1.25686 5.68468 1.13499C5.68468 1.01312 5.63632 0.896232 5.55022 0.809988C5.50837 0.767659 5.45854 0.734054 5.40361 0.711118C5.34868 0.688183 5.28974 0.676374 5.23022 0.676374C5.17069 0.676374 5.11176 0.688183 5.05683 0.711118C5.0019 0.734054 4.95207 0.767659 4.91022 0.809988L4.40022 1.31999L1.09022 0.0999876C0.98475 0.0605345 0.868473 0.0611388 0.763419 0.101686C0.658365 0.142233 0.571833 0.219906 0.52022 0.319988C0.470045 0.407382 0.450657 0.50909 0.465162 0.608814C0.479667 0.708539 0.527226 0.800508 0.600219 0.869988L6.09022 5.12999C5.43022 5.91999 4.79022 6.77999 4.17022 7.56999C3.68022 8.23999 3.17022 8.93999 2.77022 9.65999L1.46022 9.05999C1.34043 9.00169 1.20523 8.98286 1.07407 9.00622C0.942904 9.02958 0.822522 9.09391 0.73022 9.18999L0.20022 9.71999C0.138233 9.78053 0.0889773 9.85286 0.0553479 9.93271C0.0217186 10.0126 0.00439453 10.0983 0.00439453 10.185C0.00439453 10.2716 0.0217186 10.3574 0.0553479 10.4373C0.0889773 10.5171 0.138233 10.5894 0.20022 10.65L2.92022 13.37C3.04341 13.4897 3.20843 13.5567 3.38022 13.5567C3.55201 13.5567 3.71703 13.4897 3.84022 13.37L4.38022 12.83C4.47251 12.7353 4.53424 12.6151 4.55742 12.485C4.5806 12.3548 4.56416 12.2207 4.51022 12.1L3.96022 10.86C4.68022 10.42 5.38022 9.93999 6.06022 9.44999C6.74022 8.95999 7.66022 8.20999 8.42022 7.55999L12.5802 12.93C12.655 13.0119 12.7563 13.0647 12.8662 13.0792C12.9762 13.0936 13.0877 13.0687 13.181 13.0088C13.2744 12.949 13.3436 12.8581 13.3764 12.7522C13.4092 12.6462 13.4034 12.5321 13.3602 12.43L13.4002 12.48Z"
             Fill="{Binding Data.Color}" Height="18" Stretch="Fill" Width="18" />
     </Viewbox>
     <TextBlock Text="{Binding Data.Name}" Margin="5,0,5,0" Foreground="{ThemeResource SystemBaseHighColor}" />
    </StackPanel>
   </StackPanel>
  </DataTemplate>
 
  <DataTemplate x:Key="monthCellTemplateWithBestPrice">
   <StackPanel Background="LightYellow">
    <notification:BadgeContainer>
     <notification:BadgeContainer.Badge>
      <notification:SfBadge Content="Best Price" Shape="Rectangle" Background="{ThemeResource TextControlHighlighterBackground}" Foreground="Black" HorizontalAnchor="Inside" Margin="0,0,1,0" VerticalAnchor="Inside" />
     </notification:BadgeContainer.Badge>
    </notification:BadgeContainer>
    <TextBlock x:Name="TextBlock" HorizontalAlignment="Left" Margin="5,5,0,0" VerticalAlignment="Center" Text="{Binding Path=DateText}" />
 
    <ListView ItemsSource="{Binding Appointments}" HorizontalAlignment="Center" IsHitTestVisible="False"
              ItemTemplate="{StaticResource listViewItemTemplate}"/>
   </StackPanel>
  </DataTemplate>
 
  <DataTemplate x:Key="monthCellTemplateWithoutBestPrice">
   <StackPanel>
    <TextBlock x:Name="TextBlock" HorizontalAlignment="Left" Margin="5,5,0,0" VerticalAlignment="Center" Text="{Binding Path=DateText}" />
    <ListView ItemsSource="{Binding Appointments}" HorizontalAlignment="Center" IsHitTestVisible="False"
              ItemTemplate="{StaticResource listViewItemTemplate}"/>
   </StackPanel>
  </DataTemplate>
 
  <local:MonthCellTemplateSelector x:Key="monthCellTemplateSelector"
                                     MonthCellWithBestPriceTemplate="{StaticResource monthCellTemplateWithBestPrice}"
                                     MonthCellLowestPriceTemplate="{StaticResource monthCellTemplateWithoutBestPrice}"/>
 </Grid.Resources>
 <Scheduler:SfScheduler x:Name="scheduler"
                        ItemsSource="{Binding LowestFares}"
                        ShowBusyIndicator="True"
                        AppointmentEditFlag="None">
  <Scheduler:SfScheduler.AppointmentMapping>
   <Scheduler:AppointmentMapping Subject="Name"
                                 Notes="Cost"
                                 StartTime="Date"
                                 AppointmentBackground="Color" />
  </Scheduler:SfScheduler.AppointmentMapping>
  <Scheduler:SfScheduler.MonthViewSettings>
   <Scheduler:MonthViewSettings AppointmentDisplayMode="None"
                                MonthCellTemplateSelector="{StaticResource monthCellTemplateSelector}"/>
  </Scheduler:SfScheduler.MonthViewSettings>
 </Scheduler:SfScheduler>
</Grid>

After executing the above code, we will get output like the following image.

Lowest Airfare Calendar Built with the WinUI Scheduler
Lowest Airfare Calendar Built with the WinUI Scheduler

GitHub reference

Refer to the airfare calendar using the WinUI Scheduler demo on GitHub.

Conclusion

Thanks for reading! In this blog, we had a quick overview of designing a calendar to display the lowest airfares using the Syncfusion WinUI Scheduler. Following this example, you can also design fare calendars for booking trains, hotels, and more. Just follow the steps in this blog and enjoy hassle-free ticket booking!

For current customers, the newest version of our WinUI controls is available for download from the License and Downloads page. If you are not yet a Syncfusion customer, you can try our 30-day free trial to see how our components can enhance your projects.

You can also contact us through our support forumsupport portal, or feedback portal. We are happy to assist you!

Related blogs

Be the first to get updates

Jeyasri Murugan

Meet the Author

Jeyasri Murugan

I'm Jeyasri Murugan, a Product Manager at Syncfusion. I have experience in developing custom controls for various .NET frameworks, including .NET MAUI, Xamarin, WPF, WinUI, and UWP.