WPF Webbrowser create html file from user input - c#

I'm reading a html using the webbrowser component in WPF. I should let the user to give there own text, upload an image and save it as a .html file.
By this way I can get the tag value:
string myTagValue = (FrameWithinGrid.Document as mshtml.HTMLDocument)
.getElementsByTagName("div")
.OfType<mshtml.IHTMLElement>()
.First()
.innerText;
How can i get the value from a text box and save it as a .html file including a new image?
Need your help. Thank you.
This is the html file:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html lang="ja">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=Shift_JIS">
<title>Welcome to Linguini Party!</title>
<style type="text/css">
* {
margin: 0;
}
html, body {
height: 100%;
font-family: Arial;
background-color: #e1dfe3;
color: #333333;
background-repeat: no-repeat;
}
h1 {
margin-right: 8%;
margin-left: 7%;
font-size: 450%;
text-align: center;
}
h2 {
font-size: 450%;
text-align: center;
color: #8a00ca;
font-style: italic;
}
</style>
</head>
<body id="Imagebg" background="welcome_final1.png">
<div id="container">
<h1 id="text1">Welcome to<br></h1>
<h2 id="text2">Linguini Party!</h2>
</div>
</body>
</html>

One strategy for accomplishing this is to create an html template along the lines of this...
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8" />
<title></title>
</head>
<body id="Imagebg" >
<div id="container">
<h1 id="text1">$$TEXT1$$<br></h1>
<h2 id="text2">$$TEXT2$$</h2>
<img src="$$IMAGELOCATION$$"/>
</div>
</body>
</html>
This template has been instrumented with markers such as $$TEXT1$$. These will be replaced with customized text later.
Include the template as a resource, or as an external file, or wherever. I opt for including it as an embedded resource. Here's the settings...
You don't HAVE to use an embedded resource, you can use the WebBrowser to get the html also. I like using a resource because it avoids exceptions caused by missing or corrupt files.
The next step is easy. Here's a working View Model...
public class ViewModel
{
public string Text1 { get; set; }
public string Text2 { get; set; }
public string ImagePath { get; set; }
public string DestinationName { get; set; }
public void Start()
{
var resourceName = Assembly.GetExecutingAssembly().GetManifestResourceNames().Where(q => q.Contains("Template.html")).FirstOrDefault();
using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName))
{
using (StreamReader reader = new StreamReader(stream))
{
string html = reader.ReadToEnd().Replace("$$TEXT1$$", Text1).Replace("$$TEXT2$$", Text2).Replace("$$IMAGELOCATION$$", ImagePath);
File.WriteAllText(DestinationName, html);
}
}
}
}
The View Model gets the various Text1 (etc) properties set by the caller, and then loads the HTML template and replaces the markers with custom content. Then it uses the static method on File to save it.
You can modify this strategy to use any other type of instrumentation as long as it's consistent. For a more scalable, full-blown solution, I suggest HtmlAgility. I have been using it for years.

Related

RazorEngine throws 'the name model does not exist in the current context' at runtime

I am using RazorEngine package to generate e-mail templates.
Here is the code for the method:
public async Task<string> GetEmailTemplateAsString<T>(string viewName, T model)
{
var templatePath = #$"{Directory.GetCurrentDirectory()}\Views\{viewName}.cshtml";
var template = await File.ReadAllTextAsync(templatePath);
var html = Engine.Razor.RunCompile(template, "weeklySummary", typeof(T), model);
return html;
}
And the view:
#model CourseWork.Core.Models.EmailTemplate.WeeklySummaryModel
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
body {
background-color: lightgoldenrodyellow;
font-family: Verdana, Geneva, Tahoma, sans-serif;
}
.greetings {
text-align: center;
border-bottom: 1px solid lightgray;
}
.main {
display: block;
border-bottom: 1px solid lightgray;
text-align: center;
padding-bottom: 21.28px;
}
ul {
list-style: none;
padding: 0;
margin: 0;
}
li {
display: block;
padding: 10px;
}
</style>
</head>
<body>
<section class="greetings">
<h1>Hello, #Model.User.DisplayName!</h1>
<h3>Here is our weekly summary, specially for you</h3>
</section>
<section class="main">
#foreach (var entry in Model.BoardThreadWithRepliesModels)
{
<h4>#entry.BoardName</h4>
<h5>#entry.ThreadName</h5>
<ul>
#foreach (var reply in entry.Replies)
{
<li>
<span>#reply.UserDisplayName</span>
<p>#reply.Content</p>
<img src="#reply.PicRelatedPath" alt="pic-related" />
</li>
}
</ul>
}
</section>
</body>
</html>
After I run the app, I get CS0103 error with the description stated in the title of the question.
I have tried googling the error message, but, mainly, all the results have been related to IntelliSense not working, which is not my case at all.
UPD:
The calling code:
*Dapper query*
var fullModel = new WeeklySummaryModel
{
User = user,
BoardThreadWithRepliesModels = models
};
return await _emailTemplateHelper.GetEmailTemplateAsString("WeeklySummary", fullModel);
UPD2:
The exception stated that there is an issue on line 14 char 18. It turned out to be situated in auto-generated code:
// <auto-generated/>
#pragma warning disable 1591
namespace CompiledRazorTemplates.Dynamic
{
#line hidden
using System.Threading.Tasks;
using System;
using System.Collections.Generic;
using System.Linq;
internal class RazorEngine_00fefb8ea0984fabaf601e182158fa32 : RazorEngine.Templating.TemplateBase<dynamic>
{
#pragma warning disable 1998
public async override global::System.Threading.Tasks.Task ExecuteAsync()
{
Write(model);
WriteLiteral(#" CourseWork.Core.Models.EmailTemplate.WeeklySummaryModel
<html lang=""en"">
<head>
<meta charset=""UTF-8"">
<meta http-equiv=""X-UA-Compatible"" content=""IE=edge"">
<meta name=""viewport"" content=""width=device-width, initial-scale=1.0"">
<title>Document</title>
<style>
body {
background-color: lightgoldenrodyellow;
font-family: Verdana, Geneva, Tahoma, sans-serif;
}
.greetings {
text-align: center;
border-bottom: 1px solid lightgray;
}
.main {
display: block;
border-bottom: 1px solid lightgray;
text-align: center;
padding-bottom: 21.28px;
}
ul {
list-style: none;
padding: 0;
margin: 0;
}
li {
display: block;
padding: 10px;
}
</style>
</head>
<body>
<section class=""greetings"">
<h1>Hello, ");
Write(Model.User.DisplayName);
WriteLiteral("!</h1>\r\n <h3>Here is our weekly summary, specially for you</h3>\r\n </section>\r\n\r\n <section class=\"main\">\r\n");
foreach (var entry in Model.BoardThreadWithRepliesModels)
{
WriteLiteral(" <h4>");
Write(entry.BoardName);
WriteLiteral("</h4>\r\n <h5>");
Write(entry.ThreadName);
WriteLiteral("</h5>\r\n <ul>\r\n");
foreach (var reply in entry.Replies)
{
WriteLiteral(" <li>\r\n <span>");
Write(reply.UserDisplayName);
WriteLiteral("</span>\r\n <p>");
Write(reply.Content);
WriteLiteral("</p>\r\n <img");
BeginWriteAttribute("src", " src=\"", 1563, "\"", 1590, 1);
WriteAttributeValue("", 1569, reply.PicRelatedPath, 1569, 21, false);
EndWriteAttribute();
WriteLiteral(" alt=\"pic-related\" />\r\n </li>\r\n");
}
WriteLiteral(" </ul>\r\n");
}
WriteLiteral(" </section>\r\n</body>\r\n</html>");
}
#pragma warning restore 1998
}
}
#pragma warning restore 1591
------------- END -----------
RazorEngine is a custom library built on top of Microsoft's Razor view engine. It doesn't have all capabilities you might be familiar with from MVC and Razor pages.
Just drop the #model directive. It should work, but if it doesn't, Visual Studio doesn't help much in the sense of IntelliSense anyway.
This error:
The name 'model' does not exist in the current context
commonly occurs when you try to reference the instance of the model within the template with a lower case m.
As explained here, the type of the model is defined using the lowercase #model but to reference the instance of the model you must use the upper case #Model or Model.
I cannot see nay incorrect reference to the view model in your script, but that doesn't mean it is not there.
Try downgrading the nuget package, the version 3 runtime full exception should contain more information like this:
Errors while compiling a Template.
Please try the following to solve the situation:
* If the problem is about missing/invalid references or multiple defines either try to load
the missing references manually (in the compiling appdomain!) or
Specify your references manually by providing your own IReferenceResolver implementation.
See https://antaris.github.io/RazorEngine/ReferenceResolver.html for details.
Currently all references have to be available as files!
* If you get 'class' does not contain a definition for 'member':
try another modelType (for example 'null' to make the model dynamic).
NOTE: You CANNOT use typeof(dynamic) to make the model dynamic!
Or try to use static instead of anonymous/dynamic types.
More details about the error:
- error: (126, 58) The name 'model' does not exist in the current context
Temporary files of the compilation can be found in (please delete the folder):
...
It should contain the line number and character number of the incorrect reference as well as the temporary file location where the template was being compiled.

ASP.NET MVC FileContentResult inline PDF filename not showing in browser title

.NET Framework 4.7.2 MVC project
I have a controller action that dynamically loads a PDF to return inline to the browser. Everything is working, except the filename is not showing in the browser title bar or the tab. Instead, the browser is showing the value of the "id" parameter, presumably because it follows the last slash.
I need the browser to display the PDF filename, so that users will know what PDF they are viewing. Our users tend to have multiple PDFs open in tabs and switch between them frequently. This is a simplified version of the code:
public FileContentResult ViewPDF(int id)
{
byte[] pdfContents = loadPDF(id);
string filename = getPDFFilename(id);
var cd = new ContentDisposition
{
FileName = filename,
Inline = true
};
Response.AddHeader("Content-Disposition", cd.ToString());
string returnContentType = MimeMapping.GetMimeMapping(filename);
return File(pdfContents, returnContentType);
}
I have also tried a FileStream with no luck and have tried Edge, IE, and Chrome, but they all do the same. In Chrome, when I Save the PDF, it does save with the correct filename but just won't show it in the browser.
This isn't the ideal solution, but I ended up creating a new View page that contains a full-screen <iframe> that loads the PDF inline. This way I could at least display the PDF name in the page title, which appears in the tab.
Similar to this:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>#ViewData["Title"]</title>
<style type="text/css">
body, html {
width: 100%;
height: 100%;
overflow: hidden;
margin: 0;
}
.pdfFrame {
width: 100%;
height: 100%;
border: none;
}
</style>
</head>
<body class="nomargins">
<iframe class="pdfFrame" src="#Url.Action("GetPDF", new { id = ViewBag.pdfID })" frameBorder="0"></iframe>
</body>
</html>

Setting HTML5 draggable attribute from codebehind not working?

I have an table generated from the code-behind and have tried applying the HTML5 draggable attribute to its table cells.
TabCell.Attributes["draggable"] = "true";
The above applies the attribute successfully as I can see it in inspect element but the element doesn't drag.
Does anyone have any idea's why this may be?
I had to set draggable through JQuery on the element.
$('#myid').draggable();
Doesn't work when the attribute is applied server-side
It's not entirely clear from your question what TabCell is, but assuming it's just a clientside HTML element you want to do:
TabCell.setAttribute("draggable", "true");
You don't need JQuery. Here is some code with two tabs, both made draggable by setting the attribute as above.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<style>
.tab {
overflow: hidden;
border: 1px solid #ccc;
background-color: #f1f1f1;
}
.tab button {
background-color: inherit;
float: left;
border: none;
outline: none;
cursor: pointer;
padding: 14px 16px;
transition: 0.3s;
}
.tab button:hover {
background-color: #ddd;
}
</style>
</head>
<body>
<div class="tab">
<button id="TabCell1">Tab1 Header</button>
<button id="TabCell2">Tab2 Header</button>
</div>
<script>
window.onload = () => {
var TabCell = document.getElementById('TabCell1');
TabCell.setAttribute("draggable", "true");
var TabCell2 = document.getElementById('TabCell2');
TabCell2.setAttribute("draggable", "true");
};
</script>
</body>
</html>

How can I center a image in a HTML created by HtmlAgilityPack

I have a very simple HTML document created with the HtmlAgilityPack, with a embedded image; (base64 format)
Public Report As New HtmlDocument()
Dim html As String = "<!DOCTYPE html>
<html>
<body>
<img src=""data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAANUAAADICAIAAADwajORAAAAAXNSR0IArs4c6QAAAARn"" alt=""Red dot"" align=""middle""/>
</body>
</html> "
Report.LoadHtml(html)
WebBrowser1.DocumentText = Report.Text
The image displays on the left, I'd like to horizontally center it, how can this be done?
(The actual base64 image is shortened for obvious reasons)
The answer I was looking for was:
With the HtmlAgilityPack you can embed the CCS insite the HTLM like so:
Dim html As String = "<!DOCTYPE html>
<html>
<body>
<head><style>html, body {
height: 100%;
margin:0;
padding:0;
}
.center {
display: block;
margin-left: auto;
margin-right: auto;
}
</style></head>
<div>
<img src=""data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAANUAAADICAIAAADwajORA"" alt=""Red dot"" class=""center""/>
</div>
</body>
</html> "
Thanks to Mortb for pointing me in the right direction.
give the image style of
img{
display:block;
margin:auto;
}
or you can put the image inside a div tag and give the div this style:
div{
width:; ==> give it any width you want
height:; ==> give it any height want
margin:auto;
}
In HTML images behave like text, so to center an image horizontally all you really need to do is add a div around it which centers all text:
<div style="text-align: center">
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAANUAAADICAIAAADwajORAAAAAXNSR0IArs4c6QAAAARn" alt="Red dot"/>
</div>
No special CSS workarounds needed.

Highlight 2 places in a single map without using search box [duplicate]

This question already has answers here:
Add "Search Area" outline onto google maps result
(5 answers)
Closed 5 years ago.
I want to highlight 2 places in google maps like the image below(could not show two places highlighted, i have just shown the border style that i will implement).
I want to show border of place exactly like the image below.
I want to dynamically mark places based on place name.
For example I don't have lat long values so ,so I have to search by name of
place.
Right now, to do this using the Google Maps Javascript API, you'll need external data to show the borders of each place. Having it internal to the Javascript API is already being requested here in Google's Issue Tracker: https://issuetracker.google.com/issues/35816953
As a workaround though, you can use the Maps Embed API to mimic the behavior you outlined in your post.
Here's a sample:
Be sure to replace YOUR_API_KEY_HERE with your own API key.
var input = document.getElementById('location');
var autocomplete;
function initPlaces() {
autocomplete = new google.maps.places.Autocomplete(input);
autocomplete.addListener('place_changed', function() {
var place = autocomplete.getPlace();
if (!place.geometry) {
alert('Error with your search for ' + place.name);
}
if(place.place_id) {
markLocation(place.place_id);
}
})
}
function markLocation(placeId) {
var url = 'https://www.google.com/maps/embed/v1/place?key=AIzaSyCD0rWgXRVBa7PgaTWXVp_gU51pgHGviYY';
var placeStr = '&q=place_id:';
var iframe = document.getElementById('iframe');
placeStr += placeId;
url += placeStr;
iframe.src = url;
}
var onSubmitHandler = function(e) {
e.preventDefault();
//markLocation();
}
document.getElementById('form').addEventListener('submit', onSubmitHandler);
input {
height: 2rem;
border-radius: 2px;
border-style: none;
border: 1px solid #e2e2e2;
padding-left: 1rem;
}
.places {
height: 100px;
}
#map {
height: 100%;
}
#location {
width: 400px;
}
.map-frame {
width: 100%;
height: 500px;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<div class="places">
<form id="form" autocomplete="off">
<input id="location" type="text" placeholder="Enter a location">
</form>
</div>
<div class="map-frame">
<!-- Be sure to replace YOUR_API_KEY_HERE with your actual API key -->
<iframe width="100%" id="iframe" height="100%"frameborder="0" style="border:0"
src="https://www.google.com/maps/embed/v1/place?q=place_id:ChIJ-QB6d6K5lzMRxi-hKfTINm0&key=YOUR_API_KEY_HERE" allowfullscreen></iframe>
</div>
<!-- Be sure to replace YOUR_API_KEY_HERE with your actual API key -->
<script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY_HERE&libraries=places&callback=initPlaces" async defer></script>
</body>
</html>
An external jsbin link here as well if you want to try it out: jsbin
Here's the documentation of the Maps Embed API in case you want to pursue that track: https://developers.google.com/maps/documentation/embed/start
Hope that helps!

Categories