So I have a user control with six textboxes and a few buttons. One of those buttons is 'clear'. When I click the clear button, in the btnClear_Click handler, I want to find all the textboxes in my user control (and ONLY in my user control). And then set them to an empty string. That's it. That's all.
This is turning out to be a herculean, insurmountably difficult thing to do. Finding an answer is like trying to map the human genome. I just want to ITERATE THROUGH THE CONTROLS. Nothing more.
I'm not interested in hearing about the merits of what I'm trying to do. Just the mechanics of how to do it. Something like this:
public partial class myUserControl: UserControl
{
private void btnClear_Click(object sender, RoutedEventArgs e)
{
var allMyControls = SomeMiraculousOperationToGetAllControlsThatOnlyExistInMyUserControl();
foreach (var control in allMyControls)
{
if (control is TextBox)
((TextBox)control).Text = string.Empty;
}
}
}
You can use the VisualTreeHelper to enumerate the child controls of your user control.
You can find an extension method base on this class here
public static T GetChildOfType<T>(this DependencyObject depObj)
where T : DependencyObject
{
if (depObj == null) return null;
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
{
var child = VisualTreeHelper.GetChild(depObj, i);
var result = (child as T) ?? GetChildOfType<T>(child);
if (result != null) return result;
}
return null;
}
Related
Good day
I have a new field inside the CROpportunity Extenstion called usrGrossProfit.
During CROpportunity's RowSelected it works out the values as needed. The problem I am having is that the users are using the create Quote button on the form and because of this never saves using the save button, The system does it for them. I have found that because of this the usrGrossProfit value is not saved.
Is there a way to force a save/Persist inside the RowSelected function?
protected void CROpportunity_RowSelected(PXCache cache, PXRowSelectedEventArgs e)
{
try
{
var row = (CROpportunity)e.Row;
if (row == null) return;
CROpportunityExt SOE = PXCache<CROpportunity>.GetExtension<CROpportunityExt>(row);
int total = 0;
decimal TotalSales = 0;
decimal TotalCost = 0;
foreach (CROpportunityProducts item in this.Base.Products.Select())
{
total++;
CROpportunityProductsExt2 itemExt = PXCache<CROpportunityProducts>.GetExtension<CROpportunityProductsExt2>(item);
TotalCost += (decimal)itemExt.UsrCostPrice.Value * item.Qty.Value;
TotalSales += (decimal)itemExt.UsrSellingprice * item.Qty.Value;
}
SOE.UsrGrossProfit = TotalSales - TotalCost;
// I added this just to try and see if it helps
cache.SetValueExt<CROpportunityExt.usrGrossProfit>(row, (decimal)(TotalSales - TotalCost));
// we are not allowed to press the save button in the event Handler
//this.Base.Save.Press();
}
catch (Exception ex)
{
PXTrace.WriteError(ex);
}
}
I have also tried to override the CreateQuote Function but this doesn't work
public delegate IEnumerable CreateQuoteDelegate(PXAdapter adapter);
[PXOverride]
public IEnumerable CreateQuote(PXAdapter adapter, CreateQuoteDelegate baseMethod)
{
this.Base.Persist();
return baseMethod(adapter);
}
I have also made a business event to open and save the Opportunity also with no luck.
No, you shouldn't save on row selected even if it was allowed. This is because row selected event gets fired several times and you don't want to be saving each time.
If you want to save on your CreateQuote override, try this:
Base.Save.PressButton(adapter)
Perhaps a better option, might be to force the user so that it's the user himself who saves. For example, you could check the state and throw an error in your override instead of saving.
if (Opportunity.Current != null && Opportunity.Cache.GetStatus(Opportunity.Current) == PXEntryStatus.Inserted)
{
throw new PXException("Please save before proceeding");
}
I am using MVVMCross 3.2.2 as part of an iOS/Android app. One of my screens has multiple views that are displayed depending upon the selection in a Tab bar like row of buttons. Different data is displayed in each of these these views individual UITableView. The data binding works perfectly.
I also have a menu, that has a "profile" selection. Changing the profile fires an MvxMessage that my HomeView receives and then uses the message to set the ViewModel up to filter the data to be displayed. This all seems to work perfectly and the data is displayed correctly.
If I do something in the HomeView that displays another view using ShowViewModel(). When I return back to the home view the binding no longer works properly when a profile changes is made. The message gets handled, the data gets filtered, but a call to ReloadDataTable on the UITableView does not change the data.
ViewModel
#region Groupings
public IList<Group> Groups{
get { return _groupService.GetAll(); }
}
public void SetupSubGroups(Group group)
{
if (group == null)
{
_groups = new ObservableCollection<Group> ();
if (_profileService.SelectedProfile != null)
{
var grp = _groupService.GetByGroupName (_profileService.SelectedProfile.Name);
if (grp == null)
grp = new Group { Name = _profileService.SelectedProfile.Name };
_groups.Add (grp);
}
}
else
{
var litsOfGroups = _groupService.GetSubGroups (group);
foreach (var grp in litsOfGroups)
_groups.Add (grp);
}
RaisePropertyChanged(() => AvailableGroups);
}
private ObservableCollection <Group> _groups;
public ObservableCollection<Group> AvailableGroups {
get { return _groups; }
}
#endregion
ViewController
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
var groupSource = new GroupTableViewDataSource (TableViewGroups);
TableViewGroups.Source = groupSource;
_localViewModel.SetupSubGroups (null);
_bindingSet = this.CreateBindingSet<HomeViewController, HomeViewModel> ();
_bindingSet.Bind (groupSource).To (vm => vm.AvailableGroups);
_bindingSet.Apply ();
TableViewReportTags.ReloadData ();
NavigationController.NavigationBarHidden = false;
}
private void OnProfileChanged(ProfileChangedMessage message)
{
_localViewModel.SetupSubGroups (null);
TableViewGroups.ReloadData ();
}
private HomeViewModel _localViewModel { get { return ViewModel as HomeViewModel; } }
Any ideas what I can look at, or change would be really useful. I have spend many hours on this, and have made no progress.
I am dynamically creating a RadGrid and adding GridTemplateColumns to it. Those columns have textbox in them.
After binding datatable to the grid, after user makes changes to the textboxes and on clicking save button, I would like to access the textbox values. But I am stuck at getting hold of the textbox instance. I couldn't even get hold of GridItems!
To add more complexity, my RadGrid is in a UserControl, which is in a (multi)view.
Heres the code.
protected void Page_Init(object sender, EventArgs e)
{
DefineGridStructure();
}
protected void Page_Load(object sender, EventArgs e)
{
if (RadGrid1 != null && RadGrid1.Items.Count > 0)
{
string strtxt = ((TextBox)RadGrid1.Items[1]["ProductGroup1"].Controls[0]).Text;//For starters, load one control and check it's state
}
}
private void DefineGridStructure()
{
RadGrid1 = new RadGrid();
RadGrid1.AutoGenerateColumns = false;
RadGrid1.ShowHeader = true;
RadGrid1.NeedDataSource += RadGrid1_NeedDataSource;
foreach(GridColumn qtyColumn in BuildGridQtyColumns(PaxColumnCount))
{
RadGrid1.MasterTableView.Columns.Add(qtyColumn);
}
//Add grid to page
phRadGrid.Controls.Add(RadGrid1);
}
private List<GridColumn> BuildGridQtyColumns(int count)
{
List<GridColumn> qtyColumns = new List<GridColumn>();
for (int i = 1; i <= count; i++)
{
string qtyColumnName = string.Format("ProductGroup{0}", i);
GridTemplateColumn qtyColumn = new GridTemplateColumn();
qtyColumn.ItemTemplate = new GridNumberTemplate(qtyColumnName);//Creates a textbox control
qtyColumn.UniqueName = qtyColumnName;
qtyColumn.HeaderText = "Qty";
qtyColumn.HeaderStyle.Width = Unit.Pixel(60);
qtyColumn.HeaderStyle.HorizontalAlign = HorizontalAlign.Center;
qtyColumns.Add(qtyColumn);
}
return qtyColumns;
}
Since my control is in view, it's Page_Init is called more than once for each action that involves this view.
For a dynamically generated radgrid, it should be created in page_init method and viewstate for this grid will be restored for us automatically which we can get hold of in page_load method.
Im trying to locate an SPDataSource control located on my SharePoint page. I found the following code which probably works fine, I just don't know what to pass into it.
public static Control FindControlRecursive(Control Root, string Id)
{
if (Root.ID == Id)
return Root;
foreach (Control Ctl in Root.Controls)
{
Control FoundCtl = FindControlRecursive(Ctl, Id);
if (FoundCtl != null)
return FoundCtl;
}
return null;
}
I don't know how to have it search the whole page or at the very least the ContentPlaceHolder that the control is in.
edit
Looks like I have a more rudimentary issue here. Not sure how to explain but I'm not opening up the page before running my code. I'm opening the site via the following:
using (SPWeb web = thisSite.Site.OpenWeb("/siteurl/,true))
So when I try to find the page below I'm getting Object reference not set to instance of object.
var page = HttpContext.Current.Handler as Page;
Perhaps I'm going about this the wrong way, I'm in my infancy here so I'm just kind of stumbling along figuring stuff out!
What you got is actually not SharePoint specific, it's c# asp.net.
Anyway, you could call it like this
var page = HttpContext.Current.Handler as Page;
var control = page; // or put the element you know exist that omit (is a parent) of the element you want to find
var myElement = FindControlRecursive(control, "yourelement");
Most likely you'll need to cast the return as well
var myElement = (TextBox)FindControlRecursive(control, "yourelement");
// or
var myElement = FindControlRecursive(control, "yourelement") as TextBox;
There are however more efficient ways to write such a method, here is one simple example
public static Control FindControlRecursive(string id)
{
var page = HttpContext.Current.Handler as Page;
return FindControlRecursive(page, id);
}
public static Control FindControlRecursive(Control root, string id)
{
return root.ID == id ? root : (from Control c in root.Controls select FindControlRecursive(c, id)).FirstOrDefault(t => t != null);
}
Call it the same way as I suggested earlier.
If you are handling larger pages the methods above might be a bit slow, what you should do is aim for a method using generics instead. They are way faster than traditional methods.
Try this one
public static T FindControlRecursive<T>(Control control, string controlID) where T : Control
{
// Find the control.
if (control != null)
{
Control foundControl = control.FindControl(controlID);
if (foundControl != null)
{
// Return the Control
return foundControl as T;
}
// Continue the search
foreach (Control c in control.Controls)
{
foundControl = FindControlRecursive<T>(c, controlID);
if (foundControl != null)
{
// Return the Control
return foundControl as T;
}
}
}
return null;
}
You call it like this
var mytextBox = FindControlRecursive<TextBox>(Page, "mytextBox");
Is there any way to prevent the change of a tab in TabControl in Silverlight 4?
A simple case is when I've got a form with some data, and I want to ask the user if he/she wants to save this data before actually changing the tab.
I've seen code examples on how to do this in WPF, but not in Silverlight.
What can I do to stop the tab from changing?
Bind SelectedIndex to a property on your data context.
<sdk:TabControl SelectedIndex="{Binding SelectedIndex, Mode=TwoWay}">
<sdk:TabItem Header="TabItem">
<Grid Background="#FFE5E5E5"/>
</sdk:TabItem>
<sdk:TabItem Header="TabItem">
<Grid Background="#FFE5E5E5"/>
</sdk:TabItem>
</sdk:TabControl>
In the SET accessor, write your code to check whether the user really wants to do what they're trying to do.
public class Context : INotifyPropertyChanged
{
int _SelectedIndex = 0;
public int SelectedIndex
{
get
{
return _SelectedIndex;
}
set
{
MessageBoxResult result = MessageBox.Show("Do you want to save?", "Really?", MessageBoxButton.OKCancel);
if (result == MessageBoxResult.OK)
{
_SelectedIndex = value;
}
RaisePropertyChanged("SelectedIndex");
}
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
}
Net effect is, if the user chooses 'cancel' on the dialogue the private variable is never changed - the PropertyChanged event fires, rebinding the selected index to the existing value.
Hope this is what you were trying to accomplish.
UPDATE (11/10/2012) - Alternate method (possibly for SL5?). Write code behind to tie into SelectionChanged event of your TabControl, reset the tab control's selected item property based on your test.
private void TabControl_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
{
if (e.RemovedItems.Count > 0)
{
MessageBoxResult result = MessageBox.Show("Do you want to save?", "Really?", MessageBoxButton.OKCancel);
if (result != MessageBoxResult.OK)
{
((TabControl)sender).SelectionChanged -= new SelectionChangedEventHandler(TabControl_SelectionChanged);
((TabControl)sender).SelectedItem = e.RemovedItems[0];
((TabControl)sender).SelectionChanged += new SelectionChangedEventHandler(TabControl_SelectionChanged);
}
}
}