enter image description here I am creating a chat program in the wpf environment. If I type in English, the font doesn't break, but if I type in letters other than English, it breaks
Why is it breaking?
Where you converted the message
public string ReadMessage()
{
byte[] msgBuffer;
var length = ReadInt32();
msgBuffer = new byte[length];
_ns.Read(msgBuffer, 0, length);
var msg = Encoding.Default.GetString(msgBuffer);
return msg;
}
So I gave a value of 1024 to the length, and the text didn't break,
but why it didn't break when I put the value of 1024
And when the value 1024 is given, the text appears on the console,
but only username appears on the mainwindow screen, and can't see the message I sent
Where to Show Converted Messages
public Client(TcpClient client)
{
ClientSocket = client;
UID = Guid.NewGuid();
_packetReader = new PacketReader(ClientSocket.GetStream());
var opcode = _packetReader.ReadByte();
Username = _packetReader.ReadMessage();
Console.WriteLine($"[{DateTime.Now}]: Client {Username} sucess to acess:");
Task.Run(() => Process());
}
void Process()
{
while (true)
{
try
{
var opcode = _packetReader.ReadByte();
switch (opcode)
{
case 5:
var msg = _packetReader.ReadMessage();
Console.WriteLine($"[{DateTime.Now}]: from {Username} {msg}");
Program.BroadcastMessage($"[{DateTime.Now}]:{Username} {msg}");
break;
default:
break;
}
}
Related
So here's the question. I have a browser that I'm developing using CefSharp, and I'm trying to get the browser to properly authenticate and pass the UserInfo back to the website that's requesting a login. Below is the button that they are clicking on the website:
As it is written now, I catch this login event in the PopUpHandler class which implements the ILifeSpanHandler interface. I catch it specifically in the OnBeforePopup method, and run the default OAuth class that I got off of the internet. I've modified the OAuth class a bit to implement a custom cefsharp browser pop-up to get the user to input their credentials.
public bool OnBeforePopup(IWebBrowser browserControl, IBrowser browser, IFrame frame, string targetUrl, string targetFrameName,
WindowOpenDisposition targetDisposition, bool userGesture, IPopupFeatures popupFeatures, IWindowInfo windowInfo,
IBrowserSettings browserSettings, ref bool noJavascriptAccess, out IWebBrowser newBrowser)
{
foreach (var allowedSite in Helper.AllowedPopups)
{
if (targetUrl.Contains(allowedSite))
{
if (targetUrl.Contains("login") && targetUrl.Contains("oauth"))
{
OAuth that = new OAuth();
that.AuthorizeWithGoogle();
newBrowser = null;
return true;
}
Helper.OpenNewTab(targetUrl, true);
newBrowser = null;
return true;
}
}
string askingURL = Helper.GetWebsiteName(targetUrl);
AllowPopUpNotifier allowThis = new AllowPopUpNotifier(askingURL);
if (allowThis.ShowDialog() == true)
{
Helper.AllowedPopups.Add(askingURL);
if (targetUrl.Contains("login") && targetUrl.Contains("oauth"))
{
var newPopUpWindow = new CustomPopUpWindow(targetUrl);
newPopUpWindow.Show();
newBrowser = null;
return true;
}
Helper.OpenNewTab(targetUrl, true);
newBrowser = null;
return true;
}
else
{
newBrowser = null;
return true;
}
}
Then, the OAuth class that I've implemented looks like this:
public class OAuth
{
//client configuration;
const string clientID = "581786658708-elflankerquo1a6vsckabbhn25hclla0.apps.googleusercontent.com";
const string clientSecret = "3f6NggMbPtrmIBpgx-MK2xXK";
//const string clientID = "1020802206989-hsvquqebqgrj8kj4b387lcnosos4manc.apps.googleusercontent.com";
//const string clientSecret = "5k_uICJwwq25oV6-BM22310V";
const string authorizationEndpoint = "https://accounts.google.com/o/oauth2/v2/auth";
const string tokenEndpoint = "https://www.googleapis.com/oauth2/v4/token";
const string userInfoEndpoint = "https://www.googleapis.com/oauth2/v3/userinfo";
//ref http://stackoverflow.com/a/3978040
public static int GetRandomUnusedPort()
{
var listener = new TcpListener(IPAddress.Loopback, 0);
listener.Start();
var port = ((IPEndPoint)listener.LocalEndpoint).Port;
listener.Stop();
return port;
}
public async Task<UserCredential> getUserCredential()
{
UserCredential credential;
string[] scopes = new string[] { }; // user basic profile
//Read client id and client secret from Web config file
credential = await GoogleWebAuthorizationBroker.AuthorizeAsync(
new ClientSecrets
{
ClientId = "1020802206989-hsvquqebqgrj8kj4b387lcnosos4manc.apps.googleusercontent.com",
ClientSecret = "3f6NggMbPtrmIBpgx-MK2xXK"
}, scopes,
"user", CancellationToken.None, new FileDataStore("Auth.Api.Store"));
return credential;
}
public async void AuthorizeWithGoogle()
{
//Generates state and PKCE values.
string state = randomDataBase64url(32);
string code_verifier = randomDataBase64url(32);
string code_challenge = base64urlencodeNoPadding(sha256(code_verifier));
const string code_challenge_method = "S256";
//Creates a redirect URI using an available port on the loopback address.
string redirectURI = string.Format("http://{0}:{1}/", IPAddress.Loopback, GetRandomUnusedPort());
Debug.WriteLine("redirect URI: " + redirectURI);
//Creates an HttpListener to listen for requests on that redirect URI.
var http = new HttpListener();
http.Prefixes.Add(redirectURI);
Debug.WriteLine("Listening..");
http.Start();
//Creates the OAuth 2.0 authorization request.
string authorizationRequest = string.Format("{0}?response_type=code&scope=openid%20profile&redirect_uri={1}&client_id={2}&state={3}&code_challenge={4}&code_challenge_method={5}",
authorizationEndpoint,
Uri.EscapeDataString(redirectURI),
clientID,
state,
code_challenge,
code_challenge_method);
//Opens request in the browser.
//Process.Start(authorizationRequest);
//var newBrowser = new WebBrowser();
var that = new CustomPopUpWindow(authorizationRequest);
//that.browser.Address = authorizationRequest;
//newBrowser.Source = new Uri(authorizationRequest, UriKind.RelativeOrAbsolute);
//newBrowser.Load(authorizationRequest);
//that.Content = newBrowser;
that.Show();
//Waits for the OAuth authorization response.
var context = await http.GetContextAsync();
// Brings this app back to the foreground.
var mainWindow = Helper.GetMainWindow();
Application.Current.Dispatcher.Invoke(() =>
{
mainWindow.Activate();
});
//Sends an HTTP response to the browser.
var response = context.Response;
string responseString = string.Format("<html><head><meta http-equiv='refresh' content='10;url=https://google.com'></head><body>Please return to the app.</body></html>");
var buffer = System.Text.Encoding.UTF8.GetBytes(responseString);
response.ContentLength64 = buffer.Length;
var responseOutput = response.OutputStream;
Task responseTask = responseOutput.WriteAsync(buffer, 0, buffer.Length).ContinueWith((task) =>
{
responseOutput.Close();
http.Stop();
Console.WriteLine("HTTP server stopped.");
});
//Checks for errors.
if (context.Request.QueryString.Get("error") != null)
{
Debug.WriteLine(String.Format("OAuth authorization error: {0}.", context.Request.QueryString.Get("error")));
Helper.GoogleAuthorized = false;
CustomMessageBox.Show("Google login not authorized. Check your login credentials and try again.");
return;
}
if (context.Request.QueryString.Get("code") == null
|| context.Request.QueryString.Get("state") == null)
{
Debug.WriteLine("Malformed authorization response. " + context.Request.QueryString);
Helper.GoogleAuthorized = false;
CustomMessageBox.Show("Google login not authorized. Check your login credentials and try again.");
return;
}
//extracts the code
var code = context.Request.QueryString.Get("code");
var incoming_state = context.Request.QueryString.Get("state");
//Compares the receieved state to the expected value, to ensure that
//this app made the request which resulted in authorization.
if (incoming_state != state)
{
Debug.WriteLine(String.Format("Received request with invalid state ({0})", incoming_state));
Helper.GoogleAuthorized = false;
CustomMessageBox.Show("Google login not authorized. Check your login credentials and try again.");
return;
}
Debug.WriteLine("Authorization code: " + code);
//Starts the code exchange at the Token Endpoint.
performCodeExchange(code, code_verifier, redirectURI);
}
async void performCodeExchange(string code, string code_verifier, string redirectURI)
{
Debug.WriteLine("Exchanging code for tokens...");
//builds the request
string tokenRequestURI = "https://www.googleapis.com/oauth2/v4/token";
string tokenRequestBody = string.Format("code={0}&redirect_uri={1}&client_id={2}&code_verifier={3}&client_secret={4}&scope=&grant_type=authorization_code",
code,
System.Uri.EscapeDataString(redirectURI),
clientID,
code_verifier,
clientSecret
);
//sends the request
HttpWebRequest tokenRequest = (HttpWebRequest)WebRequest.Create(tokenRequestURI);
tokenRequest.Method = "POST";
tokenRequest.ContentType = "application/x-www-form-urlencoded";
tokenRequest.Accept = "Accept=text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
byte[] _byteVersion = Encoding.ASCII.GetBytes(tokenRequestBody);
tokenRequest.ContentLength = _byteVersion.Length;
Stream stream = tokenRequest.GetRequestStream();
await stream.WriteAsync(_byteVersion, 0, _byteVersion.Length);
stream.Close();
try
{
//gets the response
WebResponse tokenResponse = await tokenRequest.GetResponseAsync();
using (StreamReader reader = new StreamReader(tokenResponse.GetResponseStream()))
{
//reads response body
string responseText = await reader.ReadToEndAsync();
Debug.WriteLine(responseText);
//converts to dictionary
Dictionary<string, string> tokenEndpointDecoded = JsonConvert.DeserializeObject<Dictionary<string, string>>(responseText);
string access_token = tokenEndpointDecoded["access_token"];
userinfoCall(access_token);
}
}
catch (WebException ex)
{
if (ex.Status == WebExceptionStatus.ProtocolError)
{
var response = ex.Response as HttpWebResponse;
if (response != null)
{
Debug.WriteLine("HTTP: " + response.StatusCode);
using (StreamReader reader = new StreamReader(response.GetResponseStream()))
{
//reads response body
string responseText = await reader.ReadToEndAsync();
Debug.WriteLine(responseText);
Helper.GoogleAuthorized = false;
CustomMessageBox.Show("Google login not authorized. Check your login credentials and try again.");
return;
}
}
}
}
}
async void userinfoCall(string access_token)
{
Debug.WriteLine("Making API Call to Userinfo...");
//builds the request
string userinfoRequestURI = "https://www.googleapis.com/oauth2/v3/userinfo";
//sends the request
HttpWebRequest userinfoRequest = (HttpWebRequest)WebRequest.Create(userinfoRequestURI);
userinfoRequest.Method = "GET";
userinfoRequest.Headers.Add(string.Format("Authorization: Bearer {0}", access_token));
userinfoRequest.ContentType = "application/x-www-form-urlencoded";
userinfoRequest.Accept = "Accept=text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
//gets the response
WebResponse userinfoResponse = await userinfoRequest.GetResponseAsync();
using (StreamReader userinfoResponseReader = new StreamReader(userinfoResponse.GetResponseStream()))
{
//reads response body
string userinfoResponseText = await userinfoResponseReader.ReadToEndAsync();
Debug.WriteLine(userinfoResponseText);
}
}
/// <summary>
/// Appends the given string to the on-screen log, and the debug console.
/// </summary>
/// <param name = "output" > string to be appended</param>
public void output(string output)
{
//textBoxOutput.Text = textBoxOutput.Text + output + Environment.NewLine;
Console.WriteLine(output);
}
/// <summary>
/// Returns URI-safe data with a given input length.
/// </summary>
/// <param name = "length" > Input length(nb.output will be longer)</param>
/// <returns></returns>
public static string randomDataBase64url(uint length)
{
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
byte[] bytes = new byte[length];
rng.GetBytes(bytes);
return base64urlencodeNoPadding(bytes);
}
/// <summary>
/// Returns the SHA256 hash of the input string.
/// </summary>
/// <param name = "inputStirng" ></ param >
/// < returns ></ returns >
public static byte[] sha256(string inputStirng)
{
byte[] bytes = Encoding.ASCII.GetBytes(inputStirng);
SHA256Managed sha256 = new SHA256Managed();
return sha256.ComputeHash(bytes);
}
/// <summary>
/// Base64url no-padding encodes the given input buffer.
/// </summary>
/// <param name = "buffer" ></ param >
/// < returns ></ returns >
public static string base64urlencodeNoPadding(byte[] buffer)
{
string base64 = Convert.ToBase64String(buffer);
//Converts base64 to base64url.
base64 = base64.Replace("+", "-");
base64 = base64.Replace("/", "_");
//Strips padding.
base64 = base64.Replace("=", "");
return base64;
}
}
}
This gets me the UserInfo, and writes it on the "Debug.WriteLine(userinfoResponseText);" line in the OAuth class. However, I don't know how to redirect it back to the website that initially called the pop-up. Can anybody help? I'm so lost.
In my MainViewModel I have only RelayCommands that open different pages.
Theese commands are like this
Messenger.Default.Send<int>(2015);
ViewModel.ReportViewModel reportVM = new ReportViewModel(report);
Views.ReportView pagReport = new ReportView() { DataContext = reportVM };
ApplicationHelper.NavigationService(pagReport);
in ReportViewModel I have
public ReportViewModel(string report)
{
Messenger.Default.Register<int>(this, Doit);
ShowReport(report);
}
private void Doit(int val)
{
int test = val;//code never touch this line
}
What I'm doing wrong ?
Per my comment above, you're instantiating/newing up reportVM after you send the message. If there isn't an instance of ReportViewModel before the message is sent then that message has no listener.
//Instantiate first:
ViewModel.ReportViewModel reportVM = new ReportViewModel(report);
Views.ReportView pagReport = new ReportView() { DataContext = reportVM };
ApplicationHelper.NavigationService(pagReport);
//Send the message:
Messenger.Default.Send<int>(2015);
I have hundreds of different random URLs coming in, all documents in libs, without any other parameters from different farms and different site collections and sites, goal is to download a file as a binary array from SharePoint.
So e.g. incoming url = http://a.b.c.d.e/f.g/h.i/j/k/l/m.docx .
So how to get the (a) correct site collection root url (b) site root url (c) library root url from this? The only way I now think of is slowly stripping off each part of the url until e.g. .Rootfolder no longer gives an exception... or the other way around slowly adding bits by the first part of the url until rootfolder nog longers gives an exception then query for subwebs etc..
The point is that ClientContext constructor accepts the url of web/site only.
But if the url will be specified in the following format:
http://site/web/documents/file.docx
then the exception System.Net.WebException will occur.
The following example demonstrates how to resolve ClientContext from request Url:
public static class ClientContextUtilities
{
/// <summary>
/// Resolve client context
/// </summary>
/// <param name="requestUri"></param>
/// <param name="context"></param>
/// <param name="credentials"></param>
/// <returns></returns>
public static bool TryResolveClientContext(Uri requestUri, out ClientContext context, ICredentials credentials)
{
context = null;
var baseUrl = requestUri.GetLeftPart(UriPartial.Authority);
for (int i = requestUri.Segments.Length; i >= 0; i--)
{
var path = string.Join(string.Empty, requestUri.Segments.Take(i));
string url = string.Format("{0}{1}", baseUrl, path);
try
{
context = new ClientContext(url);
if (credentials != null)
context.Credentials = credentials;
context.ExecuteQuery();
return true;
}
catch (Exception ex) {}
}
return false;
}
}
Usage
ClientContext context;
if (ClientContextUtilities.TryResolveClientContext(requestUri, out context, null))
{
using (context)
{
var baseUrl = requestUri.GetLeftPart(UriPartial.Authority);
var fileServerRelativeUrl = requestUri.ToString().Replace(baseUrl, string.Empty);
var file = context.Web.GetFileByServerRelativeUrl(fileServerRelativeUrl);
context.Load(file);
context.Load(context.Web);
context.Load(context.Site);
context.ExecuteQuery();
}
}
Since your goal is to download a file, there is pretty straightforward way to accomplish it without parsing url parts.
For example, using WebClient.DownloadFile Method:
private static void DownloadFile(Uri fileUri, ICredentials credentials, string localFileName)
{
using(var client = new WebClient())
{
client.Credentials = credentials;
client.DownloadFile(fileUri, localFileName);
}
}
I have made a working method but it seems elaborate, so any suggestions for improvement are welcome just to "download file if one of the specific columns has value "yes":
public void getDocument(Document doc)
{
// get the filename
Uri uri = new Uri(doc.uri);
doc.filename = "";
doc.filename = System.IO.Path.GetFileName(uri.LocalPath);
//string fullPathWithoutFileName = docUri.Replace(filename, "");
// would also include ?a&b so:
string[] splitDocUri = doc.uri.Split('/');
string fullPathWithoutFileName = "";
for (int i = 0; i < splitDocUri.Length -1; i++)
{
fullPathWithoutFileName += (splitDocUri[i] + '/');
}
// get via "_api/contextinfo" the context info
HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(fullPathWithoutFileName + "_api/contextinfo");
req.Method = "POST";
req.Accept = "application/json; odata=verbose";
req.Credentials = new NetworkCredential(doc.username, doc.password, doc.domain);
req.Headers.Add("X-FORMS_BASED_AUTH_ACCEPTED","f");
req.ContentLength = 0;
BypassCertificateError();
HttpWebResponse rp = (HttpWebResponse)req.GetResponse();
Stream postStream = rp.GetResponseStream();
StreamReader postReader = new StreamReader(postStream);
string results = postReader.ReadToEnd();
// Now parse out some values needs system.web.extensions
JavaScriptSerializer jss = new JavaScriptSerializer();
var d = jss.Deserialize<dynamic>(results);
string formDigestValue = d["d"]["GetContextWebInformation"]["FormDigestValue"];
// the full url to the website e.g. "http://server:7777/level1/level 2"
string webFullUrl = d["d"]["GetContextWebInformation"]["WebFullUrl"];
// the full url to the site collection e.g. "http://server:7777"
string siteFullUrl = d["d"]["GetContextWebInformation"]["SiteFullUrl"];
// now we can create a context
ClientContext ctx = new ClientContext(webFullUrl);
ctx.ExecutingWebRequest +=
new EventHandler<WebRequestEventArgs>(ctx_MixedAuthRequest);
BypassCertificateError();
ctx.AuthenticationMode = ClientAuthenticationMode.Default;
ctx.Credentials = new NetworkCredential(doc.username, doc.password, doc.domain);
// Get the List
Microsoft.SharePoint.Client.File file = ctx.Web.GetFileByServerRelativeUrl(uri.AbsolutePath);
List list = file.ListItemAllFields.ParentList;
ctx.Load(list);
ctx.ExecuteQuery();
// execute a CAML query against it
CamlQuery camlQuery = new CamlQuery();
camlQuery.ViewXml =
"<View><Query><Where><Eq><FieldRef Name='FileLeafRef'/>" +
"<Value Type='Text'>" + doc.filename + "</Value></Eq></Where>" +
"<RowLimit>1</RowLimit></Query></View>";
ListItemCollection listItems = list.GetItems(camlQuery);
ctx.Load(listItems);
try {
ctx.ExecuteQuery();
}
catch
{
// e.g. : no access or the listname as incorrectly deduced
throw;
}
// and now retrieve the items needed
if (listItems.Count == 1)
{
ListItem item = listItems[0];
// some more checking from testColumn to decide if to download yes/no
string testColumn;
if (item.IsPropertyAvailable("testColumn")) {
testColumn = (string)item["testColumn"];
}
FileInformation fileInformation =
Microsoft.SharePoint.Client.File.OpenBinaryDirect(ctx,
(string)item["FileRef"]);
doc.bytes = ReadFully(fileInformation.Stream);
}
else
{
doc.errormessage = "Error: No document found";
}
}
I have a utility that allows the user to take a camera photo and upload it, in addition to another option to upload a file. I've got most of it working, except for the part where I have to convert the webcam image to a jpg prior to upload. The code below has no error but produces invalid image data:
void CaptureImageCompleted(object sender, CaptureImageCompletedEventArgs e)
{
busyIndicator.IsBusy = true;
stopCapture();
capturedImage.ImageSource = e.Result;
ImageTools.ExtendedImage eimg = e.Result.ToImage();
var encoder = new ImageTools.IO.Jpeg.JpegEncoder();
Stream stream = eimg.ToStreamByExtension("jpg");
//DO THIS LATER
//if (stream.Length > 512000)
//{
// eimg = ExtendedImage.Resize(eimg, 240, new NearestNeighborResizer());
// stream = eimg.ToStreamByExtension("jpg");
//}
encoder.Encode(eimg, stream);
BitmapImage bitmap = new BitmapImage();
bitmap.SetSource(stream);
byte[] bytes = new byte[stream.Length];
stream.Read(bytes, 0, (int)stream.Length);
// picture file a class object to be used by uploader
pictureFile.PictureName = "webcam.jpg"; // name will be changed later
pictureFile.PictureStream = bytes;
HtmlPage.Window.Invoke("gotDetails_WebCam", ""); // post page, then come back and do upload
}
Here is what PictureFile looks like:
[DataContract]
public class PictureFile
{
[DataMember]
public string PictureName { get; set; }
[DataMember]
public byte[] PictureStream { get; set; }
}
Can anyone figure out what I'm doing wrong to produce the bytes needed for a jpeg?
good to see that you solved,
here is my running code,
I use png format,there is also file size check.
Maybe it helps s.one else.
dSrvPR is my Domain Service Class instance
photo is an entity object in my EF.
_captureSource.CaptureImageCompleted += ((s, args) =>
{
if (dSrvPR.PR_PATIENTPHOTOs.Count > 0 && photo != null)
{
dSrvPR.PR_PATIENTPHOTOs.Remove(photo);
}
dSrvPR.PR_PATIENTPHOTOs.Clear();
photo = new PR_PATIENTPHOTO();
ImageTools.ExtendedImage eimg=args.Result.ToImage();
var encoder=new ImageTools.IO.Png.PngEncoder();
Stream stream= eimg.ToStreamByExtension("png");
if (stream.Length > 512000)
{
eimg= ExtendedImage.Resize(eimg, 240, new NearestNeighborResizer());
stream = eimg.ToStreamByExtension("png");
}
if (stream.Length <= 512001)
{
BinaryReader binary = new BinaryReader(stream);
//Read bytes from the BinaryReader and put them into a byte array.
Byte[] file = binary.ReadBytes((int)stream.Length);
photo.ID = Guid.NewGuid();
photo.PHOTO = file;
photo.PHOTODATE = DateTime.Now;
photo.ISACTIVE = true;
//some more unrelated fields
dSrvPR.PR_PATIENTPHOTOs.Add(photo);
dSrvPR.SubmitChanges();
//Msg succedded
}
else
{
Util.alert(...,"file size exceeded! :)";
}
});
My mistake. It seems I had some extra code in there (unnecessarily converting stream to bitmap). Here is what I got working:
void CaptureImageCompleted(object sender, CaptureImageCompletedEventArgs e)
{
busyIndicator.IsBusy = true;
stopCapture();
capturedImage.ImageSource = e.Result;
ImageTools.ExtendedImage eimg = e.Result.ToImage();
var encoder = new ImageTools.IO.Jpeg.JpegEncoder();
Stream stream = eimg.ToStreamByExtension("jpg");
byte[] bytes = new byte[stream.Length];
stream.Read(bytes, 0, (int)stream.Length);
// picture file a class object to be used by uploader
pictureFile.PictureName = "webcam.jpg"; // name will be changed later
pictureFile.PictureStream = bytes;
HtmlPage.Window.Invoke("gotDetails_WebCam", ""); // post page, then come back and do upload
}
I'm trying to display a tweet on the backside of a live tile, when I set it as BackContent it's way too big.... Is there any way to lower the font size?
EDIT:
Claus, Now i'm having trouble getting the tile to display and I can't get any info on why it's not working due to the nature of your ImageOpened call, I can't step through it with the debugger....
In my TileGenerator class, this works:
public static void GenerateTestTile(string strTweet, string strScreenName, string tileTitle)
{
// Define the tile's address. This is where you navigate, when the tile is clicked.
var address = "/MainPage.xaml?TileID=6";
// Check if a tile with the same address already exists
//var tile = ShellTile.ActiveTiles.FirstOrDefault(x => x.NavigationUri.ToString() == address);
var tile = ShellTile.ActiveTiles.First();
// Define our tile data.
var tileData = new StandardTileData
{
BackTitle = strScreenName,
BackContent = strTweet
};
// If the file already exists, update it.
if (tile != null)
{
tile.Update(tileData);
}
else
{
// Otherwise, create a new tile.
ShellTile.Create(new Uri(address, UriKind.Relative), tileData);
}
}
But this doesn't (exact method taken from your example), it doesn't do anything to the tile at all...
public static void GenerateExampleTile(string timeOfDay, string temperature, Uri cloudImagePath, string tileTitle)
{
// Setup the font style for our tile.
var fontFamily = new FontFamily("Segoe WP");
var fontForeground = new SolidColorBrush(Colors.White);
var tileSize = new Size(173, 173);
// Create a background rectagle for a custom colour background.
var backgroundRectangle = new Rectangle();
backgroundRectangle.Width = tileSize.Width;
backgroundRectangle.Height = tileSize.Height;
backgroundRectangle.Fill = new SolidColorBrush(Colors.Blue);
// Load our 'cloud' image.
var source = new BitmapImage(cloudImagePath);
source.CreateOptions = BitmapCreateOptions.None;
source.ImageOpened += (sender, e) => // This is important. The image can't be rendered before it's loaded.
{
// Create our image as a control, so it can be rendered to the WriteableBitmap.
var cloudImage = new Image();
cloudImage.Source = source;
cloudImage.Width = 100;
cloudImage.Height = 64;
// TextBlock for the time of the day.
TextBlock timeOfDayTextBlock = new TextBlock();
timeOfDayTextBlock.Text = timeOfDay;
timeOfDayTextBlock.FontSize = 20;
timeOfDayTextBlock.Foreground = fontForeground;
timeOfDayTextBlock.FontFamily = fontFamily;
// Temperature TextBlock.
TextBlock temperatureTextBlock = new TextBlock();
temperatureTextBlock.Text = temperature + '°';
temperatureTextBlock.FontSize = 30;
temperatureTextBlock.Foreground = fontForeground;
temperatureTextBlock.FontFamily = fontFamily;
// Define the filename for our tile. Take note that a tile image *must* be saved in /Shared/ShellContent
// or otherwise it won't display.
var tileImage = string.Format("/Shared/ShellContent/{0}.jpg", timeOfDay);
// Define the path to the isolatedstorage, so we can load our generated tile from there.
var isoStoreTileImage = string.Format("isostore:{0}", tileImage);
// Open the ISF store,
using (IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication())
{
// Create our bitmap, in our selected dimension.
var bitmap = new WriteableBitmap((int)tileSize.Width, (int)tileSize.Height);
// Render our background. Remember the renders are in the same order as XAML,
// so whatever is rendered first, is rendered behind the next element.
bitmap.Render(backgroundRectangle, new TranslateTransform());
// Render our cloud image
bitmap.Render(cloudImage, new TranslateTransform()
{
X = 8, // Left margin offset.
Y = 54 // Top margin offset.
});
// Render the temperature text.
bitmap.Render(temperatureTextBlock, new TranslateTransform()
{
X = 124,
Y = 63
});
// Render the time of the day text.
bitmap.Render(timeOfDayTextBlock, new TranslateTransform()
{
X = 12,
Y = 6
});
// Create a stream to store our file in.
var stream = store.CreateFile(tileImage);
// Invalidate the bitmap to make it actually render.
bitmap.Invalidate();
// Save it to our stream.
bitmap.SaveJpeg(stream, 173, 173, 0, 100);
// Close the stream, and by that saving the file to the ISF.
stream.Close();
}
// Define the tile's address. This is where you navigate, when the tile is clicked.
var address = "/MainPage.xaml?TileID=" + timeOfDay;
// Check if a tile with the same address already exists
var tile = ShellTile.ActiveTiles.FirstOrDefault(x => x.NavigationUri.ToString() == address);
// Define our tile data.
var tileData = new StandardTileData
{
BackgroundImage = new Uri(isoStoreTileImage, UriKind.Absolute),
Title = tileTitle,
};
// If the file already exists, update it.
if (tile != null)
{
tile.Update(tileData);
}
else
{
// Otherwise, create a new tile.
ShellTile.Create(new Uri(address, UriKind.Relative), tileData);
}
};
}
Both methods are being called in this way....
public class ScheduledAgent : ScheduledTaskAgent
{
...
/// <summary>
/// Agent that runs a scheduled task
/// </summary>
/// <param name="task">
/// The invoked task
/// </param>
/// <remarks>
/// This method is called when a periodic or resource intensive task is invoked
/// </remarks>
protected override void OnInvoke(ScheduledTask task)
{
LoadWatchList();
}
//WATCH LIST
private void LoadWatchList()
{
if (HasConnectivity)
{
GetWatchListTweetsFromTwitter(CurrentWatchListID);
}
}
public void GetWatchListTweetsFromTwitter(int list_id)
{
WebClient wcWatchListTimeline = new WebClient();
wcWatchListTimeline.DownloadStringCompleted += new DownloadStringCompletedEventHandler(wcWatchListTimeline_DownloadStringCompleted);
wcWatchListTimeline.DownloadStringAsync(new System.Uri("https://api.twitter.com/1/lists/statuses.xml?per_page=1&list_id=" + list_id));
}
void wcWatchListTimeline_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
String strTweet = "content";
String strScreenName = "title";
if (e.Error != null)
{
strScreenName = "error";
strTweet = e.Error.Message;
}
else
{
XElement tweet = XElement.Parse(e.Result);
Tweet thisTweet = GetTweet(tweet);
if (thisTweet != null)
{
strTweet = thisTweet.text;
strScreenName = thisTweet.screen_name;
}
}
// TAKEN FROM EXAMPLE FOR TESTING - NOT WORKING
string timeOfday = "morning";
string temperature = "99";
string location = "San Antonio";
Uri cloudImagePath = new Uri("Images/tweetEmpty.png", UriKind.Relative);
Deployment.Current.Dispatcher.BeginInvoke(() => TileGenerator.GenerateExampleTile(timeOfday, temperature, cloudImagePath, "mainTile"));
//WORKING
//Deployment.Current.Dispatcher.BeginInvoke(() => TileGenerator.GenerateTile(strTweet, strScreenName, "mainTile"));
NotifyComplete();
}
protected Tweet GetTweet(XElement Xdata)
{
List<Tweet> listTweets = (from tweet in Xdata.Descendants("status")
select new Tweet
{
screen_name = tweet.Element("user").Element("screen_name").Value,
text = tweet.Element("text").Value
}).ToList<Tweet>();
if (listTweets.Count > 0)
{
return listTweets[0];
}
else
{
return null;
}
}
}
Only by creating a custom image, and using that as the background for the tile.
Updated: How To: Live Tile with Scheduled Agent