Thanks for the great package. As per the specificaiton your system "Currently
only handles textboxes, checkboxes, radio buttons, and dropdown lists.
Other controls will render and work fine, but they need to be handled
in code to update profile."
I need to handle the following data types:
Boolean (renders a checkbox) Google maps datatype Multiple select boxes Upload
All render fine on the page, but the data is not saved. Please could you advise as to how to add support for these...
Thanks, am I right in saying that I need to add a case for each of the data types somthing like:
case "umbraco.editorControls.xxxxxxxxx": { var xxxxxxxxx= new TextBox { ID = string.Format("editor{0}", propertyType.Alias), Text = Convert.ToString(propertyValue) }; xxxxxxxxx.TextChanged += this.Editor_TextChanged; xxxxxxxxx.Enabled = _currentMemberType.MemberCanEdit(propertyType); propertyPanel.Controls.Add(xxxxxxxxx); } break;
In some cases will need to add a region to handle the data:
#region ... for textbox controls
/// <summary> /// Handles the TextChanged event of the ProfileEditor control. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param> private void Editor_TextChanged(object sender, EventArgs e) { var alias = ((TextBox) sender).ID.Replace("editor", ""); var value = ((TextBox) sender).Text;
CurrentProfile.SetProperty(alias, value); }
#endregion
How would I go about handling an image upload (ideally including an auto resize, I have imagegen installed)
Sorry for the questions, but am fairly new to Umbraco / .Net
Daniel, finally tidied up the bits on the file upload, here are the changes I made the to the source.
Added XMLGenerate to the save method to force the XML to update.
public static bool Save() { try { Profile.Save(); // MV addition Make the changes visible Member _MvCurrentMember = Member.GetCurrentMember(); _MvCurrentMember.XmlGenerate(new XmlDocument()); _MvCurrentMember.Save(); // end addition return true; } catch (Exception) { return false; } }
Added the following to AssignEditorEvent to assign events to these data types:
case "umbraco.editorControls.dropdownMultiple": //mv added this ((ListControl)editor).SelectedIndexChanged += new EventHandler(this.Editor_SelectedIndexChangedMulti); if (this.InDebug) { Literal literal4 = new Literal { Text = string.Format("<p>Event assigned to {0} as MultiListControl</p>", editor.ID) }; this.tabpagecontainer.Controls.Add(literal4); } return;
case "umbraco.editorControls.uploadField": //mv added this ((uploadField)editor).Init += new EventHandler(this.Editor_UploadChanged); if (this.InDebug) { Literal literal5 = new Literal { Text = string.Format("<p>Event assigned to {0} as Upload Control</p>", editor.ID) }; this.tabpagecontainer.Controls.Add(literal5); } return;
if (IsPostBack) { // Clear data, this is to see if the checkbox to remove the file was selected if (Page.Request[uf.ClientID + "clear"] == "1") { // delete file deleteFile(CurrentProfile.GetProperty(alias).ToString()); // clear the profile value CurrentProfile.SetProperty(alias, null);
}
if (uf.PostedFile.ContentLength > 0) {
//get the file name of the posted file, prefix with member id to avoid any issues with duplicate file names between members string filename = Member.GetCurrentMember().Id.ToString() + "_" + System.IO.Path.GetFileName(uf.PostedFile.FileName); var ext = filename.Substring(filename.LastIndexOf(".") + 1, filename.Length - filename.LastIndexOf(".") - 1).ToLower();
//only save the file if the file type matches the allowed types if (",jpeg,jpg,gif,png,".IndexOf("," + ext + ",") > -1) {
// Check if image and then get sizes, make thumb and update database if (",jpeg,jpg,gif,bmp,png,tiff,tif,".IndexOf("," + ext + ",") > -1) { int fileWidth; int fileHeight;
FileStream fs = new FileStream(_fullFilePath, FileMode.Open, FileAccess.Read, FileShare.Read);
private void generateThumbnail(System.Drawing.Image image, int maxWidthHeight, int fileWidth, int fileHeight, string fullFilePath, string ext, string thumbnailFileName) { // Generate thumbnail float fx = (float)fileWidth / (float)maxWidthHeight; float fy = (float)fileHeight / (float)maxWidthHeight; // must fit in thumbnail size float f = Math.Max(fx, fy); //if (f < 1) f = 1; int widthTh = (int)Math.Round((float)fileWidth / f); int heightTh = (int)Math.Round((float)fileHeight / f);
// fixes for empty width or height if (widthTh == 0) widthTh = 1; if (heightTh == 0) heightTh = 1;
// Create new image with best quality settings Bitmap bp = new Bitmap(widthTh, heightTh); Graphics g = Graphics.FromImage(bp); g.SmoothingMode = SmoothingMode.HighQuality; g.InterpolationMode = InterpolationMode.HighQualityBicubic; g.PixelOffsetMode = PixelOffsetMode.HighQuality;
// Copy the old image to the new and resized Rectangle rect = new Rectangle(0, 0, widthTh, heightTh); g.DrawImage(image, rect, 0, 0, image.Width, image.Height, GraphicsUnit.Pixel);
// Copy metadata ImageCodecInfo[] codecs = ImageCodecInfo.GetImageEncoders(); ImageCodecInfo codec = null; for (int i = 0; i < codecs.Length; i++) { if (codecs[i].MimeType.Equals("image/jpeg")) codec = codecs[i]; }
// Set compresion ratio to 90% EncoderParameters ep = new EncoderParameters(); ep.Param[0] = new EncoderParameter(Encoder.Quality, 90L);
// Save the new image bp.Save(thumbnailFileName, codec, ep); bp.Dispose(); g.Dispose();
}
private void deleteFile(string file) { if (file.Length > 0) { // delete old file if (System.IO.File.Exists(System.Web.HttpContext.Current.Server.MapPath(file))) System.IO.File.Delete(System.Web.HttpContext.Current.Server.MapPath(file));
Handling other control / data types
Thanks for the great package. As per the specificaiton your system "Currently only handles textboxes, checkboxes, radio buttons, and dropdown lists. Other controls will render and work fine, but they need to be handled in code to update profile."
I need to handle the following data types:
Boolean (renders a checkbox)
Google maps datatype
Multiple select boxes
Upload
All render fine on the page, but the data is not saved. Please could you advise as to how to add support for these...
Thanks
Thanks for the Kudos.
Haven't had any time to work on an update to this package to include support for other datatypes.
The idea for the package was a simple profile editor.. was needed for a client.. I've had ideas to update the code and refine the UI.
I'll post the source on the project page; that'll allow you to look into handling the other datatypes.
Wow.. it has been awhile since I worked on this.. the source is on codeplex.. download it and have a look.
Thanks, am I right in saying that I need to add a case for each of the data types somthing like:
case "umbraco.editorControls.xxxxxxxxx":
{
var xxxxxxxxx= new TextBox
{
ID = string.Format("editor{0}", propertyType.Alias),
Text = Convert.ToString(propertyValue)
};
xxxxxxxxx.TextChanged += this.Editor_TextChanged;
xxxxxxxxx.Enabled = _currentMemberType.MemberCanEdit(propertyType);
propertyPanel.Controls.Add(xxxxxxxxx);
}
break;
In some cases will need to add a region to handle the data:
#region ... for textbox controls
/// <summary>
/// Handles the TextChanged event of the ProfileEditor control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
private void Editor_TextChanged(object sender, EventArgs e)
{
var alias = ((TextBox) sender).ID.Replace("editor", "");
var value = ((TextBox) sender).Text;
CurrentProfile.SetProperty(alias, value);
}
#endregion
How would I go about handling an image upload (ideally including an auto resize, I have imagegen installed)
Sorry for the questions, but am fairly new to Umbraco / .Net
Thanks
Looking closer at the source code it seems the code from codeplex is different to the package code I have:
Code from the .ascx file installed with the project:
<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="ProfileEditor.ascx.cs" Inherits="Dascoba.Umb.ProfileEditor.Editor" %>
<asp:ScriptManager ID="ScriptManager1" runat="server">
</asp:ScriptManager>
<link rel='stylesheet' href='/umbraco_client/propertypane/style.css' />
<p>
<asp:Button ID="UpdateButton" runat="server" Text="Update Profile" OnClick="UpdateButton_Click"
OnClientClick="javascript:return confirm('Are you sure you wish to update your profile?');" />
<asp:Literal ID="litStatus" runat="server"></asp:Literal>
</p>
<asp:Panel CssClass="tabpagecontainer" ID="tabpagecontainer" runat="server" />
Code from same file on codeplex:
<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="ProfileEditor.ascx.cs"
Inherits="Dascoba.Umb.ProfileEditor.Editor" %>
<%@ Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit" TagPrefix="ajax" %>
<link rel='stylesheet' href='/umbraco_client/menuicon/style.css' />
<link rel='stylesheet' href='/umbraco_client/propertypane/style.css' />
<link rel='stylesheet' href='/umbraco_client/datepicker/aqua/theme.css' />
<asp:ScriptManager ID="ScriptManager1" runat="server">
</asp:ScriptManager>
<p>
<asp:Button ID="btnUpdate" runat="server" Text="Update Profile" OnClick="btnUpdate_Click" />
<asp:Literal ID="litStatus" runat="server"></asp:Literal>
</p>
<ajax:ConfirmButtonExtender runat="server" ID="updateConfirm" TargetControlID="btnUpdate"
ConfirmOnFormSubmit="true" ConfirmText="You are about to update your profile.">
</ajax:ConfirmButtonExtender>
<ajax:TabContainer runat="server" ID="TabContainer1" Width="100%" Height="400px"
ScrollBars="Auto" OnInit="TabContainer1_Init">
</ajax:TabContainer>
Ideally I just want the source code to match the project files.
Also noticed this discussion http://umbracoprofileeditor.codeplex.com/discussions/205859 with a suggested fix to handle all data types - Hoping to use this, but not sure about working with the different code?
Any chance I could have the source to match the package?
Just to clarify, I have installed the following package:
Compatible with: Version 4.5.x with the new schema
The source on codeplex might be outdated... I'll have to get back to you on that.
Daniel, finally tidied up the bits on the file upload, here are the changes I made the to the source.
Added XMLGenerate to the save method to force the XML to update.
public static bool Save()
{
try
{
Profile.Save();
// MV addition Make the changes visible
Member _MvCurrentMember = Member.GetCurrentMember();
_MvCurrentMember.XmlGenerate(new XmlDocument());
_MvCurrentMember.Save();
// end addition
return true;
}
catch (Exception)
{
return false;
}
}
Added the following to AssignEditorEvent to assign events to these data types:
case "umbraco.editorControls.dropdownMultiple": //mv added this
((ListControl)editor).SelectedIndexChanged += new EventHandler(this.Editor_SelectedIndexChangedMulti);
if (this.InDebug)
{
Literal literal4 = new Literal
{
Text = string.Format("<p>Event assigned to {0} as MultiListControl</p>", editor.ID)
};
this.tabpagecontainer.Controls.Add(literal4);
}
return;
case "umbraco.editorControls.uploadField": //mv added this
((uploadField)editor).Init += new EventHandler(this.Editor_UploadChanged);
if (this.InDebug)
{
Literal literal5 = new Literal
{
Text = string.Format("<p>Event assigned to {0} as Upload Control</p>", editor.ID)
};
this.tabpagecontainer.Controls.Add(literal5);
}
return;
Added the following to support the above:
private void Editor_SelectedIndexChangedMulti(object sender, EventArgs e)
{
string alias = ((ListControl)sender).ID.Replace("editor", "");
//string selectedValue = ((ListControl)sender).SelectedValue;
string selectedValue = "";
for (int intLoopIndex = 0; intLoopIndex <= ((ListControl)sender).Items.Count - 1; intLoopIndex++)
{
if (((ListControl)sender).Items[intLoopIndex].Selected)
{
if (selectedValue.Length > 0) {
selectedValue += ",";
}
selectedValue += ((ListControl)sender).Items[intLoopIndex].Value;
}
}
CurrentProfile.SetProperty(alias, selectedValue);
}
private void Editor_UploadChanged(object sender, EventArgs e)
{
uploadField uf = ((uploadField)sender);
string alias = uf.ID.Replace("editor", "");
if (IsPostBack)
{
// Clear data, this is to see if the checkbox to remove the file was selected
if (Page.Request[uf.ClientID + "clear"] == "1")
{
// delete file
deleteFile(CurrentProfile.GetProperty(alias).ToString());
// clear the profile value
CurrentProfile.SetProperty(alias, null);
}
if (uf.PostedFile.ContentLength > 0)
{
//get the file name of the posted file, prefix with member id to avoid any issues with duplicate file names between members
string filename = Member.GetCurrentMember().Id.ToString() + "_" + System.IO.Path.GetFileName(uf.PostedFile.FileName);
var ext = filename.Substring(filename.LastIndexOf(".") + 1, filename.Length - filename.LastIndexOf(".") - 1).ToLower();
//only save the file if the file type matches the allowed types
if (",jpeg,jpg,gif,png,".IndexOf("," + ext + ",") > -1) {
string _fullFilePath = System.Web.HttpContext.Current.Server.MapPath(umbraco.GlobalSettings.Path + "/../media/member_upload/" + filename);
uf.PostedFile.SaveAs(_fullFilePath);
CurrentProfile.SetProperty(alias, "/media/member_upload/" + filename);
// Check if image and then get sizes, make thumb and update database
if (",jpeg,jpg,gif,bmp,png,tiff,tif,".IndexOf("," + ext + ",") > -1)
{
int fileWidth;
int fileHeight;
FileStream fs = new FileStream(_fullFilePath,
FileMode.Open, FileAccess.Read, FileShare.Read);
System.Drawing.Image image = System.Drawing.Image.FromStream(fs);
fileWidth = image.Width;
fileHeight = image.Height;
fs.Close();
// Generate thumbnails
string fileNameThumb = _fullFilePath.Replace("." + ext, "_thumb");
generateThumbnail(image, 100, fileWidth, fileHeight, _fullFilePath, ext, fileNameThumb + ".jpg");
image.Dispose();
}
}
}
}
}
private void generateThumbnail(System.Drawing.Image image, int maxWidthHeight, int fileWidth, int fileHeight, string fullFilePath, string ext, string thumbnailFileName)
{
// Generate thumbnail
float fx = (float)fileWidth / (float)maxWidthHeight;
float fy = (float)fileHeight / (float)maxWidthHeight;
// must fit in thumbnail size
float f = Math.Max(fx, fy); //if (f < 1) f = 1;
int widthTh = (int)Math.Round((float)fileWidth / f); int heightTh = (int)Math.Round((float)fileHeight / f);
// fixes for empty width or height
if (widthTh == 0)
widthTh = 1;
if (heightTh == 0)
heightTh = 1;
// Create new image with best quality settings
Bitmap bp = new Bitmap(widthTh, heightTh);
Graphics g = Graphics.FromImage(bp);
g.SmoothingMode = SmoothingMode.HighQuality;
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
g.PixelOffsetMode = PixelOffsetMode.HighQuality;
// Copy the old image to the new and resized
Rectangle rect = new Rectangle(0, 0, widthTh, heightTh);
g.DrawImage(image, rect, 0, 0, image.Width, image.Height, GraphicsUnit.Pixel);
// Copy metadata
ImageCodecInfo[] codecs = ImageCodecInfo.GetImageEncoders();
ImageCodecInfo codec = null;
for (int i = 0; i < codecs.Length; i++)
{
if (codecs[i].MimeType.Equals("image/jpeg"))
codec = codecs[i];
}
// Set compresion ratio to 90%
EncoderParameters ep = new EncoderParameters();
ep.Param[0] = new EncoderParameter(Encoder.Quality, 90L);
// Save the new image
bp.Save(thumbnailFileName, codec, ep);
bp.Dispose();
g.Dispose();
}
private void deleteFile(string file)
{
if (file.Length > 0)
{
// delete old file
if (System.IO.File.Exists(System.Web.HttpContext.Current.Server.MapPath(file)))
System.IO.File.Delete(System.Web.HttpContext.Current.Server.MapPath(file));
string extension = ((string)file.Substring(file.LastIndexOf(".") + 1, file.Length - file.LastIndexOf(".") - 1));
extension = extension.ToLower();
//check for thumbnails
if (",jpeg,jpg,gif,bmp,png,tiff,tif,".IndexOf("," + extension + ",") > -1)
{
//delete thumbnails
string thumbnailfile = file.Replace("." + extension, "_thumb");
try
{
if (System.IO.File.Exists(System.Web.HttpContext.Current.Server.MapPath(thumbnailfile + _thumbnailext)))
System.IO.File.Delete(System.Web.HttpContext.Current.Server.MapPath(thumbnailfile + _thumbnailext));
}
catch { }
if (_thumbnails != "")
{
string[] thumbnailSizes = _thumbnails.Split(";".ToCharArray());
foreach (string thumb in thumbnailSizes)
{
if (thumb != "")
{
string thumbnailextra = thumbnailfile + "_" + thumb + _thumbnailext;
try
{
if (System.IO.File.Exists(System.Web.HttpContext.Current.Server.MapPath(thumbnailextra)))
System.IO.File.Delete(System.Web.HttpContext.Current.Server.MapPath(thumbnailextra));
}
catch { }
}
}
}
}
}
}
This does require the source that was used for the package I listed above.
Im sure that there are more efficiant ways of handling the file upload, but this works!
Thanks Mark
is working on a reply...