this problem is driving me really mad.
In an Asp.Net-application, I have two DropDownLists, DropDownStore and DropDownCampaign.
<asp:DropDownList ID="storeDropDown" AppendDataBoundItems="true"
AutoPostBack="true" DataSourceID="storeSqlDataSource"
DataTextField="Name" DataValueField="StoreId"
runat="server" OnSelectedIndexChanged="storeDropDown_SelectedIndexChanged">
<asp:ListItem Value="">Choose a store</asp:ListItem>
</asp:DropDownList>
<asp:DropDownList ID="campaignDropDown" DataSourceID="campaignSqlDataSource"
DataTextField="Name" DataValueField="CampaignLevelId"
AppendDataBoundItems="true" runat="server">
<asp:ListItem Value="">Choose a campaign</asp:ListItem>
</asp:DropDownList>
As you can see, they are both bound to SQLDataSources.
The SQLDataSource for the second DropDownList looks as follows:
<asp:SqlDataSource ID="campaignSqlDataSource" runat="server" ConnectionString="<%$ ConnectionStrings:AFPMAdManagerConnectionString %>"
SelectCommand="SELECT [CampaignLevelId], [Name] FROM [CampaignLevel] where [StoreId] = #StoreId">
<SelectParameters>
<asp:ControlParameter ControlID="storeDropDown" Name="StoreId" PropertyName="SelectedValue" Type="String" />
</SelectParameters>
</asp:SqlDataSource>
so that the second DropDownList is bound, when the user chooses an entry of the first
DropDownList.
This works well. But when I set the value of the first DropDownList programmatically,
the second DropDownList is bound twice:
protected void Page_Load(object sender, EventArgs e)
{
storeDropDown.SelectedValue = "someStore";
}
Why?
It's being told to bind twice. It binds on the original value of the first dropdown (since that's the controlID governing it), and then when you set it in Page_load event it binds it again.
I would recommend binding it to a label with visible property set to False. Then on the first dropdown selectedindex changed, set the text property of the label.
While I don't know the exact reason for the double binding, your best bet might be to set an OnDataBinding handler for the second list, set a breakpoint in it, and examine the call stack in both places. That'll tell you why the framework is binding that list, both times.
Depending on how sensitive to performance you are, you might want to just set AppendDataBoundItems to false on the second list so that it doesn't matter that it's re-bound.
Try wrapping your selection in:
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
storeDropDown.SelectedValue = "someStore";
}
}
Related
So, I have recently started working on a JSF page using richfaces 4, in which I have a rich:collapsiblePanel. I face a problem however, I am using the collapsiblePanel within a rich:dataGrid, which renders the collapsiblePanels by iterating though a list recieved from the server. There is a link to 'sort' the collapsiblePanels according to the data in the panel header (in the backing bean of course). When any of the collapsiblePanels are expanded, and the sort link is clicked, all of them are expanded, whilst all are expanded, if one is closed, and the link clicked again, all of them close.
Things I have tried:
Changing the switchType to any other than client (i.e ajax and server)
Adding a constant boolean in the backing bean to force the expand attribute to false on reload (although it is not even affected by the backing bean at all)
Sample code of what it looks like at the moment:
<h:panelGrid id="SomePanelGrid">
<rich:dataGrid id="SomeDataGrid" value="bean.listValues" var="values"
iterationStatusVar="counter" elements="10">
<rich:collapsiblePanel switchType="client" expanded="#{bean.expanded}">
Layouts and what not (not in relation to this)
</rich:collapsiblePanel>
</rich:dataGrid>
</h:panelGrid>
The link simply calls a method in the backing bean which does the sorting.
I have found a similar problem, involving a dataTable instead of a dataGrid, although no answers have been given, but only links that lead to more dead ends. This can be found at: https://community.jboss.org/message/819938
Any help would be greatly appreciated. Unfortunately I do not have alot of time to answer alot of other questions at the moment, but I will be checking back a bit later.
Thanks in advance.
You have many syntax flaws inside your code, here is how it should looks like :
<h:panelGrid id="SomePanelGrid">
<rich:dataGrid id="SomeDataGrid" value="#{bean.listValues}" var="values"
iterationStatusVar="counter" elements="10">
<rich:collapsiblePanel switchType="client" expanded="#{bean.expanded}">
Layouts and what not (not in relation to this)
</rich:collapsiblePanel>
</rich:dataGrid>
</h:panelGrid>
You are probably experiencing only one collapsiblePanel in your example, this code modified and tested work properly.
Now if you want to save collapsiblePanels expanded state when refreshing your dataGrid by AJAX, you need to add some stuff.
First, you need to add one property to your objects you are iterating on, to save the state of each panels.
public class Item
{
private boolean expanded;
public void setExpanded(boolean expanded)
{
this.exanded = expanded;
}
public boolean getExpanded()
{
return this.expanded;
}
// Your other stuff
}
Second, you need to add a listener in your bean to know when user changes the state of a panel, note the attribute to get back which item is related to this panel.
#ManagedBean
#ViewScope
public class Bean
{
private List<Item> listValues;
#PostConstruct
void init()
{
listValues = //... Some initialization to your list
}
public List<Item> getListValues()
{
return this.listValues;
}
public void toggle(PanelToggleEvent event)
{
// Take the current item
Item item = (Item)event.getComponent().getAttributes().get("item");
// Save the current state in the item
item.setExpanded(event.getExpanded());
}
}
Finally, you need to change your switchType to AJAX and add the listener in your code without forgetting the attribute that need to be passed in the listener.
<h:form>
<rich:dataGrid id="SomeDataGrid" value="#{bean.listValues}" var="item"
iterationStatusVar="counter" elements="10">
<rich:collapsiblePanel switchType="ajax" expanded="#{item.expanded}">
<f:attribute name="item" value="#{item}" />
Layouts and what not (not in relation to this)
</rich:collapsiblePanel>
</rich:dataGrid>
</h:form>
I've lost my C# Panel Controls....
the asp for my panel is
<asp:Panel ID="pnlSett1" GroupingText="Contra Account 1" runat="server"
Width="400" >
</asp:Panel>
I've set up the controls in code behind using
Label lblCompanyNumber = new Label();
lblCompanyNumber.Text = "ABCDEF";
lblCompanyNumber.ID = "CompanyNumber";
pnlSett1.Controls.Add(lblCompanyNumber);
But after the panel is populated and the user clicks on the ContraUpdate button (postback) ---
protected void btnContraUpdate_Click(object sender, EventArgs e)
Control pnlCompanyNumber = pnlSett1.FindControl("CompanyNumber");
it can't find the control....Null value returned
Any ideas, i've tried putting the Find Control after the initial Control Add to prove the FindControl is correct and it is, but then I tried it on the PageLoad on the way back in, and that brings back Null value as well......
I'm just now starting to learn ASP.NET MVC. How would I go about creating a reusable tri-state checbox? In WebForms this would be a control, but I don't know the MVC equivalent.
Add a TriStateCheckBox (or TriStateCheckBoxFor if you use the strongly typed overloads) extension method to HtmlHelper and add the namespace of that extension method class to the namespaces section of your web.config.
As for the implementation, I'd recommend having at look at the InputExtensions source on codeplex and using that to create your own.
Limitations:
View Rendering - When rendering HTML content, there is no attribute you can possibly place on an <input type="checkbox" /> that will give it the property indeterminate.
At some point, you'll have to use JavaScript to grab the element and set the indeterminate property:
// vanilla js
document.getElementById("myChk").indeterminate = true;
// jQuery
$("#myCheck).prop("indeterminate", true);
Form Data - model binding will always be limited to what values are actually sent in the request, either from the url or the data payload (on a POST).
In this simplified example, both unchecked and indeterminate checkboxes are treated identically:
And you can confirm that for yourself in this Stack Snippet:
label {
display: block;
margin-bottom: 3px;
}
<form action="#" method="post">
<label >
<input type="checkbox" name="chkEmpty">
Checkbox
</label>
<label >
<input type="checkbox" name="chkChecked" checked>
Checkbox with Checked
</label>
<label >
<input type="checkbox" name="chkIndeterminate" id="chkIndeterminate">
<script> document.getElementById("chkIndeterminate").indeterminate = true; </script>
Checkbox with Indeterminate
</label>
<label >
<input name="RegularBool" type="checkbox" value="true">
<input name="RegularBool" type="hidden" value="false">
RegularBool
</label>
<input type="submit" value="submit"/>
</form>
Model Binding - Further, model binding will only occur on properties that are actually sent. This actually poses a problem even for regular checkboxes, since they won't post a value when unchecked. Value types do always have a default value, however, if that's the only property in your model, MVC won't new up an entire class if it doesn't see any properties.
ASP.NET solves this problem by emitting two inputs per checkbox:
Note: The hidden input guarantees that a 'false' value will be sent even when the checkbox is not checked. When the checkbox is checked, HTTP is allowed to submit multiple values with the same name, but ASP.NET MVC will only take the first instance, so it will return true like we'd expect.
Render Only Solution
We can render a checkbox for a nullable boolean, however this really only works to guarantee a bool by converting null → false when rendering. It is still difficult to share the indeterminate state across server and client. If you don't need to ever post back indeterminate, this is probably the cleanest / easiest implementation.
Roundtrip Solution
As there are serious limitations to using a HTML checkbox to capture and post all 3 visible states, let's separate out the view of the control (checkbox) with the tri-state values that we want to persist, and then keep them synchronized via JavsScript. Since we already need JS anyway, this isn't really increasing our dependency chain.
Start with an Enum that will hold our value:
/// <summary> Specifies the state of a control, such as a check box, that can be checked, unchecked, or set to an indeterminate state.</summary>
/// <remarks> Adapted from System.Windows.Forms.CheckState, but duplicated to remove dependency on Forms.dll</remarks>
public enum CheckState
{
Checked,
Indeterminate,
Unchecked
}
Then add the following property to your Model instead of a boolean:
public CheckState OpenTasks { get; set; }
Then create an EditorTemplate for the property that will render the actual property we want to persist inside of a hidden input PLUS a checkbox control that we'll use to update that property
Views/Shared/EditorTemplates/CheckState.cshtml:
#model CheckState
#Html.HiddenFor(model => model, new { #class = "tri-state-hidden" })
#Html.CheckBox(name: "",
isChecked: (Model == CheckState.Checked),
htmlAttributes: new { #class = "tri-state-box" })
Note: We're using the same hack as ASP.NET MVC to submit two fields with the same name, and placing the HiddenFor value that we want to persist first so it wins. This just makes it easy to traverse the DOM and find the corresponding value, but you could use different names to prevent any possible overlap.
Then, in your view, you can render both the property + checkbox using the editor template the same way you would have used a checkbox, since it renders both. So just add this to your view:
#Html.EditorFor(model => model.OpenTasks)
The finally piece is to keep them synchronized via JavaScript on load and whenever the checkbox changes like this:
// on load, set indeterminate
$(".tri-state-hidden").each(function() {
var isIndeterminate = this.value === "#CheckState.Indeterminate";
if (isIndeterminate) {
var $box = $(".tri-state-box[name='" + this.name + "'][type='checkbox']");
$box.prop("indeterminate", true);
}
});
// on change, keep synchronized
$(".tri-state-box").change(function () {
var newValue = this.indeterminate ? "#CheckState.Indeterminate"
: this.checked ? "#CheckState.Checked"
: "#CheckState.Unchecked";
var $hidden = $(".tri-state-hidden[name='" + this.name + "'][type='hidden']");
$hidden.val(newValue);
});
Then you can use however you'd like in your business model. For example, if you wanted to map to a nullable boolean, you could use the CheckState property as a backing value and expose/modify via getters/setters in a bool? like this:
public bool? OpenTasksBool
{
get
{
if (OpenTasks == CheckState.Indeterminate) return null;
return OpenTasks == CheckState.Checked;
}
set
{
switch (value)
{
case null: OpenTasks = CheckState.Indeterminate; break;
case true: OpenTasks = CheckState.Checked; break;
case false: OpenTasks = CheckState.Unchecked; break;
}
}
}
Alternative Solution
Also, depending on your domain model, you could just use Yes, No, ⁿ/ₐ radio buttons
ASP.NET MVC certainly doesn't provide such component, actually it simply relies on the standard elements available in HTML but you may want to check out this solution.
I have used the following template in my project:
<DataTemplate
x:Key="textBoxDataTemplate">
<TextBox
Name="textBox"
ToolTip="{Binding RelativeSource={RelativeSource Self}, Path=(Validation.Errors)[0].ErrorContent}"
Tag="{Binding}"
PreviewKeyDown="cellValueTextBoxKeyDown">
<TextBox.Text>
<MultiBinding
Converter="{StaticResource intToStringMultiConverter}">
<Binding
Path="CellValue"
Mode="TwoWay">
<Binding.ValidationRules>
<y:MatrixCellValueRule
MaxValue="200" />
</Binding.ValidationRules>
</Binding>
<Binding
RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type y:MatrixGrid}}"
Path="Tag"
Mode="OneWay" />
</MultiBinding>
</TextBox.Text>
</TextBox>
</DataTemplate>
I used this template to create an editable matrix for the user. The user is able to navigate from cell to cell within the matrix and I would like to highlight the data in the selected textbox but it doesn't work. I called TextBox.Focus () and TextBox.SelectAll () to achieve the effect but nothing. The Focus () works but the text never gets highlighted.
Any help is welcome and appreciated.
Okay, if anyone is interested, the solution to this problem of mine was to include the statement e.Handled = true; in the event handler method where the textBox.SelectAll() and textBox.Focus() are called.
The problem was that I attached an event handler to the textbox's PreviewKeyDown event which handles a tunneling event and probably the SelectAll() and Focus() calls are ignored without calling the e.Handled = true; statement.
Hope it'll help someone.
Without the rest of your code it's difficult to say whether this will work for you, but I put together a small sample using your DataTemplate (minus the parts that refer to code that wasn't posted).
I was able to select all the text in the text boxes by adding a GotFocus event handler to the TextBox in the DataTemplate:
<TextBox
...
GotFocus="textBox_GotFocus"
...>
...
</TextBox>
And the code-behind:
private void textBox_GotFocus(object sender, RoutedEventArgs e)
{
TextBox textBox = sender as TextBox;
if (textBox != null)
{
textBox.SelectAll();
}
}
Let me know if you are attempting to select all under different circumstances (not when the box receives focus).
Here's a very good very simple solution (I don't know if it works for your template, but give it a try): http://social.msdn.microsoft.com/forums/en-US/wpf/thread/564b5731-af8a-49bf-b297-6d179615819f
Why doesn't this display the date/time when rendered?
<asp:Label runat="server" ID="test" Text="<%= DateTime.Now.ToString() %>" ></asp:Label>
Is there anyway to make this work?
Asp.net server controls don't play well with the <%=, instead you can do:
<span><%= DateTime.Now.ToString() %></span>
Ps. you could alternatively set the label's text on the code-behind. It might work for your scenario to set it on the PreRenderComplete.
I'm not sure if you've got a code behind file, but if you really need to set the label's Text property in the .aspx markup you could add the following code to the page:
<script runat="server">
protected override void OnPreLoad(EventArgs e)
{
if (!Page.IsPostBack)
{
this.test.Text = DateTime.Now.ToString();
base.OnPreLoad(e);
}
}
</script>
This way you can maintain the label control's state on postback.
Put the inline code inside the label's tag as below,
< asp:Label ID="Lbl" runat="server" Text="">
<%= DateTime.Now.ToString() %>
< /asp:Label>
Well the asp tags are rendered. You will have to set the property at runtime. or just do the <%= DateTime.Now.ToString() %>.
The simplest way to make that work would be to use a data-binding expression in place of the code render block...
<asp:Label runat="server" ID="test" Text="<%# DateTime.Now.ToString() %>" ></asp:Label>
Now the Text property will be set whenever Page.DataBind() is called, so in your code-behind you'll want something like
protected override void OnPreRender(EventArgs e)
{
if (!Page.IsPostBack)
{
DataBind();
}
base.OnPreRender(e);
}
The real problem here though is I need to set the property of a WebControl with code on the markup page. The only way I've found to do this is put the whole control in a code block. Its not elegant or suggested but when all else fails this will work.
<%
var stringBuilder = new StringBuilder();
var stringWriter = new StringWriter(stringBuilder);
var htmlWriter = new HtmlTextWriter(stringWriter);
var label = new Label { Text = DateTime.Now.ToString() };
label.RenderControl(htmlWriter);
Response.Write(stringBuilder.ToString());
%>
But this won't work if you need the control to maintain state.
UPDATE:
After researching Kev's answer I did find an even better solution. I don't have a code behind (its an MVC page) but you can still reference a control on the page through a code block so my new solution is the following. Note - You have to place the code block first for this to work.
<%
lblTest.Text = DateTime.Now.ToString();
%>
<asp:label runat="server" ID="lblTest" />
Thanks for the inspiration Kev!