At first, this exception doesn't really make sense to me. Why shouldn't i be able to duplicate this object multiple times? but thats not the point:
i use a List. Whenever i navigate to a site, it should do this:
(App.Current as App).recent.ForEach(x => container.Children.Add(x));
(container = another StackPanel)
the first time, it works. afterwards, i get the exception displayed in the questiontitle. i already tried using a listbox, but i just got a ArgumentException. I think these exceptions have the same source, but i don't know what i'm doing wrong. please help
thanks
The error is quite clear: A WPF/SL Control can only belong to 1 Parent control at a time.
So you'll either have to remove the Controls from their Parent when you are moving away from a Page or you'll have to Create (possibly Clone) new Controls in this ForEach.
When you navigate to a page, the old instance is not removed instantly, so when you add your controls to the new page, they may still be used in the old page if it's not destroyed, causing the exception.
Try overriding the OnNavigatedFrom(NavigationEventArgs e) and OnNavigatingFrom(NavigatingCancelEventArgs e) methods that are invoked when you leave a page so that you empty your StackPanel.
For example, you could do :
protected override void OnNavigatedFrom(NavigationEventArgs e)
{
base.OnNavigatedFrom(e);
container.Children.Clear();
}
You have to remove the container's children when you navigate from the page. But not if the navigation is due to a suspend. To avoid the children clear when the navigation is due to a suspend it is better to override OnNavigatingFrom instead of OnNavigatedFrom
protected override void OnNavigatingFrom(NavigatingCancelEventArgs e)
{
container.Children.Clear();
base.OnNavigatingFrom(e);
}
Related
I am creating a custom web control that I need only one instance of control user can add in page, same like scriptmanager.
I need this check under custom control it self but not getting any correct approach, I know by iterating page.controls property I can check existence of control but I would like to know is it only a way? or is there any other generic/right way to check like scriptmanager does when more than one instance found in page.
First thing come to my mind..
on your custom control..
protected override void OnInit(EventArgs e)
{
if (Context.Items.Contains("MyCustomControl"))
throw new Exception("only one instance of a MyCustomControl can be added to the page");
Context.Items["MyCustomControl"] = true;
base.OnInit(e);
}
I'm developing a Silverlight 4 RIA application. There is a DataGrid storing data and two buttons: add a new item and remove an item. After creating a new item for the second time the application freezes like this - I'll explain the strange behaviour below.
The scenario of creating a new item looks like this:
After clicking, the child window appears. The reference to the domain data source used on the parrent page is being
passed to the child window in the constructor.
The user chooses a file.
The file is send to a web service. In response the web service returns some data from that file.
A new data object is being created and inserted to domain data source.
The child window causes the entire application to freeze only when it's called twice, but the first call requires object creation. I can open and close the child window repeatedly and everything will work fine until a sequence of: open.create -> open.close / open.create occurs. I tried to trace all exceptions with VS tool (alt ctrl e) but there are none.
A breakpoint on
private void Application_UnhandledException(object sender, ApplicationUnhandledExceptionEventArgs e)
does not show anything either. Any ideas?
Page code.
Child window code
Remove the following and everything will be fine.
private void ChildWindow_Closed(object sender, EventArgs e)
{
this.DialogResult = false;
}
And to evaluate a bit more, ChildWindow_Closed is the outcome of setting the DialogResult at the first place.
By re setting it unexpected things happen.
I did a bit more research after you helped me with this issue. Seems its a SL4 bug.
This should also help. Topic about this on SL forums.
protected override void OnClosed(EventArgs e)
{
base.OnClosed(e);
Application.Current.RootVisual.SetValue(Control.IsEnabledProperty, true);
}
As you can see, I want to navigate to "ScoreInputDialog.xaml" page, where the user can type in a name. After this I am trying to save the name to a list, but it is always empty because navigation to page "ScoreInputDialog.xaml" is being done at last. How can I navigate to the desired page and get my value before continuing with rest of the code?
NavigationService.Navigate(new Uri("/ScoreInputDialog.xaml", UriKind.Relative)); // Sets tempPlayerName through a textbox.
if (phoneAppService.State.ContainsKey("tmpPlayerName"))
{
object pName;
if (phoneAppService.State.TryGetValue("tmpPlayerName", out pName))
{
tempPlayerName = (string)pName;
}
}
highScorePlayerList.Add(tempPlayerName);
You should do nothing directly after the Navigate call. Instead override the OnNavigatedTo method of the page you are coming from, to get notified when the user comes back:
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
This method will be called when the user exits the "ScoreInputDialog.xaml", probably by pressing the back button or because you call NavigationService.GoBack(). This exits the "ScoreInputDialog.xaml" page and goes to the previous page, where the OnNavigatedTo will be called. This is the time to check for the value.
Illustration of the navigation flow:
"OriginPage" ---[Navigate]---> "ScoreInputDialog" ---[GoBack() or Back-button]---> "OriginPage" (*)
Where the (*) is there the OnNavigatedTo will be called. The implementation could look like this:
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
if (phoneAppService.State.ContainsKey("tmpPlayerName"))
{
object pName;
if (phoneAppService.State.TryGetValue("tmpPlayerName", out pName))
{
tempPlayerName = (string)pName;
}
highScorePlayerList.Add(tempPlayerName);
}
}
Remember to clear the temp player name before calling Navigate:
phoneAppService.State.Remove("tmpPlayerName");
NavigationService.Navigate(new Uri("/ScoreInputDialog.xaml", UriKind.Relative));
Note: OnNavigatedTo will also be called when the user sees the page the first time or navigates back from other pages than "ScoreInputDialog.xaml". But then the "tmpPlayerName" value will not be set.
Navigate isn't being performed last, it is just happening asynchronously. You have to wait for the navigation to complete.
http://msdn.microsoft.com/en-us/library/system.windows.navigation.navigationservice.navigated.aspx
Read the following page : http://msdn.microsoft.com/en-us/library/ms615507.aspx
At the bottom after the Methods and Properties definitions in the "Remark" part it explains how the NavigationService Class works and this nice little graphic explains a lot :
I'm in a situation where I need a listbox to remember after postback the attributes I've added to a number of the listitems in it. I found this solution online which appears to solve the issue but am not sure how to implement it.
List box solution
He says he wrote a class that inherits from Listbox which is fine, I've done that and have called it EnhancedListBox but how do I then apply that to the Listbox I'm using on the page?
I can't just substitute
<asp:ListBox >
with
<asp:EnhancedListBox>
but how else do I let the page know I want to use my inherited code?
Thanks.
SaveViewState and LoadViewState are virutal methods that you can override. What you want to try is creating "your own" ListBox:
class EnhancedListBox : ListBox
{
protected override object SaveViewState()
{
// code here from the tutorial
}
protected override void LoadViewState(object savedState)
{
// code here from the tutorial
}
}
This is also called "Creating a custom control", it's very common to do it this way and it gives you great flexibility.
you need to create a custom control for this
check this out http://msdn.microsoft.com/en-us/library/ms366537.aspx for the startup.
I have a button in my user control which should be used to remove the user control from its parent container. This is the way I have coded it today.
private void RemoveRoleButton_Click(object sender, RoutedEventArgs e)
{
if (ConfirmRoleRemoval())
{
Panel parentPanel = (Panel)this.Parent;
parentPanel.Children.Remove(this);
}
}
private bool ConfirmRoleRemoval()
{
return MessageBox.Show("Are you sure [...]
}
Is it normal to do it this way in WPF?
Yes, it looks fine to me. As Mike Hillberg writes in his blog:
An element doesn’t actually pick its logical parent; instead, a parent “adopts” children.
Thus, it makes sense that "removing" a child is also done through the object model of the parent.
As a side note: You might want to consider throwing a "nice" exception (or even disabling the button) when the parent is not a Panel (rather than waiting for the InvalidCastException).