I'm working on a ServerControl (SuperFish Menu).
Below is my codes.
Menu.cs
[AspNetHostingPermission(SecurityAction.Demand, Level = AspNetHostingPermissionLevel.Minimal)]
[AspNetHostingPermission(SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
[ParseChildren(true, "MenuItems")]
[PersistChildren(true)]
[ToolboxData("<{0}:Menu runat=\"server\"></{0}:Menu>")]
public class Menu : WebControl, INamingContainer
{
#region Fields
List<MenuItem> _MenuItems;
#endregion
#region Properties
public VerOrHor VerticalOrHorizontal { get; set; }
public string Main_ul_CssClass { get; set; }
[PersistenceMode(PersistenceMode.InnerDefaultProperty)]
public animation AnimationItems { get; set; }
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
[PersistenceMode(PersistenceMode.InnerDefaultProperty)]
public List<MenuItem> MenuItems
{
get
{
if (_MenuItems == null)
{
_MenuItems = new List<MenuItem>();
}
return _MenuItems;
}
}
string _AnimationType
{
get
{
switch (this.AnimationItems.AnimationType)
{
case AnimationType.Opacity_Height:
return "animation:{opacity:'show',height:'show'}";
case AnimationType.Opacity:
return "animation:{opacity:'show'}";
case AnimationType.Height:
return "animation:{height:'show'}";
default:
return "animation:{opacity:'show',height:'show'}";
}
}
}
string _AnimationSpeed
{
get
{
switch (this.AnimationItems.AnimationSpeed)
{
case AnimationSpeed.Fast:
return "speed:Fast";
case AnimationSpeed.Normal:
return "speed:Normal";
case AnimationSpeed.Slow:
return "speed:Slow";
default:
return "speed:Fast";
}
}
}
#endregion
#region Methods
public override void RenderBeginTag(HtmlTextWriter writer)
{
}
public override void RenderEndTag(HtmlTextWriter writer)
{
}
protected override void AddAttributesToRender(HtmlTextWriter writer)
{
base.AddAttributesToRender(writer);
}
protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);
#region Adding Script & link Tags
HtmlGenericControl jquery = new HtmlGenericControl("script");
jquery.Attributes.Add("type", "text/javascript");
jquery.Attributes.Add("src", Page.ClientScript.GetWebResourceUrl(typeof(Menu), "JQueryMenu.JavaScriptFiles.jquery_1_4_3.js"));
jquery.EnableViewState = false;
Page.Header.Controls.Add(jquery);
HtmlGenericControl hoverIntent = new HtmlGenericControl("script");
hoverIntent.Attributes.Add("type", "text/javascript");
hoverIntent.Attributes.Add("src", Page.ClientScript.GetWebResourceUrl(typeof(Menu), "JQueryMenu.JavaScriptFiles.hoverIntent.js"));
hoverIntent.EnableViewState = false;
Page.Header.Controls.Add(hoverIntent);
HtmlGenericControl jquery_bgiframe_min = new HtmlGenericControl("script");
jquery_bgiframe_min.Attributes.Add("type", "text/javascript");
jquery_bgiframe_min.Attributes.Add("src", Page.ClientScript.GetWebResourceUrl(typeof(Menu), "JQueryMenu.JavaScriptFiles.jquery_bgiframe_min.js"));
jquery_bgiframe_min.EnableViewState = false;
Page.Header.Controls.Add(jquery_bgiframe_min);
HtmlGenericControl superfish = new HtmlGenericControl("script");
superfish.Attributes.Add("type", "text/javascript");
superfish.Attributes.Add("src", Page.ClientScript.GetWebResourceUrl(typeof(Menu), "JQueryMenu.JavaScriptFiles.superfish.js"));
superfish.EnableViewState = false;
Page.Header.Controls.Add(superfish);
HtmlGenericControl supersubs = new HtmlGenericControl("script");
supersubs.Attributes.Add("type", "text/javascript");
supersubs.Attributes.Add("src", Page.ClientScript.GetWebResourceUrl(typeof(Menu), "JQueryMenu.JavaScriptFiles.supersubs.js"));
supersubs.EnableViewState = false;
Page.Header.Controls.Add(supersubs);
HtmlGenericControl csslink = new HtmlGenericControl("link");
csslink.Attributes.Add("href", Page.ClientScript.GetWebResourceUrl
(typeof(Menu), "JQueryMenu.CSS.superfish.css"));
csslink.ID = "NavigationMenu";
csslink.Attributes.Add("type", "text/css");
csslink.Attributes.Add("rel", "stylesheet");
csslink.EnableViewState = false;
Page.Header.Controls.Add(csslink);
if (this.VerticalOrHorizontal == VerOrHor.Vertical)
{
HtmlGenericControl csslink01 = new HtmlGenericControl("link");
csslink01.Attributes.Add("href", Page.ClientScript.GetWebResourceUrl
(typeof(Menu), "JQueryMenu.CSS.superfish-vertical.css"));
csslink01.Attributes.Add("type", "text/css");
csslink01.Attributes.Add("rel", "stylesheet");
csslink01.EnableViewState = false;
Page.Header.Controls.Add(csslink01);
}
#endregion
}
protected override void RenderContents(HtmlTextWriter output)
{
output.Write(CreateMenuHtmlTags().ToString());
}
StringBuilder CreateMenuHtmlTags()
{
if (_MenuItems == null || _MenuItems.Count <= 0)
throw new Exception("Please Fill the control with <MenuItem> tags");
StringBuilder Html = new StringBuilder("");
#region Add <Script>
if (String.IsNullOrEmpty(Main_ul_CssClass))
Html.Append("<script>$(document).ready(function() { $(\"ul.sf-menu\").superfish({pathLevels: 1,");
else
Html.Append("<script>$(document).ready(function() { $(\"ul." + Main_ul_CssClass + "\").superfish({ pathLevels: 1,");
if (AnimationItems == null)
Html.Append("delay:1000, animation:{opacity:'show',height:'show'}, speed:'normal', autoArrows: true, dropShadows: true}); });</script>");
else
{
Html.Append("delay:" + AnimationItems.Delay.Trim() + ",");
Html.Append(_AnimationType + ",");
Html.Append(_AnimationSpeed + ",");
Html.Append("dropShadows: " + AnimationItems.DropShadow.ToString() + ",");
Html.Append(#"autoArrows: false});});</script>");
}
#endregion
if (String.IsNullOrEmpty(Main_ul_CssClass))
Html.Append("<ul class=\"sf-menu sf-js-enabled sf-shadow\" id='sample-menu-1'>");
else
Html.Append("<ul class=\"" + Main_ul_CssClass + "\" id='sample-menu-1'>");
foreach (MenuItem item in _MenuItems)
{
if (item.SubMenuItems != null || item.SubMenuItems.Count > 0)
{
if (!string.IsNullOrEmpty(item.li_CssClass))
Html.Append("<li class=\"" + item.li_CssClass + "\">");
else
Html.Append("<li>");
Html.Append("" + item.Text.Trim() + "");
ParseSubMenuItems(ref Html, item);
Html.Append("</li>");
}
else
Html.Append("<li>" + item.Text.Trim() + "</li>");
}
Html.Append("</ul>");
return Html;
}
void ParseSubMenuItems(ref StringBuilder Html, MenuItem menuItems)
{
if (menuItems == null || menuItems.SubMenuItems.Count == 0) return;
Html.Append("<ul class=\"" + menuItems.ul_CssClass.Trim() + "\" style=\"display: none; visibility: hidden;\">");
foreach (MenuItem item in menuItems.SubMenuItems)
{
if (item.SubMenuItems != null || item.SubMenuItems.Count > 0)
{
if (!string.IsNullOrEmpty(item.li_CssClass))
Html.Append("<li class=\"" + item.li_CssClass + "\">");
else
Html.Append("<li>");
Html.Append("" + item.Text.Trim() + "");
ParseSubMenuItems(ref Html, item);
Html.Append("</li>");
}
else
Html.Append("<li>" + item.Text.Trim() + "</li>");
}
Html.Append("</ul>");
}
#endregion
}
public enum VerOrHor
{
Vertical,
Horizontal
}
public class MenuItemsCollectionEditor : CollectionEditor
{
public MenuItemsCollectionEditor(Type type)
: base(type)
{
}
protected override bool CanSelectMultipleInstances()
{
return false;
}
protected override Type CreateCollectionItemType()
{
return typeof(MenuItem);
}
}
MenuItem.cs
[PersistChildren(true)]
[ParseChildren(true, "SubMenuItems")]
public class MenuItem : Control, INamingContainer
{
#region Fields
List<MenuItem> _SubMenuItems;
#endregion
#region Properties
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
//[Editor(typeof(SubMenuItemsCollectionEditor), typeof(UITypeEditor))]
[PersistenceMode(PersistenceMode.InnerDefaultProperty)]
public List<MenuItem> SubMenuItems
{
get
{
if (_SubMenuItems == null)
{
_SubMenuItems = new List<MenuItem>();
}
return _SubMenuItems;
}
}
[DefaultValue("MenuItem")]
public string Text { get; set; }
[DefaultValue("")]
[Description("<ul /> css class")]
public string ul_CssClass { get; set; }
[DefaultValue("")]
[Description("<li /> css class")]
public string li_CssClass { get; set; }
[DefaultValue("#")]
[Description("<a /> href attribute")]
public string href { get; set; }
[TemplateContainer(typeof(MenuItem))]
[PersistenceMode(PersistenceMode.InnerDefaultProperty)]
public ITemplate Template { get; set; }
#endregion
}
public class SubMenuItemsCollectionEditor : CollectionEditor
{
public SubMenuItemsCollectionEditor(Type type)
: base(type)
{
}
protected override bool CanSelectMultipleInstances()
{
return false;
}
protected override Type CreateCollectionItemType()
{
return typeof(MenuItem);
}
}
animation.cs
public class animation
{
[DefaultValue("1000")]
[NotifyParentProperty(true)]
public string Delay { get; set; }
[DefaultValue("Opacity_Height")]
[NotifyParentProperty(true)]
public AnimationType AnimationType { get; set; }
[DefaultValue("fast")]
[NotifyParentProperty(true)]
public AnimationSpeed AnimationSpeed { get; set; }
[DefaultValue("false")]
[NotifyParentProperty(true)]
public bool DropShadow { get; set; }
}
public enum AnimationType
{
Opacity_Height,
Opacity,
Height
}
public enum AnimationSpeed
{
Fast,
Normal,
Slow
}
It works fine with below code (Without AnimationItems):
<MdsMenu:Menu ID="Menu1" runat="server">
<MdsMenu:MenuItem Text="MenuItem 01"></MdsMenu:MenuItem>
<MdsMenu:MenuItem Text="MenuItem 02"></MdsMenu:MenuItem>
<MdsMenu:MenuItem Text="MenuItem 03" />
</MdsMenu:Menu>
But when I add AnimationItems tag like the following code I receive the Exception :
Exception : Error Creating Control - Menu1Type 'JQueryMenu.Menu' does not have a public property named 'MenuItem'.
<MdsMenu:Menu ID="Menu1" runat="server">
<AnimationItems AnimationSpeed="Fast" AnimationType="Opacity_Height" DropShadow="true" Delay="1000" />
<MdsMenu:MenuItem Text="MenuItem 01"></MdsMenu:MenuItem>
<MdsMenu:MenuItem Text="MenuItem 02"></MdsMenu:MenuItem>
<MdsMenu:MenuItem Text="MenuItem 03" />
</MdsMenu:Menu>
You have two properties decorated with PersistenceMode.InnerDefaultProperty, and:
Only one property can be designated
the default property.
I'd suggest you decorate your AnimationItems property with PersistenceMode.InnerProperty instead:
[PersistenceMode(PersistenceMode.InnerProperty)]
public animation AnimationItems
{
get;
set;
}
EDIT: The above is not enough. I got the code to work with some tweaks:
First, disable child persistence and remove the defaultProperty argument from the [ParseChildren] attribute:
[AspNetHostingPermission(SecurityAction.Demand,
Level = AspNetHostingPermissionLevel.Minimal)]
[AspNetHostingPermission(SecurityAction.InheritanceDemand,
Level = AspNetHostingPermissionLevel.Minimal)]
[ParseChildren(true)]
[ToolboxData("<{0}:Menu runat=\"server\"></{0}:Menu>")]
public class Menu : WebControl, INamingContainer
{
}
Then, decorate the AnimationItems property with PersistenceMode.InnerProperty, as suggested above. Do the same to MenuItems and remove its [DesignerSerializationVisibility] attribute:
[PersistenceMode(PersistenceMode.InnerProperty)]
public animation AnimationItems { get; set; }
[PersistenceMode(PersistenceMode.InnerProperty)]
public List<MenuItem> MenuItems
{
}
Finally, add a <MenuItems> element to your markup:
<MdsMenu:Menu ID="Menu1" runat="server">
<AnimationItems AnimationSpeed="Fast" AnimationType="Opacity_Height"
DropShadow="true" Delay="1000" />
<MenuItems>
<MdsMenu:MenuItem Text="MenuItem 01"></MdsMenu:MenuItem>
<MdsMenu:MenuItem Text="MenuItem 02"></MdsMenu:MenuItem>
<MdsMenu:MenuItem Text="MenuItem 03" />
</MenuItems>
</MdsMenu:Menu>
Related
I'm tired to search on web a solution for this. Basicly i am using InputBase to extend the normal inputbox to a custom component. For single selection in its ok, but turns complicate when i have mutiple selection "select multiple="multiple""
So here is the code:
File: XDropDownMultiSelect.razor
#using System.Linq.Expressions
#typeparam T
#inherits InputBase<T>
#if (!string.IsNullOrEmpty(Label))
{
<label class="form-label">#Label</label>
}
<select #bind="CurrentValue" class="form-control select2 #CssClass" id="#Id" #attributes="AdditionalAttributes" multiple>
#if (DropdownValues != null)
{
foreach (var cursor in DropdownValues)
{
<option value="#cursor.Key">#cursor.Value</option>
}
}
</select>
#code {
[Inject] public IJSRuntime _js { get; set; }
[Parameter, EditorRequired] public string Id { get; set; }
[Parameter] public string Label { get; set; }
[Parameter] public Expression<Func<T>> ValidationFor { get; set; }
[Parameter] public bool ShowDefaultOption { get; set; } = true;
[Parameter] public Dictionary<string, string> DropdownValues { get; set; }
[Parameter] public string Selected { get; set; }
protected override bool TryParseValueFromString(string value, out T result, out string validationErrorMessage)
{
if (typeof(T) == typeof(string))
{
result = (T)(object)value;
validationErrorMessage = null;
return true;
}
else if (typeof(T) == typeof(string[]))
{
result = (T)(object)(new string[] { value });
validationErrorMessage = null;
return true;
}
else if (typeof(T) == typeof(Guid))
{
Guid.TryParse(value, out var parsedValue);
result = (T)(object)parsedValue;
validationErrorMessage = null;
return true;
}
else if (typeof(T).IsEnum)
{
try
{
result = (T)Enum.Parse(typeof(T), value);
validationErrorMessage = null;
return true;
}
catch (ArgumentException)
{
result = default;
validationErrorMessage = $"The {FieldIdentifier.FieldName} field is not valid.";
return false;
}
}
throw new InvalidOperationException($"{GetType()} does not support the type '{typeof(T)}'.");
}
}
I use "CurrentValue" instead of "CurrentValueAsString" because is an array no string, and if i set CurrentValueAsString will have a render json problem...
Now i call by simple:
<XDropDownMultiSelect #bind-Value="usersSelected" Id="test" DropdownValues="usersAll" />
#code{
public string[] usersSelected { get; set; } = new [] { "user1" };
public string[] usersAll{ get; set; } = new [] { "user1", "user2", "user3" };
Its working, but dosenĀ“t bind the new selection values to my selectValues object.
i found how to use CurrentValueAsString
protected override string FormatValueAsString(T? value)
{
if( value != null)
{
return value.ToJson(); //this is extension my to convert any object to json format.
}
return base.FormatValueAsString(value);
}
But this not update the source model with new selections.
I am new to blazor and need to create a dynamic treeview where nodes can be created and deleted. All this data is saved in database. After pulling the data from database what kind of object I need to create to bind to Mudtreeview?
If only first level nodes are rendered initially, how can I load the children on node click?
is there any example somewhere? All the sample code on mudblazor site is with static data.
Adding and removeing items is easy if you bind the treeview to a collection in MudBlazor. I made a little demo for you to can play around online: https://try.mudblazor.com/snippet/cuwlvFQcfJTzHuki
Here is the full code of the example:
<MudButton OnClick="AddItems" Variant="Variant.Filled">Add items</MudButton>
<MudButton OnClick="DeleteItems" Variant="Variant.Filled">Delete items</MudButton>
<MudPaper Width="300px" Elevation="0">
<MudTreeView Items="TreeItems" MultiSelection="true" #bind-ActivatedValue="ActivatedValue" #bind-SelectedValues="SelectedValues">
<ItemTemplate>
<MudTreeViewItem #bind-Expanded="#context.IsExpanded" Items="#context.TreeItems" Value="#context"
Icon="#context.Icon" Text="#context.Title" EndText="#context.Number?.ToString()" EndTextTypo="#Typo.caption" />
</ItemTemplate>
</MudTreeView>
</MudPaper>
<div style="width: 100%">
<MudText Typo="#Typo.subtitle1">Activated item: #(ActivatedValue?.Title)</MudText>
<MudText Typo="#Typo.subtitle1">Sum of selected items: #GetSelectedSum()</MudText>
</div>
#code {
private TreeItemData ActivatedValue { get; set; }
private HashSet<TreeItemData> SelectedValues { get; set; }
private HashSet<TreeItemData> TreeItems { get; set; } = new HashSet<TreeItemData>();
public class TreeItemData
{
public string Title { get; set; }
public string Icon { get; set; }
public int? Number { get; set; }
public bool IsExpanded { get; set; }
public HashSet<TreeItemData> TreeItems { get; set; }
public TreeItemData(string title, string icon, int? number = null)
{
Title = title;
Icon = icon;
Number = number;
}
public override bool Equals(object x) {
var other = x as TreeItemData;
if (other==null)
return false;
return other.Title==Title;
}
public override int GetHashCode() {
return Title.GetHashCode();
}
}
protected override void OnInitialized()
{
TreeItems.Add(new TreeItemData("All Mail", Icons.Filled.Email));
TreeItems.Add(new TreeItemData("Trash", Icons.Filled.Delete));
TreeItems.Add(new TreeItemData("Categories", Icons.Filled.Label)
{
IsExpanded = true,
TreeItems = new HashSet<TreeItemData>()
{
new TreeItemData("Social", Icons.Filled.Group, 90),
new TreeItemData("Updates", Icons.Filled.Info, 2294),
new TreeItemData("Forums", Icons.Filled.QuestionAnswer, 3566),
new TreeItemData("Promotions", Icons.Filled.LocalOffer, 733)
}
});
TreeItems.Add(new TreeItemData("History", Icons.Filled.Label));
}
public int GetSelectedSum()
{
return SelectedValues?.Sum(i => i.Number ?? 0) ?? 0;
}
private int i=0;
public void AddItems() {
TreeItems.Add(new TreeItemData("Added Item " + (i++), Icons.Filled.Coronavirus));
}
public void DeleteItems() {
var item=TreeItems.FirstOrDefault(x=>x.Title.StartsWith("Added Item"));
TreeItems.Remove(item);
}
}
I have created tow custom controls to use bootstrap in my C# code. The first one implement a bootstrap dropdown list with this code ;
using System.Web.UI;
using System.Web.UI.WebControls;
using static JDBootStrap.BSTypes;
namespace JDBootStrap.Components
{
[ToolboxData("<{0}:BSDropDown runat=server></{0}:BSDropDown>")]
public class BSDropDown : Panel
{
public enum OrientationType { Down, Up, Right }
string _text;
OrientationType _orientation;
ControlCollection _controls;
sizeType _size = sizeType.md;
bool _useInGroup;
bool useInList;
Glyphicon.GlyphiconType? _glyphicon;
string _style;
public BSDropDown()
{
Controls = new ControlCollection(this);
}
public Glyphicon.GlyphiconType? Glyphicon
{
get
{
return _glyphicon;
}
set
{
_glyphicon = value;
}
}
#region Properties
protected override string TagName
{
get
{
return UseInList ? "li" : "div";
}
}
protected override ControlCollection CreateControlCollection()
{
return Controls;
}
public string Text
{
get
{
return _text;
}
set
{
_text = value;
}
}
public OrientationType Orientation
{
get
{
return _orientation;
}
set
{
_orientation = value;
}
}
public bool UseInList
{
get
{
return useInList;
}
set
{
useInList = value;
}
}
new public ControlCollection Controls
{
get
{
return _controls;
}
set
{
_controls = value;
}
}
public sizeType Size
{
get
{
return _size;
}
set
{
_size = value;
}
}
public bool UseInGroup
{
get
{
return _useInGroup;
}
set
{
_useInGroup = value;
}
}
#endregion
public override void RenderBeginTag(HtmlTextWriter writer)
{
writer.Write("<" + TagName + " class=\"" + GetOrientationClass());
if (_orientation == OrientationType.Right) writer.Write(" dropdown-submenu");
if (!string.IsNullOrEmpty(CssClass)) writer.Write(" " + CssClass);
if (_useInGroup) writer.Write(" btn-group");
writer.Write(" btn-" + (UseInGroup ? "group-" : "") + _size.ToString().ToLower());
writer.Write("\"");
writer.Write(" name =\"" + UniqueID + "\"");
writer.Write(" id=\"" + ClientID + "\"");
writer.Write(">");
writer.Write(UseInList ? "<a href =\"#\"" : "<button");
writer.Write(" class=\"");
writer.Write(_useInGroup ? "btn btn-default " : "");
writer.Write("dropdown-toggle");
writer.Write("\" data-toggle=\"dropdown\" role=\"button\" aria-haspopup=\"true\" aria-expanded=\"false\">");
if (!string.IsNullOrEmpty(_text)) writer.WriteEncodedText(_text);
if (_glyphicon != null)
{
var g = new Glyphicon((Glyphicon.GlyphiconType)_glyphicon);
g.RenderControl(writer);
}
if (_orientation != OrientationType.Right) writer.Write("<span class=\"caret\" style=\"margin-left:4px;\"></span>");
writer.Write(UseInList ? "</a>" : "</button>");
writer.Write("<ul class=\"dropdown-menu\">");
}
protected override void Render(HtmlTextWriter writer)
{
RenderBeginTag(writer);
RenderChildren(writer);
RenderEndTag(writer);
}
protected override void RenderChildren(HtmlTextWriter writer)
{
foreach (Control ctrl in Controls)
{
if (ctrl.GetType() == typeof(BSDropDown)) ((BSDropDown)ctrl).Orientation = OrientationType.Right;
if (ctrl.GetType() == typeof(BSMenuItem)) ((BSMenuItem)ctrl).SubMenu = true;
ctrl.RenderControl(writer);
}
}
public override void RenderEndTag(HtmlTextWriter writer)
{
writer.Write("</ul>");
writer.Write("</" + TagName + ">");
}
private string GetOrientationClass()
{
switch (Orientation)
{
case OrientationType.Up:
return "dropup";
default:
return "dropdown";
}
}
}
}
the second one is a menuitem like this :
using System;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace JDBootStrap.Components
{
[ToolboxData("<{0}:BSMenuSeparator runat=server></{0}:BSMenuSeparator>")]
public class BSMenuSeparator : WebControl
{
protected override void Render(HtmlTextWriter writer)
{
writer.Write("<li class=\"divider\"></li>");
}
}
[ToolboxData("<{0}:BSMenuHeader runat=server></{0}:BSMenuHeader>")]
public class BSMenuHeader : WebControl
{
private string _title;
public BSMenuHeader(string title)
{
_title = title;
}
public string Title
{
get
{
return _title;
}
set
{
_title = value;
}
}
protected override void Render(HtmlTextWriter writer)
{
writer.Write("<li class=\"dropdown-header\">");
if (!string.IsNullOrEmpty(_title)) writer.Write(_title);
writer.Write("</li>");
}
}
[ToolboxData("<{0}:BSMenuItem runat=server></{0}:BSMenuItem>")]
public class BSMenuItem : Panel, IButtonControl, IPostBackEventHandler
{
string _text;
string _navigateUrl;
bool _active ;
b
ool _subItem;
Glyphicon.GlyphiconType? _glyphicon;
string _value;
string _title;
string _commandArgument;
string _validationGroup;
string _postBackUrl;
string _commandName;
bool _causesValidation;
static readonly object EventClick = new object();
public event EventHandler Click
{
add
{
Events.AddHandler(EventClick, value);
}
remove
{
Events.RemoveHandler(EventClick, value);
}
}
public event CommandEventHandler Command;
#region Property
public BSMenuItem()
{
}
public BSMenuItem(string text)
{
_text = text;
}
public BSMenuItem(string text, string navigateUrl)
{
_text = text;
_navigateUrl = navigateUrl;
}
public string Text
{
get
{
return _text;
}
set
{
_text = value;
}
}
public string NavigateUrl
{
get
{
return _navigateUrl;
}
set
{
_navigateUrl = value;
}
}
public bool Active
{
get
{
return _active;
}
set
{
_active = value;
}
}
public bool SubMenu
{
get
{
return _subItem;
}
set
{
_subItem = value;
}
}
public Glyphicon.GlyphiconType? Glyphicon
{
get
{
return _glyphicon;
}
set
{
_glyphicon = value;
}
}
public bool CausesValidation
{
get
{
return _causesValidation;
}
set
{
_causesValidation = value;
}
}
public string CommandArgument
{
get
{
return _commandArgument;
}
set
{
_commandArgument = value;
}
}
public string ValidationGroup
{
get
{
return _validationGroup;
}
set
{
_validationGroup = value;
}
}
public string PostBackUrl
{
get
{
return _postBackUrl;
}
set
{
_postBackUrl = value;
}
}
public string CommandName
{
get
{
return _commandName;
}
set
{
_commandName = value;
}
}
public string Value
{
get
{
return _value;
}
set
{
_value = value;
}
}
public string Title
{
get
{
return _title;
}
set
{
_title = value;
}
}
#endregion
protected override void Render(HtmlTextWriter writer)
{
if (Controls.Count == 0)
{
writer.Write("<li");
writer.Write(" name =\"" + UniqueID + "\"");
writer.Write(" id=\"" + ClientID+"\"");
if (_active) writer.Write(" class=\"active\"");
writer.Write("><a href=\"");
writer.WriteEncodedUrl(NavigateUrl ?? "#");
writer.Write("\"");
if (Events != null) writer.Write(" OnClick=\"" + Page.ClientScript.GetPostBackEventReference(this, Value)+"\"");
if (Title != null) writer.Write(" title=\"" + Title + "\"");
writer.Write(">");
if (Glyphicon!=null)
{
var g = new Glyphicon((Glyphicon.GlyphiconType)_glyphicon);
g.RenderControl(writer);
}
if (!string.IsNullOrEmpty(_text)) writer.WriteEncodedText(_text);
writer.Write("</a></li>");
}
else
{
var dd = new BSDropDown
{
Text = _text,
UseInList = true
};
if (SubMenu) dd.Orientation = BSDropDown.OrientationType.Right;
dd.Controls=Controls;
dd.RenderControl(writer);
}
}
protected virtual void OnClick(EventArgs e)
{
EventHandler handler = (EventHandler)Events[EventClick];
handler?.Invoke(this, e);
}
protected virtual void OnCommand(CommandEventArgs e)
{
Command?.Invoke(this, e);
}
public void RaisePostBackEvent(string eventArgument)
{
OnClick(new EventArgs());
OnCommand(new CommandEventArgs(CommandName, CommandArgument));
}
}
If i use my menu item alone, or as a child of my drop-down control using my aspx page to set them, it work fine. But if i create them programmatically my RaisePostBackEvent is never fired. __EventTarget is well set but nothing happen.
It work only if i set in my aspx page my dropdown and add my child programmatically... (I add my control in Page_init). Thanks for your help.
I use an array of control to override Controls of my dropdown list. If i remove this collection and use inherited Controls properties it work.
I was using my own array because my menuitem can change behaviour and become dropdown list if there is child. So i have to move control child from menuitem to a dropdown (list and Controls can't be set).
Now i have to move control like this :
int l = Controls.Count;
for (int a = 0; a < l; a++)
dd.Controls.Add(Controls[0]);
Controls.Clear();
Controls.Add(dd);
where dd is my new dropdown list. Hope it can help someone.
I copied this code from another project and can't figure out why it isn't working. My observable collections are working great binding and updating, but my textboxes aren't changing. I have a button click that lets the user pick a directory (DirectoryBrowse() method) and then assigns that value to the data context's property that is bound to the textbox. PropertyChanged is always null and I can't figure out why! The initial binding works just fine, just note when I change the value in the code-behind. I've been at this entirely too long, but any help would be appreciated!
DataContext class:
[Serializable]
public class Settings : ViewModels.ViewModelEntity
{
public static Settings defaultSettings { get; set; }
private string _ExportDir;
public string ExportDir
{
get { return this._ExportDir; }
set
{
if (this._ExportDir != value)
{
this._ExportDir = value;
this.NotifyPropertyChanged("ExportDir");
}
}
}
private string _LastRunTime;
public string LastRunTime
{
get { return this._LastRunTime; }
set
{
if (this._LastRunTime != value)
{
this._LastRunTime = value;
this.NotifyPropertyChanged("LastRunTime");
}
}
}
private string _TSCertPath;
public string TSCertPath
{
get { return this._TSCertPath; }
set
{
if (this._TSCertPath != value)
{
this._TSCertPath = value;
this.NotifyPropertyChanged("TSCertPath");
}
}
}
public ObservableCollection<Map> Brokers { get; set; }
public ObservableCollection<Account> Accounts { get; set; }
public List<Holiday> Holidays { get; set; }
public bool RefreshHolidays { get; set; }
public string ProxyServer { get; set; }
public string ProxyPort { get; set; }
public string ProxyUsername { get; set; }
public string ProxyPassword { get; set; }
public bool TSProd { get; set; }
public string TSTriad { get; set; }
public string TSPassword { get; set; }
public string TSCertPassword { get; set; }
public Settings()
{
this.Brokers = new ObservableCollection<Map>();
this.Accounts = new ObservableCollection<Account>();
}
}
Xaml:
<TextBlock TextWrapping="Wrap" Text="File Export Path*"/>
<TextBox TextWrapping="Wrap" Text="{Binding Path=ExportDir, Mode=TwoWay}" />
<Button x:Name="btnBrowseExportDir" Content="..." Click="btnBrowseExportDir_Click"/>
Code-behind:
public MainWindow()
{
InitializeComponent();
Settings.Initialize();
this.DataContext = Settings.defaultSettings;
string[] args = Environment.GetCommandLineArgs();
if (args.Contains("create"))
{
this.Close();
}
}
private string DirectoryBrowse()
{
CommonOpenFileDialog dialog = new CommonOpenFileDialog();
dialog.IsFolderPicker = true;
CommonFileDialogResult result = dialog.ShowDialog();
if (result.ToString().ToUpper() == "OK")
{
if (!Directory.Exists(dialog.FileNames.First()))
{
this.lblStatus.Text = "Invalid directory selected";
return string.Empty;
}
else
{
return dialog.FileNames.First();
}
}
else
{
this.lblStatus.Text = "Invalid directory selected";
return string.Empty;
}
}
private void btnBrowseExportDir_Click(object sender, RoutedEventArgs e)
{
Settings.defaultSettings.ExportDir = DirectoryBrowse();
}
ViewModelEntity:
public class ViewModelEntity
{
public event PropertyChangedEventHandler PropertyChanged;
public virtual void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Settings.defaultSettings is never assigned a value. So the databinding have nothing to work with.
Thoug code for Settings.Initialize() is missing.
#Dave and #Icepickle showed me what I was missing, no implementaiton of INotifyPropertyChanged!
I'm trying to serialize/deserialize collection of interfaces, which basically is unsupported. I found a question on SO where a proposition is stated to provide a serializable wrapper properties for those properties which depends on interfaces. So that's what I have:
public class Serialize {
public Serialize() {
this.SCollection = new SerializableInterfacesCollection<ObservableCollection<A>>(new ObservableCollection<A>());
}
[XmlIgnore()]
public ObservableCollection<A> Collection {
get {
return this.SCollection.Value;
}
set {
SCollection.Value = value;
}
}
public SerializableInterfacesCollection<ObservableCollection<A>> SCollection { get; set; }
}
public interface A {
string Str { get; set; }
int Int { get; set; }
// bad properties... very bad:
B B { get; set; }
ObservableCollection<B> Collection {get;set;}
}
public interface B {
string Label { get; set; }
string Value { get; set; }
}
public class AImpl: A {
public AImpl() {
SB = new SerializableInterface<B>();
SCollection = new SerializableInterfacesCollection<ObservableCollection<B>>(new ObservableCollection<B>());
}
[XmlAttribute()]
public string Type = typeof(AImpl).FullName;
public string Str {get;set;}
public int Int {get;set;}
[XmlIgnore()]
public B B {
get {
return SB.Value;
}
set {
SB.Value = value;
}
}
public SerializableInterface<B> SB;
[XmlIgnore()]
public ObservableCollection<B> Collection {
get {
return SCollection.Value;
}
set {
SCollection.Value = value;
}
}
public SerializableInterfacesCollection<ObservableCollection<B>> SCollection { get; set; }
}
public class BImpl01: B {
[XmlAttribute()]
public string Type = typeof(BImpl01).FullName;
public string Label {get;set;}
public string Value {get;set;}
}
public class BImpl02: B {
[XmlAttribute()]
public string Type = typeof(BImpl02).FullName;
public string Label {get;set;}
public string Value {get;set;}
}
Everything works fine if the A interface does not include "bad properties" (and of course they do not appear in the AImpl class). If it does than the collection's element does not deserialize and stops after deserializing first property of interface B.
Here are the wrappers:
public class SerializableInterface<T>: IXmlSerializable {
public SerializableInterface(T value) {
Value = value;
}
public SerializableInterface() { }
public T Value { get; set; }
public const string TypeAttr = "Type";
public const string NullAttrValue = "null";
#region IXmlSerializable Members
public System.Xml.Schema.XmlSchema GetSchema() {
return null;
}
public virtual void ReadXml(System.Xml.XmlReader reader) {
if (!reader.HasAttributes)
throw new FormatException("expected a type attribute!");
string type = reader.GetAttribute(TypeAttr);
reader.Read(); // consume the value
if (type == NullAttrValue)
return;// leave T at default value
XmlSerializer serializer = new XmlSerializer(Type.GetType(type));
this.Value = (T)serializer.Deserialize(reader);
}
public virtual void WriteXml(System.Xml.XmlWriter writer) {
if (Value == null) {
writer.WriteAttributeString(TypeAttr, NullAttrValue);
return;
}
try {
var type = Value.GetType();
var ser = new XmlSerializer(type);
writer.WriteAttributeString(TypeAttr, type.FullName);
ser.Serialize(writer, Value);
}
catch (Exception e) {
// some logging
throw e;
}
}
#endregion
}
public class SerializableInterfacesCollection<T>: SerializableInterface<T> where T: IList, new() {
public SerializableInterfacesCollection() { }
public SerializableInterfacesCollection(T value)
: base(value) {}
#region IXmlSerializable Members
public override void ReadXml(System.Xml.XmlReader reader) {
try {
if (!reader.HasAttributes)
throw new FormatException("No " + TypeAttr + " in element");
string type = reader.GetAttribute(TypeAttr);
if (string.IsNullOrEmpty(type) || type == NullAttrValue || type != typeof(T).FullName)
return;
reader.Read();
Value = new T();
while (reader.NodeType != XmlNodeType.EndElement) {
string typename = reader.GetAttribute(TypeAttr);
if (string.IsNullOrEmpty(typename)) {
throw new FormatException("Collection element has to have " + TypeAttr + " attribute specifing its type");
}
Type t = Type.GetType(typename);
if (null == t.GetInterface(typeof(T).GetProperty("Item").PropertyType.FullName))
break;
XmlSerializer xs = new XmlSerializer(t);
var o = xs.Deserialize(reader);
Value.Add(o);
}
}
catch (Exception e) {
// some logging
throw e;
}
}
public override void WriteXml(System.Xml.XmlWriter writer) {
if (Value == null) {
writer.WriteAttributeString(TypeAttr, NullAttrValue);
return;
}
try {
writer.WriteAttributeString(TypeAttr, Value.GetType().FullName);
foreach (var el in Value) {
var ser = new XmlSerializer(el.GetType());
ser.Serialize(writer, el);
}
}
catch (Exception e) {
// some logging
throw e;
}
}
#endregion
}
and here is a method generating data for tests:
private Serialize makeA() {
Serialize result = new Serialize();
for (int i = 0; i < 10; ++i) {
A a = new AImpl() { Str = "str " + i, Int = i, B = makeB(i) };
for (int j = 0; j < 10; ++j) {
a.Collection.Add(makeB(j));
}
result.Collection.Add(a);
}
return result;
}
B makeB(int i) {
if (i % 2 == 0) {
return new BImpl01(){Label= "Blabel " + i, Value="value b"+i};
}
else {
return new BImpl02(){Label= "B2label " + i, Value="value b2"+i};
}
}