Is there a way that I could access the e event arguments for a button that has not been clicked?
I need to delete multiple entries in a gridview by clicking a button and having it simulate clicking the delete button for each selected entry, but I can't use performClick, so I'm trying to call the actual method that deletes each one. However, that method requires an "e As System.Web.UI.WebControls.GridViewCommandEventArgs" parameter and I can't figure out how to get that.
You won't be able to access the EventArgs parameter.
I'd suggest you design your code like this:
public class MyClass
{
private ListView listView;
protected void OnClick(EventArgs e)
{
performAction();
}
private void performAction()
{
listView.deleteSelectedItems();
}
}
Don't implement functionality you are going to need somewhere else in delegates. Instead call this functionality inside the delegates' body. This way you can reuse performAction() somewhere else ..
Your problem calling delete button can be resolved if you add one check box in each row of datagrid and on click of button Delete you can perform delete operation for the checked rows in following manner
Protected void btnDelete_Click(object sender, EventArgs e)
{
for(int i = 0; i < GridView1.Rows.Count; i++)
{
CheckBox chkDelete = (CheckBox)GridView1.Rows[i].Cells[0].FindControl("chkSelect");
if(chkDelete != null)
{
if(chkDelete.Checked)
{
strID = GridView1.Rows[i].Cells[1].Text;
ids.Add(strID); //ids can colletion of any type
}
}
}
}
Now send ids to any function to perform delete.
Related
I have a asp:Repeater that has a DataSourceID to a custom collection.
The collection class has properties that I would like to display in the FooterTemplate. Because it calculate a value based on all the items.
In the FooterTemplate, is there a way to access the actual collection object? Maybe with Container or Eval.
I don't have direct access to the DataSource. I could change the code to have it as a parameter but would rather find an other way.
can you use something like this?
rpt.DataSource = mydatasource;
rpt.DataBind();
// label in footer
var lblDateTime = rpt.FindControl("lblDateTime") as Label;
if (lblDateTime != null)
{
lblDateTime.Text = mydatasource.First().DateChecked;
}
or like this
void R1_ItemDataBound(Object Sender, RepeaterItemEventArgs e)
{
// Execute the following logic for Footer only.
if (e.Item.ItemType == ListItemType.Footer) {
// put code here to get what you want and show it in the footer
}
}
During my override of OnActivate() in my view-model, I need to call GetView() in order to focus an element. When I do this after I have previously activated my view, it's fine. But when I call this the first activation, it fails.
I was able to get it to work by swapping a few lines in ConductorBaseWithActiveItem.ChangeActiveItem. The original is as follows:
protected virtual void ChangeActiveItem(T newItem, bool closePrevious) {
ScreenExtensions.TryDeactivate(activeItem, closePrevious);
newItem = EnsureItem(newItem);
if(IsActive)
ScreenExtensions.TryActivate(newItem);
activeItem = newItem;
NotifyOfPropertyChange("ActiveItem");
OnActivationProcessed(activeItem, true);
}
and with my changes:
protected virtual void ChangeActiveItem(T newItem, bool closePrevious) {
ScreenExtensions.TryDeactivate(activeItem, closePrevious);
newItem = EnsureItem(newItem);
activeItem = newItem;
NotifyOfPropertyChange("ActiveItem");
if (IsActive)
ScreenExtensions.TryActivate(newItem);
OnActivationProcessed(activeItem, true);
}
This seems to work. Notifying that "ActiveItem" changed triggers the code to load and cache the view. Then ScreenExtensions.TryActivate calls my OnActivate override.
Question: I haven't noticed any problems doing this, but I'm curious if anyone knows better than I do what repercussions this change could have?
Thanks!
One thing you could try is overriding Caliburn's OnViewAttached method and trying to focus it there. That being said, in MVVM, focus is more of a View concern, so if possible, that logic should be moved from the ViewModel to the View.
One way you may be able to solve this is by creating an attached behavior (you will need a reference to the Microsoft.Expression.Interactions assembly):
public class FocusWhenVisibleBehavior : Behavior<FrameworkElement>
{
protected override void OnAttached()
{
this.AssociatedObject.Loaded += this.Loaded;
this.AssociatedObject.IsVisibleChanged += this.VisibleChanged;
}
protected override void OnDetaching()
{
this.AssociatedObject.Loaded -= this.Loaded;
this.AssociatedObject.IsVisibleChanged -= this.VisibleChanged;
}
private void Loaded(object sender, RoutedEventArgs e)
{
this.TryFocus();
}
private void VisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
{
this.TryFocus();
}
private void TryFocus()
{
if (this.AssociatedObject.IsLoaded && this.AssociatedObject.IsVisible)
{
// Focus the control
this.AssociatedObject.Focus();
}
}
}
And that attaching that behavior to whatever control you want to focus:
<Button>
<i:Interaction.Behaviors>
<b:FocusWhenVisibleBehavior/>
</i:Interaction.Behaviors>
</Button>
I have a requirement in my program that the object bound (from ViewModel) in a Combobox is updated as soon as an item is selected in the combobox. Currently, the object only updates once the edit is committed by either pressing Enter or leaving the cell. The user does not want the extra step.
My thought would be to have the act of selecting an item in the combobox trigger the CommitEdit() method and then CancelEdit(). However, I cannot seem to find a way to hook into the SelectionChanged event for the DataGridComboBoxColumn as it is not available.
Other suggestions have been to listen in the viewmodel for a property change event but the property is not changed until the Cell Edit is finished.
Can anyone think of a way to cause the selection of a new item (index) in a DataGridCombobox to close the edit of the cell as if the user pressed Enter or left the cell?
NOTE: I cannot use .NET 4.5 due to customer limitations.
I've had similar issue but i just found out the solution using attached property, This may not exactly fix your problem but it will help in datagrid selection changed issue.
Below is the attached property and handler methods
public static readonly DependencyProperty ComboBoxSelectionChangedProperty = DependencyProperty.RegisterAttached("ComboBoxSelectionChangedCommand",
typeof(ICommand),
typeof(SpDataGrid),
new PropertyMetadata(new PropertyChangedCallback(AttachOrRemoveDataGridEvent)));
public static void AttachOrRemoveDataGridEvent(DependencyObject obj, DependencyPropertyChangedEventArgs args)
{
DataGrid dataGrid = obj as DataGrid;
if (dataGrid != null)
{
if (args.Property == ComboBoxSelectionChangedProperty)
{
dataGrid.SelectionChanged += OnComboBoxSelectionChanged;
}
}
else if (args.OldValue != null && args.NewValue == null)
{ if (args.Property == ComboBoxSelectionChangedProperty)
{
dataGrid.SelectionChanged -= OnComboBoxSelectionChanged;
}
}
}
private static void OnComboBoxSelectionChanged(object sender, SelectionChangedEventArgs args)
{
DependencyObject obj = sender as DependencyObject;
ICommand cmd = (ICommand)obj.GetValue(ComboBoxSelectionChangedProperty);
DataGrid grid = sender as DataGrid;
if (args.OriginalSource is ComboBox)
{
if (grid.CurrentCell.Item != DependencyProperty.UnsetValue)
{
//grid.CommitEdit(DataGridEditingUnit.Row, true);
ExecuteCommand(cmd, grid.CurrentCell.Item);
}
}
}
SpDataGrid is the custom control that i inherited from data grid.
I added below style in generic.xaml as i use the resourcedictionary for style (you can certainly add inside the datagrid).
<Style TargetType="{x:Type Custom:SpDataGrid}">
<Setter Property="Custom:SpDataGrid.ComboBoxSelectionChangedCommand" Value="{Binding ComboBoxSelectionChanged}"/>
</Style>
ComboBoxSelectionChanged is the command in my viewmodel. OnComboBoxSelectionChanged i commented the commitedit because in my case the values were already updated.
Let me know if anything is not clear or any questions. Hope this helps.
I have a parent page Page1 which has button1. Page1 has a usercontrol uc1. uc1 has an update panel inside which a grid grid1 is present. I am trying to set Page1.button1's visibility to false, depending on the row command event(there are some if conditions in the row command event) of uc1.grid1. I am setting Page1.button1's visibility in the following way:
Create a IsButton1Visible property in uc1. Set the property in UC1.Grid1.RowCommand to false, on page1 PreRender event, access IsButton1Visible and set Page1.button1 visibility.
Even though in quick watch Page1.button1 visibility is set to false at the line of assignment, when I see the UI, it is still visible. I don't know what I am doing wrong. Or the way that I am getting hold of button1 and its visibility is not correct.
In general can we set a Parent page's control's property from a user control during the user control event?
If you use the event-driven model approach
Delegate/EventArgs code:
public class ButtonVisiblityEventArgs : EventArgs
{
public ButtonVisiblityEventArgs(bool visible)
{
this.Visiblity = visible;
}
public bool Visiblity { get; private set; }
}
public delegate void UpdateParentButtonVisibilityEventHandler(object sender, ButtonVisiblityEventArgs args);
User control code:
public event UpdateParentButtonVisibilityEventHandler RaiseUpdateParentButtonVisibilityEvent;
private void RequestParentButtonVisibilityChange(bool setVisible)
{
if (RaiseUpdateParentButtonVisibilityEvent != null)
{
RaiseUpdateParentButtonVisibilityEvent(this, new ButtonVisiblityEventArgs(setVisible));
}
}
And in your command handler, just call:
RequestParentButtonVisibilityChange(false);
whenever you want to hide the button. On your page:
protected void Page_Load(object sender, EventArgs e)
{
this.RaiseUpdateParentButtonVisibilityEvent += new UpdateParentButtonVisibilityEventHandler(uc_RaiseUpdatecurrentDisplayPanelRequestEvent);
}
private void uc_RaiseUpdatecurrentDisplayPanelRequestEvent(object sender, ButtonVisiblityEventArgs args)
{
button1.Visible = args.Visiblity;
}
If the problem you are having is that your button lives outside of the update panel, you can do the following. Page codebhind:
protected void Page_Load(object sender, EventArgs e)
{
string hideScript = string.Format("function updateButtonVisibility( visibility ) {{ var button = $('#{0}'); if (visibility) {{ button.show(); }} else {{ button.hide(); }} }}", this.button1.ClientID);
Page.ClientScript.RegisterClientScriptBlock(this.GetType(), "updateButtonVisibility", hideScript, true);
}
And in your user control command handler:
bool shouldButtonBeVisible = false; //update this appropriately in your logic
ScriptManager.RegisterStartupScript(this, this.GetType(), "upUpdateButtonVisibility", "updateButtonVisibility(" + shouldButtonBeVisible ? "true" : "false" + ");", true);
Please note that this creates a TIGHT dependency between your UC and the page. It requires that any page that consumes this control has registered this script. There are ways to get around this (such as setting a function script callback to call, detecting if that javascript function exists, etc), but this should at least get you moving.
If there is something specific on the page after your update panel finishes that you could key off, it might be better to register an end request handler
$(function() { Sys.WebForms.PageRequestManager.getInstance().add_endRequest(updatePanelEndRequestHandler); } );
function updatePanelEndRequestHandler() {
var shouldBeVisible = $('.MyClassThatSaysIShouldntAllowMoreButtons').length > 0; //do some checking on the grid
updateButtonVisibility(shouldBeVisible);
}
you can put your user controls inside panels on your parent pages and change the visibility.
e.g.
<asp:Panel runat="server" ID="pnlQuote">
...
</asp:Panel>
<asp:Panel runat="server" ID="pnlContact">
<uc1:ContactForm runat="server" ID="ContactForm " />
</asp:Panel>
From the child control you can make a button click event which does something like this
protected void btnBackToQuote_Click(object sender, EventArgs e)
{
Panel pnlQuote = this.Parent.FindControl("pnlQuote") as Panel;
Panel pnlContact = this.Parent.FindControl("pnlContact") as Panel;
pnlQuote .Visible = true;
pnlContact.Visible = false;
}
I did follow the article TRULLY Understanding ViewState (great article btw) and populating my drop down list is working great. I've even setup a OnSelectedIndexChange event which fires almost as great.
The problem I've found is the SelectedIndexChanged event won't fire when selecting the 0th index. It does all other times however.
Here's some code:
<asp:DropDownList runat="server" ID="DropDownList1" EnableViewState="false"
AutoPostBack="True" OnSelectedIndexChanged="DropDownList1_SelectedIndexChanged" />
protected override void OnInit(EventArgs e)
{
this.DropDownList1.DataTextField = "Text";
this.DropDownList1.DataValueField = "Value";
this.DropDownList1.DataSource = fillQueueDropDown();
this.DropDownList1.DataBind();
base.OnInit(e);
}
protected void DropDownList1_SelectedIndexChanged(object sender, EventArgs e)
{
OnSelectedQueueChanged(e);
}
public void OnSelectedQueueChanged(EventArgs e)
{
// Do stuff.
}
public event EventHandler queueNamesChangedEvent;
public void OnSelectedQueueChanged(EventArgs e)
{
if (queueNamesChangedEvent != null)
queueNamesChangedEvent(this, e);
}
I suppose I can do some type of check in the Page_Load method:
if(ViewState["selectedIndexChangedFlag"] != 1)
// raise OnSelectedChange event
Or is there something I can setup in the OnInit() method where I'm rebinding this data everytime that i can do?
See, my custom EventHander raises an event which is caught by a the parent page in which this control resides, so that the parent could take some action using the newly selected value. And this is currently working for all cases where the selected index > 0.
I create a property in this control which contains the most recently selected index, in which case my parent page can action on this property value on every Page_Load... dunno.
Open to suggestions. Or how to force this SelectedIndexChanged event to fire for that 0th index selection.
The problem is that you are loading the data each time and this is resetting the selected index. Imagine this is your dropdown:
zero [selected]
one
two
Then in the client you change the selected index:
zero
one [selected]
two
This populates the hidden input __EVENTARGUMENT with your new index (1) and the hidden input __EVENTTARGET with the id of your dropdown. Now the server-side code kicks in and reloads your data:
zero [selected]
one
two
"zero" is the selected value because that is the default when the data is loaded. Then ASP.NET looks for __EVENTTARGET and __EVENTARGUMENT in the Request and finds your dropdown's id and finds the new index (1). Now your dropdown looks like this:
zero
one [selected]
two
Since the index has changed, the dropdown raises its SelectedIndexChanged event indicating that the index has changed. Obviously this is the part that is working, now lets see why selecting the first item in the list does not raise the event.
Now lets say that we still have the dropdown in the state it was just in (with "one" being selected and the selected index of 1). What happens when we select the first item in the list on the client?
__EVENTTARGET and __EVENTARGUMENT are populated with the id of the dropdown and the new index (0). Then the server loads the data into the dropdown and the dropdown now looks like this again:
zero [selected]
one
two
Notice that since you reloaded the data before the events fired the index is already set to 0 because that is the default. Now when your event fires and the dropdown's selected index is set to 0, the dropdown does not see this as a change since the selected index (as far as it knows) has not changed.
Here is how to fix the problem:
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
if (!Page.IsPostBack)
{
this.DropDownList1.DataTextField = "Text";
this.DropDownList1.DataValueField = "Value";
this.DropDownList1.DataSource = fillQueueDropDown();
this.DropDownList1.DataBind();
}
}
What this will do is only load the data into the dropdown if the page is not a postback. This means that ViewState will maintain the data for you as well as the selected index so that when you post back the dropdown will compare the new index to the index you saw in the client.
My goal with disabling the ViewState on this drop down list is to minimize the size of the ViewState for the page.
The problem I had with only doing the if(!Page.IsPostBack){...DataBind()...}, is that when you select an item for the first time, and the page reloads, my drop down list becomes empty.
What I ended up doing was creating another Property on this control, LastIndex. When the OnSelectedIndexChanged event fires, I update the LastIndex value. In the Page_Load, I compare the Current and Last index values, if they're different, then fire a Index changed event.
public int SelectedValue{
get { return this.DropDownList1.SelectedItem.Value; }
}
public int LastIndex{
get { return this.ViewState["lastIndex"] == null ? -1 : (int)this.ViewState["lastIndex"]; }
set { this.ViewState["lastIndex"] = value; }
}
protected override void OnInit(EventArgs e){
base.OnInit(e);
this.DropDownList1.DataTextField = "Text";
this.DropDownList1.DataValueField = "Value";
this.DropDownList1.DataSource = fillQueueDropDown();
this.DropDownList1.DataBind();
}
protected void Page_Load(object sender, EventArgs e){
if (this.LastIndex != this.SelectedValue)
this.OnSelectedQueueChanged(new EventArgs());
}
private ListItemCollection fillQueueDropDown(){...}
protected void DropDownList1_SelectedIndexChanged(object sender, EventArgs e){
OnSelectedQueueChanged(e);
this.LastIndex = this.SelectedValue;
}
public event EventHandler queueNamesChangedEvent;
public void OnSelectedQueueChanged(EventArgs e){
if (queueNamesChangedEvent != null)
queueNamesChangedEvent(this, e);
}
You are right though. The data is re-loaded and re-bound in the OnInit phase. Then the ViewState is restored (and when the 0th index is restored), when we finally get to the Events phase, the control doesn't detect the change.
Not sure this is the most elegant route, but it's working good so far.
Then i found this in the msdn docs for IPostBackDataHandler:
public virtual bool LoadPostData(string postDataKey,
NameValueCollection postCollection) {
String presentValue = Text;
String postedValue = postCollection[postDataKey];
if (presentValue == null || !presentValue.Equals(postedValue)) {
Text = postedValue;
return true;
}
return false;
}
Since the present value is the same as the changed-to value, the event isn't fired.