Add CSS class to DnnModule outer div - dotnetnuke

Is there any way to add a custom class to the outer div that contains the "DnnModule" class that is created when a module is placed on a page via the container? Currently, if I make a container that is to be floated left with a specific width, there is no way to utilize that layout unless I use javascript to go in to the HTML and add my float properties to the DnnModule level div.
For example, if I'm using a scaffolding system (bootstrap) and want to add several containers of different sizes (span3, span6, span12) when I add a module to the content pane with those containers, the layout is ignored due to the outer div that DNN adds around each module. This is extremely limiting from a CSS layout perspective and it forces the skin developer to create many individually styled skins rather than a couple skins with multiple containers to allow for more flexibility.

Found an answer on the DotNetNuke.com forums:
<script runat="server">
Private Sub Page_PreRender(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.PreRender
Try
Dim cParent As HtmlGenericControl = CType(Me.Parent, HtmlGenericControl)
cParent.Attributes("class") = cParent.Attributes("class") + " span6"
Catch ex As Exception
End Try
End Sub
</script>
Adding this to the container .ascx file allows me to insert my own specific class to the wrapper div.
Source: http://www.dotnetnuke.com/Resources/Forums/forumid/109/threadid/458919/scope/posts.aspx

C# version:
<script runat="server">
protected void Page_PreRender(object sender, EventArgs e) {
try {
HtmlGenericControl cParent = (HtmlGenericControl) this.Parent;
cParent.Attributes["class"] += " span6";
} catch (Exception ex) {
// do nothing
}
}
</script>

I think that DIV is always added automatically by DNN, and that it always has that DNNModule class, and I don't think there's an extension point for a skin or container to modify it.
Which means I think your best bet is to use jQuery (which, IIRC, is baked into current DNN images), and initial it in the skin .ascx file.
Something like (not tested):
$(".DNNModule").addClass("MyMagicClass");

This is an old question, but today I have a similar problem and at the end I use this other solution triying to add a css class to the body at code behind:
<script runat="server">
protected void Page_PreRender(object sender, EventArgs e)
{
try
{
HtmlGenericControl body = (HtmlGenericControl)Page.FindControl("body");
body.Attributes.Add("class", " fontSize" + Utils.SiteFontSize);
}
catch (Exception)
{
// do nothing
}
}
</script>

Related

How to retrieve the WebBrowser control from the HTMLDocument it contains, in WPF?

My WPF application is creating multiple WebBrowser controls. I know how to manipulate the HtmlDocument within each and also how to handle mouse events on them.
However, from within a mouse event which has a IHTMLEventObj2 object as parameter, how can I retrieve the hosting WebBrowse?
I can get to the document through the srcElement.document but how do I 'navigate up' to the WebBrowser that is hosting this document?
I thought of using a 'Tag' property, but HTMLDocument does not have one.
As a last resort, I probably could use a hash table based on the HtmlDocument object, but this is a bit complicated for such a simple thing ...
Where/how do you get your mouse event and srcElement.document? It seems like javascript.
If true, then I'm pretty sure you can't access the web control from JavaScript, because the web control is not exposed within the DOM tree. You could try to use window.external (or similar) and to expose methods through it, and then have the methods operate on the webbrowser, but that'd be a little convoluted, but I'm sure this way it is possible.
If not true and if you have some mouseevent handler in C#, then simply link the handler with the webbrowser before the event is invoked. Instead of:
// inside your Window/etc:
private int otherData;
private void MyHandler(...args) {
if(otherData > 5)
browser.Navigate("foobar.html");
}
WebBrowser wb = ...;
wb.themouseevent += myhandler; // equivalent to wb.themouseevent += this.myhandler;
use closures or custom objects to expose a handler from an object that will "know" the browser beforewards:
// inside or outside your Window/etc:
class MyHandlersWithSomeData
{
public WebBrowser browser;
public string someContextuaData;
public int otherData;
....
public void MyHandler(...args) {
if(otherData > 5)
browser.Navigate("foobar.html");
}
}
// inside your Window/etc:
WebBrowser wb = ...;
var smartHandler = new MyHandlersWithSomeData{ browser = wb, otherData = 10 };
wb.themouseevent += smartHandler.MyHandler; // note that handler is not from "this" anymore
edit: As you asked, a "simpler" approach would be to use lambdas and closures:
// inside your Window/etc:
private int otherData;
private void JustAMethodNotAHandler(WebBrowser browser, object sender, EventArgs args) {
if(otherData > 5)
browser.Navigate("foobar.html");
}
WebBrowser wb = ...;
wb.themouseevent += (sender, args) => JustAMethodNotAHandler(wb, sender, args);
However there is no magic. Under the hood, it does it almost exactly as the example above with an extra class, so called "closure". This class will store the reference to WebBrowser wb local variable and only thanks to that, when JustAMethodNotAHandler is later called, the wb is still available and passable to that method.
However, since we are now using lambdas ((blah)=>blah syntax) to quickly create the delegate, you must notice two very important things:
JustAMethodNotAHandler is not the handler, it is just a method. The anonymous function created by the lambda will be the actual handler
since the anonymous function is, well, anonymous, you will have a hard time if you ever want to unregister it later. Attempts like:
wb.themouseevent -= (sender, args) => JustAMethodNotAHandler(wb, sender, args);
will not work since each time that line is executed, a new handler is created, totally not equal to the one created with +=

C# WinForms Adding ToolStripMenuItem dynamically. Why does this not work?

I have created an instance of a ToolStripMenuItem and wanted to add it as a submenu to two different menus on my form (to a contextmenu and a menu strip). I know how to get it to work but I am wondering why this doesn't work.
private static string[] parameters = { "itemOne", "itemTwo", "itemThree"};
private void MainForm_Load(object sender, EventArgs e)
{
foreach (string s in parameters)
{
ToolStripMenuItem addThis = new ToolStripMenuItem(s);
existingToolStripMenuItem.DropDownItems.Add(addThis);
existingMenuItem.DropDownItems.Add(addThis);
}
}
I noticed it works fine if I comment out one of the DropDownItems.Add() statements or if I create two separate instances. Why does it do this?
If you learn about the implementation of ToolStripItemCollection.Add, you will find that the second call existingMenuItem.DropDownItems.Add(addThis); removes addThis from existingToolStripMenuItem.DropDownItems.
So learning how to use decompilers such as ILSpy is critical for .NET developers,
http://wiki.sharpdevelop.net/ilspy.ashx
A possible workaround is to create two separate instances as you found out. If you intend to connect the two instances together, you can use ActionList,
http://www.lextm.com/2012/04/packaging-crads-actionlist-for-net-via-nuget/

DotNetNuke throws itself into Quirks mode without changing settings

We've never experienced this before with DNN but sites which have been running for a long time is throwing itself into Quirks mode because the FallBack Skin Doctype has changed to HTML4 (Legacy).
The only thing I am doing differently now is developing directly onto the ASCX file rather than parsing the skin like I have done in the past. I am not going anywhere near the Host Settings during this process.
Any ideas please?
Thanks
If the skin doesn't specify the DocType then DNN looks at the Host Setting for it. So, you can either change it in the host setting (preferred) or specify it in the skin. Using ASCX for defining the skin rather than HTML shouldn't make any difference.
To specify the doctype for the skin, you have two options:
1.) Create a file named, "Your Skin Name".doctype.xml. e.g. myskin.doctype.xml
In the file, put the following:
<SkinDocType>
<![CDATA[<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">]]>
</SkinDocType>
2.) Add the following at the top of your skin
<script runat="server">
Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim skinDocType as Control = Me.Page.FindControl("skinDocType")
If Not skinDocType is Nothing
CType(skinDocType, System.Web.UI.WebControls.Literal).Text="<!DOCTYPE html PUBLIC ""-//W3C//DTD XHTML 1.0 Transitional//EN"" ""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"">"
End If
End Sub
</script>

Silverlight App object Does not exist' Error

name 'App' does not exist in the current context.
How that possible?
Have to note my initialization code is different than MainPage() type, as I converted SketchFlow app into production Silverlight. They instruct you to do init code via System.Windows.Controls.Frame():
private void Application_Startup(object sender, StartupEventArgs e)
{
this.RootVisual = new System.Windows.Controls.Frame() { Source = new Uri("/MyAppScreen.xaml", UriKind.Relative) };
}
public static string ValueFromHome =
"A Value on Home page";
the goal was to set up public var inside App object so I can access it from various screens down the road
Accessing Resource data requires calling App object I believe as in below, is that correct? so this won't help me
string color = App.Current.Resources["customColor"].ToString();
If you are just storing strings, look into using Resource files. Then they can be translated if that ever becomes necessary.
EDIT (to explain the resource file usage): To access the resource, first create a .resx file in your project (let's say you name it MainResource.resx), change the access modifier drop down to public, add your string with Name: ValueFromHome and Value: "A Value on Home page".
Then you can get the value by adding a using to the namespace of the resource if needed and calling it directly like so:
string value = MainResource.ValueFromHome;
I'd be wary of static variables hanging around. Maybe you could use a MainViewModel to store that value. If you really need a static variable create a new static class in your project and put your ValueFromHome property in that class. The App probably isn't available since it is a Silverlight construct and not made to be available to all areas.

SSRS: 2005, CSS not applied on first column

Some of our reports aren't displaying properly in Firefox - the first column lacks any css. After investigating, I'm finding:
<tr>
<td style="HEIGHT:6.93mm" style="...">1st Column</td>
<td style="...">2nd Column</td>
<td style="...">3rd Column</td>
</tr>
When I remove the style="HEIGHT:6.93mm", it renders properly in Firefox.
Per JudyX's post here on Monday, February 13, 2006 11:54 PM:
The first column in reports cannot be styled correctly. The report viewer control requires a “height” be specified for all table rows. Unfortunately, it applies this not to the table-row element, but to the first table-cell within that row. When it applies that as a style attribute, it conflicts with the style that we set elsewhere.
Has anyone found a solution to this?
I can confirm that this still happens with SSRS 2005. Firefox is not the only browser that will not render this as intended by the report designer. Apparently IE7 (and probably IE6) assume the last style attribute to "win" if there are multiple style attributes assigned on an element. IE8 in standards mode and Firefox assume the first style attribute to "win" in this situation. I would assume that all standards compliant browsers will make the same choice as IE8 and Firefox, although our team has not tested this.
I haven't found a solution in terms of a hotfix, but I do have a way to prevent the bad HTML from making it to the browser. OMG Ponies - thanks for posting that link to JudyX's post. Wodeh responded with a good solution about 3/4 of the way down that post - unfortunately, it was not entirely clear how to use the code that was posted.
The approach is to use a response filter on the page that contains the ReportViewer Control. The filter has access to the raw HTML that will be sent to the browser, and that provides the opportunity to modify the HTML directly without having to result to the new first column trick. In our Page_Load method, we set the Response.Filter property with the following code:
protected void Page_Load(object sender, EventArgs e)
{
Response.Filter = new CorrectSSRSIssuesResponseFilter(Response.Filter);
if (!IsPostBack) {
RenderReport();
}
}
The CorrectSSRSIssuesResponseFilter class is defined as follows, and is mostly based off of Wodeh's code from the post. The secret sauce is in the Write() method which uses the RegEx to wipe out the first style attribute:
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
namespace Reports
{
public class CorrectSSRSIssuesResponseFilter : Stream
{
private Stream _sink;
private StringBuilder Output = new StringBuilder();
public CorrectSSRSIssuesResponseFilter(Stream sink)
: base()
{
_sink = sink;
}
public CorrectSSRSIssuesResponseFilter()
: base()
{
_sink = new MemoryStream();
}
public override bool CanRead { get { return true; } }
public override bool CanSeek { get { return true; } }
public override bool CanWrite { get { return true; } }
public override void Flush()
{
_sink.Flush();
}
public override long Length
{
get { return _sink.Length; }
}
public override long Position
{
get
{ return _sink.Position; }
set
{ _sink.Position = value; }
}
public override int Read(byte[] buffer, int offset, int count)
{
return _sink.Read(buffer, offset, count);
}
public override long Seek(long offset, SeekOrigin origin)
{
return _sink.Seek(offset, origin);
}
public override void SetLength(long value)
{
_sink.SetLength(value);
}
public override void Write(byte[] buffer, int offset, int count)
{
string strBuffer = UTF8Encoding.UTF8.GetString(buffer, offset, count);
//A Closing HTML tag indicates the response object has finished recieving the entire content of the page
strBuffer = System.Text.RegularExpressions.Regex.Replace(
strBuffer
, "<TD style=\"[^\"]*\" style=(?<goodStyle>\"[^\"]*\")>"
, "<TD style=${goodStyle}>"
, System.Text.RegularExpressions.RegexOptions.Compiled
);
buffer = System.Text.Encoding.UTF8.GetBytes(strBuffer);
_sink.Write(buffer, offset, buffer.Length);
}
}
}
The solution isn't really a solution; it's a hack.
When the behavior appears, define a new first column. It should have the following attributes:
Empty - no text, no expression, etc
Set the minimum width (0.03125 inches)
If there is border styling on the other cells, style the right border of the new first cell to match while setting white/etc for the others.
This is a CSS styling issue. I have successfully implemented a fix for this in the past using the info from this post:
You basically have to locate the css file for reporting services (by default, located at C:\Program Files\Microsoft SQL Server\MSSQL.3\Reporting Services\ReportManager\Styles\ReportingServices.css on the report server), and add this class rule to it:
.DocMapAndReportFrame
{
min-height: 860px;
}
Try AsyncRendering="true" on the ReportViewer control.
With async rendering the generated HTML does not have two style tags – it uses a sytle tag for the height and all other styles are applied through a class attribute on the td element.
A much more simpler workaround fixed this issue in my case. Just added anoter row below the damaged one and set Visibility:Hidden = True.
Good luck!

Resources