Deals are redeemable offers that the user can save to the Wallet and later present to a vendor for redemption.
To add a deal to the Wallet, create a new Deal
object and call its SaveAsync
method, as demonstrated:
Deal deal = new Deal(coupon.Id)
{
DisplayName = "10% off!",
Description = "Get 10% any item purchased.",
IssuerName = "Unleashed",
IssuerWebsite = new Uri("http://example.com"),
IsUsed = false,
MerchantName = "Unleashed",
TermsAndConditions = "Valid at participating locations only.",
Code = "123454321",
ExpirationDate = DateTime.Now.AddMonths(3)
};
await deal.SaveAsync();
Note
The DisplayName
property must be set to a non-empty string before calling SaveAsync
, or an exception is raised.
The sample app for this section retrieves a list of available coupons from a WCF service and displays them on a page. The user may select one of the coupons to view it in greater detail and to save it to the Wallet’s Deals area.
The source code for this section is located in the WalletDealsAndMembership directory of the downloadable sample code.
The sample uses a custom class named Coupon
. The CouponsViewModel
retrieves the list of available coupons from the DealsAndMembership
WCF service using the service’s GetCoupons
method.
For the sake of simplicity, the service declares a list of dummy coupons, like so:
readonly List<Coupon> coupons = new List<Coupon>
{
new Coupon
{
Id = "1",
Title = "$25 Off!",
Description = "$25 off your next purchase!",
ExpirationDate = new DateTime(2013, 8, 1),
Terms = "Valid at participating locations only.",
Code = "3425167",
Base64Image = GetBase64ImageCoupon()
}, new Coupon { ... },
new Coupon { ... },
new Coupon { ... },
};
The service retrieves a sample barcode image for each coupon from within the assembly. The service then converts the image to a base-64 encoded string (see Listing 25.11).
Base-64 encoding is a way of taking binary data and turning it into text so that it is easier to transmit. Sending the image encoded in Base-64 prevents the data from being misinterpreted during transmission because raw binary data may contain special control characters.
LISTING 25.11. DealsAndMembershipService.GetBase64CouponImage
Method
static string GetBase64CouponImage()
{
Assembly assembly = Assembly.GetExecutingAssembly();
using (Stream stream = assembly.GetManifestResourceStream(
"DanielVaughan.WPUnleashed.DealsAndMembershipService.Barcode.bmp"))
{
BinaryReader br = new BinaryReader(stream);
byte[] bytes = br.ReadBytes((int)stream.Length);
string result = Convert.ToBase64String(bytes);
return result;
}
}
The CouponsViewModel
retrieves the list of available coupons from the service. The CouponsViewModel.Load
method populates an ObservableList
with the Coupon
objects returned from the DealsAndMembershipService
, as shown in the following excerpt:
public async void Load()
{
var service = (IDealsAndMembershipService)new DealsAndMembershipServiceClient();
try
{
Coupons = await Task<ObservableCollection<Coupon>>.Factory.FromAsync(
service.BeginGetCoupons, service.EndGetCoupons, null);
}
catch (Exception ex)
{
Debug.WriteLine("Unable to retrieve coupons." + ex);
}
}
The CouponsViewModel
contains a DelegateCommand<Coupon>
named ViewCouponCommand
that uses the base class’s INavigationService
to navigate to the CouponView.xaml page, as shown:
void ViewCoupon(Coupon coupon)
{
ArgumentValidator.AssertNotNull(coupon, "coupon");
Navigate("/CouponView/CouponView.xaml?CouponId=" + coupon.Id);
}
The Deals pivot item on the MainPage.xaml displays each coupon within a ListBox
. Tapping an item in the ListBox
executes the viewmodel’s ViewCouponCommand
via the custom commanding infrastructure, as shown:
<phone:PivotItem Header="Deals"
DataContext="{StaticResource couponsViewModel}">
<ListBox ItemsSource="{Binding Coupons}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Margin="12,20,0,0"
c:Commanding.Command="{Binding ViewCouponCommand,
Source={StaticResource couponsViewModel}}"
c:Commanding.CommandParameter="{Binding}">
<TextBlock Text="{Binding Title}"
Style="{StaticResource PhoneTextLargeStyle}" />
<TextBlock Text="{Binding Description}"
Style="{StaticResource PhoneTextSmallStyle}"
Foreground="{StaticResource PhoneSubtleBrush}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</phone:PivotItem>
The CouponView.xaml OnNavigatedTo
method passes the query string dictionary containing the coupon ID to the CouponViewModel
. The viewmodel’s Load
method retrieves the ID from the query string dictionary and uses it to retrieve the Coupon
object from the WCF service. See the following excerpt:
public async void Load(IDictionary<string, string> parameters)
{
string couponId;
if (!parameters.TryGetValue("CouponId", out couponId))
{
return;
}
var service = (IDealsAndMembershipService)
new DealsAndMembershipServiceClient();
try
{
Coupon = await Task<Coupon>.Factory.FromAsync(
service.BeginGetCoupon, service.EndGetCoupon, couponId, null);
}
catch (Exception ex)
{
Debug.WriteLine("Unable to retrieve coupon." + ex);
MessageService.ShowError("Unable to retrieve coupon.");
}
Refresh();
}
The viewmodel converts the coupon’s Base-64 image string to a BitmapImage
and assigns it to the Deal
object’s BarcodeImage
property. The CouponViewModel.AddToWallet
method uses the Base64ToImageConverter
to perform the conversion (see Listing 25.12). You look at this conversion process in more detail in a moment.
The AddToWallet
method copies the coupon properties over to a new Deal
object and saves it to the Wallet using the Deal
class’s SaveAsync
method.
LISTING 25.12. CouponViewModel.AddToWallet
Method
async Task AddToWallet()
{
bool successful = true;
try
{
BitmapImage barcodeImage
= Base64ToImageConverter.ConvertToBitmapImage(
coupon.Base64Image);
Deal deal = new Deal(coupon.Id)
{
BarcodeImage = barcodeImage,
DisplayName = coupon.Title,
Description = coupon.Description,
IssuerName = "Unleashed",
IssuerWebsite = new Uri("http://example.com"),
IsUsed = false,
MerchantName = "Unleashed",
TermsAndConditions = coupon.Terms,
Code = coupon.Code,
ExpirationDate = coupon.ExpirationDate
};
await deal.SaveAsync();
}
catch (Exception ex)
{
successful = false;
Debug.WriteLine(ex.ToString());
MessageService.ShowError("Unable to add deal to wallet.");
}
if (successful)
{
MessageService.ShowMessage("Deal added to wallet.");
}
}
The coupon’s Base64Image
is converted to a BitmapImage
using the custom Base64ToImageConverter
class (see Listing 25.13). The static ConvertToBitmapImage
method accepts a string and converts it to a byte array, which is then used to create a Stream
to initialize a new BitmapImage
object.
The Base64ToImageConverter
is an IValueConverter
, which the view also uses to display the coupon’s barcode image.
LISTING 25.13. Base64ToImageConverter
Class
public class Base64ToImageConverter : IValueConverter
{
public object Convert(object value, Type targetType,
object parameter, System.Globalization.CultureInfo culture)
{
if (value == null)
{
return null;
}
string base64String = value.ToString();
return ConvertToBitmapImage(base64String);
}
public object ConvertBack(object value, Type targetType,
object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
public static BitmapImage ConvertToBitmapImage(string base64EncodedImage)
{
byte[] imageBytes = System.Convert.FromBase64String(base64EncodedImage);
using (MemoryStream stream
= new MemoryStream(imageBytes, 0, imageBytes.Length))
{
BitmapImage bitmapImage = new BitmapImage();
bitmapImage.SetSource(stream);
return bitmapImage;
}
}
}
Figure 25.6 shows a deal displayed in the Wallet. The Wallet retains the barcode image and displays it whenever the user navigates to the deal.
You remove a Deal
from the Wallet in the same way as for other Wallet items: by calling the Wallet class’s static Remove
method with the string ID of the Wallet item, as shown:
Wallet.Remove(coupon.Id);
3.147.79.241