WPF Mainwindow closed automatically after refresh the child Usercontrol inside mainwindow - wpf

I am developing WPF application which contains MainWindow.xaml as container to display all user controls inside the Mainwindow .I have defined all the menus inside the Mainwindow.xaml and displaying the respective usercontol inside mainwindow.xaml grid.
Below is my Mainwindow grid definition and respective codebehind event handler code
<Grid x:Name="Container" Grid.Column="0" Width="0" Margin="0,0,0,10" Visibility="Visible">
</Grid>
Code Behind Menu click Event Handler
When the maindow is loaded after login it will call and display the CustomerListView user control
private void Window_Loaded(object sender, RoutedEventArgs e)
{
CustomerListView CLView = new CustomerListView ();
Container.Children.Clear();
Container.Children.Add(CLView );
Container.Children[0].SetValue(WidthProperty, CLView.Width);
Container.Children[0].SetValue(HeightProperty, CLView.Height);
}
//Customer Menu Click Event
public void NewCustomer_Menu_Click(object sender, RoutedEventArgs e)
{
//AddCustomer is User control
AddCustomer AddEmployeeObject = new AddCustomer();
Container.Children.Clear();
Container.Children.Add(AddEmployeeObject);
Container.Children[0].SetValue(WidthProperty, AddEmployeeObject.Width);
Container.Children[0].SetValue(HeightProperty, AddEmployeeObject.Height);
}
Everything works fine until i integrate my application by new login control.After successful login i displayed mainwindow. If i am doing some actions like adding new customers(separate user control) or editing new customers(seperate user control) my application get closed automatically.How to overcome this issue?
Code to display mainwinow after logged in
if (IsValidUser)//Bool variable to validate user
{
//Hide the Loginwindow
this.Hide();
//Display mainwindow
MainWindow objMainWindow = new MainWindow();
objMainWindow.ShowDialog();
}
If i do any update or insert operations it closes the application after insert or update or refresh.
It seems every time Maindow is reloads after the insert or update or trying to load another user control or refresh the user control inside the mainwindow grid.How to resolve this?

You are clearing your Grid named Container every time you add a new Customer object by calling Container.Children.Clear(). Don't add new controls in code behind, instead define your UI in XAML and use data binding to visualize the objects you are adding.
Some links for you to read:
Data Binding Overview: http://msdn.microsoft.com/en-us/library/ms752347(v=vs.110).aspx
ObservableCollection: http://msdn.microsoft.com/en-us/library/ms668604(v=vs.110).aspx

Woha !!! Got the solution finally. I have defined the button with IsCancel="True" property.So when ever i submit the data it closes the Mainwindow.It's just the copy paste mistake and finally removed the IsCancel attribute and works fine.

Related

How to pass data from user control to main control in wpf

I have status bar control in the main winodw. I have a user control placed in the main window.My user conrtorl has buttons .
say if i click the button in the user control ,I need to update the main window status bar .
I am following MVVM pattern. I am not sure how to achive this. I am beginner in wpf.
You need to use Dependency Property to send something to Main Control from UserControl.
For eg: If you want to change the text of a textblock present in the Main Window from a button Click present in USerControl.
You need to bind your DependencyProperty to the TextBlock TEXT property to reflect the change and your USERCONTROL must Implement INotifyPropertyChange
Make this DependencyProperty in your UserControl
public static readonly DependencyProperty TextProperty = DependencyProperty.Register("WriteText", typeof(string), typeof(UserControlnameSpace)) //Write Namespace of your UserControl where I mentioned
public string WriteText
{
get { return (bool)GetValue(TextProperty ); }
set
{
SetValue(TextProperty , value);
}
}
ButtonClick event present in USERCONTROL
public void Button_Click(object sender, RoutedEventArgs e)
{
WriteText="Hie"; //Write what you want to display on MainWindow.
}
ViewModel:-
private string _txtContent;
public string TxtContent
{
get
{
return _txtContent;
}
set
{
_txtContent = value;
RaisePropertyChanged("TxtContent");
}
}
Main Window:-
<TextBlock Text="{Binding TxtContent,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
Where you are including your UserControl:-Include this property
<UserControl WriteText={Binding TxtContent Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" />
You can set the DataContext(viewmodel) of the user control same as that of Main Window. Keep a property in viewModel and Bind that Property in the user control. So whenever anything changes in the Control that property will automatically be updated in the View Model which can be used by the Main
I would suggest that the usercontrol works with its own viewmodel. The main windows has a main controller which is responsible to initialize a Status bar messenger service and the user control view model uses that service.
User control's view model is bound to the button's actions via RelayCommand and on executing action it uses the status bar service to update the status.
This is enable your status bar on the main window to work with multiple user controls/pages of your application.

wpf window event continue raise after window is closed

I have a problem with wpf events.
In the xaml I have following combobox with selectionchanged event:
<ComboBox Grid.Column="1" Grid.Row="1" Name ="comboBox"
SelectedItem="{Binding CurrentEventBinding.ControlId, ValidatesOnDataErrors=True}"
ItemsSource="{Binding ControlsNames}" SelectionChanged="ComboboxSelectionChanged">
In the codebehind I have following code:
private void ComboboxSelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e) {
(DataContext as EventBindingEditViewModel).VmCommands.UpdateSourceCommand.Execute(null);
}
And I have the following working scenario:
Window.ShowDialog(); -> ComboboxSelectedChanged (the event is raised) -> CloseWindow();
Then again: Window.ShowDialog(); -> ComboboxSelectedChanged (the event is raised twice)
And if in the immediate window I write sender.GetHashCode() it returns first time the hashcode for the combobox from current window, and at the second time it returns the hashcode of the 'died' window.
So the event is raised so many times as the window is showed. It looks like old comboboxes aren't disposed or something like that.
Hope you understand my problem.
Thanks in advance!
The cause is that you are using binding, and it's still working after window closing. Then you change selected item in one window, it's changing selected item in other window (which is closed) via bindings. To resolve this, you should set DataContext = null in closed window. Or you can use the same window every time, just not close it, but hide.
Give the combobox a name and subscribe to SelectionChanged from code instead of XAML. On Window closing, unsubscribe from the event to make sure that it get's disposed.
<ComboBox Name="MyComboBox"....... />
And then in code:
protected override void OnSourceInitialized(EventArgs e)
{
MyComboBox.SelectionChanged += ComboBoxSelectionChanged;
}
protected override void OnClosing(CancelEventArgs e)
{
MyComboBox.SelectionChanged -= ComboBoxSelectionChanged;
}
Do you create the window with new Window() everytime, or it is a singleton ? Make sure to unsubscribe in the same manner from all events that you subscribed. Otherwise, the window that you close will never be disposed.

The best approach to show/hide windows indpendently

I am a student and am building a C# WPF application. It has three windows:
Sign in window
Create account window
and Main application window.
I uploaded a figure to show the type of navigation I am trying to implement:
I do not think it is correct to make a window show up/hide inside the close/load event of another window.
Can someone show me the right way to implement this navigation?
Also, is it a good practice to make the three windows private properties of the application class?
The last window has a frame control to support page navigation. Again, is it better to make the three pages private properties of MainWindow application?
I am sorry if this is so obvious or easy to do.
Thanks
I would not have the three windows as properties of the application. I'd instanciate a copy of the sign-in window and use that as my central point of control.
When the user logs in, hide the sign in window, show a new main window and add a hook on the main windows Closed event.
e.g
if (logonSuccess)
{
var mainWindow = new MainWindow();
mainWindow.Closed += ReshowSignupWindow;
}
I'd also have the sign-in window do the same for the create account window. Thus, I'd have the create account window return to the signup window which would either reshow itself or start the main window if an account was created.
e.g.:
// In sign-in window, handle the create window being closed
private void CreateWindowClosedHandler(object sender, EventArgs e)
{
if (accountCreatedOK)
{
ShowMainWindow();
}
else
{
ReshowSignupWindow();
}
}
I'd probably look at having the create account window shown as a dialog window via a call to ShowDialog().
Hope that helps...
Something like this code might do it (untested, I just typed it in visual studio to autoformat the code)
The XAML is for the Login Dialog. The RegistrationDialog should be similar, except for the button and handler for the registration Button.
<Window x:Class="WpfApplication1.LoginWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="LoginWindow">
<StackPanel>
<Button IsDefault="True" Content="Submit" Click="SubmitButton_Click"/>
<Button IsCancel="True" Content="Cancel" />
<Button Content="CreateAccount" Click="CreateAccountButton_Click"/>
</StackPanel>
</Window>
//Handler of LoginWindow and RegistrationWindow
private void SubmitButton_Click(object sender, RoutedEventArgs e)
{
this.DialogResult = true;
}
//Handler of LoginWindow only
private void CreateAccountButton_Click(object sender, RoutedEventArgs e)
{
this.IsCreatingAccount = true;
this.DialogResult = false;
}
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
bool isCanceled;
while (loginWin.ShowDialog() == false && !isCanceled)
{
if (loginWin.IsAccountCreationRequested)
{
if (registrationWin.ShowDialog())
{
isCanceled = true;
}
else
{
loginWin.IsAccountCreationRequested = false;
}
}
else
{
isCanceled = true;
}
}
if (loginWin.DialogResult) MainWindow.Show();
}
}
I am currently working on a Silverlight Application which is more or less similar to your application. What i feel is your can have 2 xaml controls(one for Login and other for your main application). For create account, you can use a child window which will be called from login control. And use a TabControl in your main application which will hold your other 3 xaml controls(Page1.xaml, Page2.xaml and Page3.xaml). Feel free to ask if you have any issues.
Dont forget to mark my reply as answer if it solves your problem.
I suggest you to follow the pattern. Your logic looks tightly binding with UI(user Interface) and logics.
The best pattern i like is for WPF or Silverlight is MVVM(Model View View Model). There are lot of Examples available in google for MVVM.
Just put a glance in anyone MVVM example you will be clear in developing WPF or Silverlight app.
some links are below,
http://msdn.microsoft.com/en-us/magazine/dd419663.aspx
http://www.c-sharpcorner.com/UploadFile/raj1979/simple-mvvm-pattern-in-wpf/
http://www.codeproject.com/Articles/126249/MVVM-Pattern-in-WPF-A-Simple-Tutorial-for-Absolute

What event is raised on Grid.Children.Add

In my WPF application, I have a single Main window with a Grid. The Login and Shell are 2 separate UserControls added as children to a grid. I need to find out when the Shell is loaded and start a timer from the Main window.
I just need to know as to what event is raised when a UserControl is added using Grid.Children.Add method, so that I can check if Login is loaded or the Shell and start the timer.
I'm not quite sure what you're trying,
but it sounds like you're looking for the Load event:
UserControl MyControl = new UserControl();
MyControl.Loaded += new RoutedEventHandler(MyControl_Loaded);
public void MyControl_Loaded(object sender, RoutedEventArgs e)
{
if (((UserControl)sender).IsLoaded)
{
..... do something
}
}
Hope it helps

Can't set focus to a child of UserControl

I have a UserControl which contains a TextBox. When my main window loads I want to set the focus to this textbox so I added Focusable="True" GotFocus="UC_GotFocus" to the UserControls definition and FocusManager.FocusedElement="{Binding ElementName=login}" to my main windows definition. In the UC_GotFocus method i simply call .Focus() on the control i want to focus on but this doesn't work.
All i need to do is have a TextBox in a UserControl receive focus when the application starts.
Any help would be appreciated, thanks.
I recently fixed this problem for a login splash screen that is being displayed via a storyboard when the main window is first loaded.
I believe there were two keys to the fix. One was to make the containing element a focus scope. The other was to handle the Storyboard Completed event for the storyboard that was triggered by the window being loaded.
This storyboard makes the username and password canvas visible and then fades into being 100% opaque. The key is that the username control was not visible until the storyboard ran and therefore that control could not get keyboard focus until it was visible. What threw me off for awhile was that it had "focus" (i.e. focus was true, but as it turns out this was only logical focus) and I did not know that WPF had the concept of both logical and keyboard focus until reading Kent Boogaart's answer and looking at Microsoft's WPF link text
Once I did that the solution for my particular problem was straightforward:
1) Make the containing element a focus scope
<Canvas FocusManager.IsFocusScope="True" Visibility="Collapsed">
<TextBox x:Name="m_uxUsername" AcceptsTab="False" AcceptsReturn="False">
</TextBox>
</Canvas>
2) Attach a Completed Event Handler to the Storyboard
<Storyboard x:Key="Splash Screen" Completed="UserNamePassword_Storyboard_Completed">
...
</Storyboard>
and
3) Set my username TextBox to have the keyboard focus in the storyboard completed event handler.
void UserNamePassword_Storyboard_Completed(object sender, EventArgs e)
{
m_uxUsername.Focus();
}
Note that calling item.Focus() results in the call Keyboard.Focus(this), so you don't need to call this explicitly. See this question about the difference between Keyboard.Focus(item) and item.Focus.
Its stupid but it works:
Pop a thread that waits a while then comes back and sets the focus you want. It even works within the context of an element host.
private void ListView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
System.Threading.ThreadPool.QueueUserWorkItem(
(a) =>
{
System.Threading.Thread.Sleep(100);
someUiElementThatWantsFocus.Dispatcher.Invoke(
new Action(() =>
{
someUiElementThatWantsFocus.Focus();
}));
}
);
}
Just recently I had a list-box that housed some TextBlocks. I wanted to be able to double click on the text block and have it turn into a TextBox, then focus on it and select all the text so the user could just start typing the new name (Akin to Adobe Layers)
Anyway, I was doing this with an event and it just wasn't working. The magic bullet for me here was making sure that I set the event to handled. I figure it was setting focus, but as soon as the event went down the path it was switching the logical focus.
The moral of the story is, make sure you're marking the event as handled, that might be your issue.
“When setting initial focus at application startup, the element to
receive focus must be connected to a PresentationSource and the
element must have Focusable and IsVisible set to true. The recommended
place to set initial focus is in the Loaded event handler"
(MSDN)
Simply add a "Loaded" event handler in the constructor of your Window (or Control), and in that event handler call the Focus() method on the target control.
public MyWindow() {
InitializeComponent();
this.Loaded += new RoutedEventHandler(MyWindow_Loaded);
}
void MyWindow_Loaded(object sender, RoutedEventArgs e) {
textBox.Focus();
}
since i tried a fuzquat's solution and found it the most generic one, i thought i'd share a different version, since some complained about it looking messy. so here it is:
casted.Dispatcher.BeginInvoke(new Action<UIElement>(x =>
{
x.Focus();
}), DispatcherPriority.ApplicationIdle, casted);
no Thread.Sleep, no ThreadPool. Clean enough i hope.
UPDATE:
Since people seem to like pretty code:
public static class WpfExtensions
{
public static void BeginInvoke<T>(this T element, Action<T> action, DispatcherPriority priority = DispatcherPriority.ApplicationIdle) where T : UIElement
{
element.Dispatcher.BeginInvoke(priority, action);
}
}
now you can call it like this:
child.BeginInvoke(d => d.Focus());
WPF supports two different flavors of focus:
Keyboard focus
Logical focus
The FocusedElement property gets or sets logical focus within a focus scope. I suspect your TextBox does have logical focus, but its containing focus scope is not the active focus scope. Ergo, it does not have keyboard focus.
So the question is, do you have multiple focus scopes in your visual tree?
I found a good series of blog posts on WPF focus.
Part 1: It’s Basically Focus
Part 2: Changing WPF focus in code
Part 3: Shifting focus to the first available element in WPF
They are all good to read, but the 3rd part specifically deals with setting focus to a UI element in a UserControl.
Set your user control to Focusable="True" (XAML)
Handle the GotFocus event on your control and call yourTextBox.Focus()
Handle the Loaded event on your window and call yourControl.Focus()
I have a sample app running with this solution as I type. If this does not work for you, there must be something specific to your app or environment that causes the problem. In your original question, I think the binding is causing the problem.
I hope this helps.
After having a 'WPF Initial Focus Nightmare' and based on some answers on stack, the following proved for me to be the best solution.
First, add your App.xaml OnStartup() the followings:
EventManager.RegisterClassHandler(typeof(Window), Window.LoadedEvent,
new RoutedEventHandler(WindowLoaded));
Then add the 'WindowLoaded' event also in App.xaml :
void WindowLoaded(object sender, RoutedEventArgs e)
{
var window = e.Source as Window;
System.Threading.Thread.Sleep(100);
window.Dispatcher.Invoke(
new Action(() =>
{
window.MoveFocus(new TraversalRequest(FocusNavigationDirection.First));
}));
}
The threading issue must be use as WPF initial focus mostly fails due to some framework race conditions.
I found the following solution best as it is used globally for the whole app.
Hope it helps...
Oran
I converted fuzquat's answer to an extension method. I'm using this instead of Focus() where Focus() did not work.
using System;
using System.Threading;
using System.Windows;
namespace YourProject.Extensions
{
public static class UIElementExtension
{
public static void WaitAndFocus(this UIElement element, int ms = 100)
{
ThreadPool.QueueUserWorkItem(f =>
{
Thread.Sleep(ms);
element.Dispatcher.Invoke(new Action(() =>
{
element.Focus();
}));
});
}
}
}
I've noticed a focus issue specifically related to hosting WPF UserControls within ElementHosts which are contained within a Form that is set as an MDI child via the MdiParent property.
I'm not sure if this is the same issue others are experiencing but you dig into the details by following the link below.
Issue with setting focus within a WPF UserControl hosted within an ElementHost in a WindowsForms child MDI form
I don't like solutions with setting another tab scope for UserControl. In that case, you will have two different carets when navigating by keyboard: on the window and the another - inside user control. My solution is simply to redirect focus from user control to inner child control. Set user control focusable (because by default its false):
<UserControl ..... Focusable="True">
and override focus events handlers in code-behind:
protected override void OnGotFocus(RoutedEventArgs e)
{
base.OnGotFocus(e);
MyTextBox.Focus();
}
protected override void OnGotKeyboardFocus(KeyboardFocusChangedEventArgs e)
{
base.OnGotKeyboardFocus(e);
Keyboard.Focus(MyTextBox);
}
What did the trick for me was the FocusManager.FocusedElement attribute. I first tried to set it on the UserControl, but it didn't work.
So I tried putting it on the UserControl's first child instead:
<UserControl x:Class="WpfApplication3.UserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid FocusManager.FocusedElement="{Binding ElementName=MyTextBox, Mode=OneWay}">
<TextBox x:Name="MyTextBox"/>
</Grid>
... and it worked! :)
I have user control - stack panel with two text boxes.The text boxes were added in contructor, not in the xaml. When i try to focus first text box, nothing happend.
The siggestion with Loaded event fix my problem. Just called control.Focus() in Loaded event and everthing.
Assuming you want to set focus for Username textbox, thus user can type in directly every time it shows up.
In Constructor of your control:
this.Loaded += (sender, e) => Keyboard.Focus(txtUsername);
After trying combinations of the suggestions above, I was able to reliably assign focus to a desired text box on a child UserControl with the following. Basically, give focus to the child control and have the child UserControl give focus to its TextBox. The TextBox's focus statement returned true by itself, however did not yield the desired result until the UserControl was given focus as well. I should also note that the UserControl was unable to request focus for itself and had to be given by the Window.
For brevity I left out registering the Loaded events on the Window and UserControl.
Window
private void OnWindowLoaded(object sender, RoutedEventArgs e)
{
ControlXYZ.Focus();
}
UserControl
private void OnControlLoaded(object sender, RoutedEventArgs e)
{
TextBoxXYZ.Focus();
}
I set it in the PageLoaded() or control loaded, but then I'm calling WCF async service and doing stuff that seems to lose the focus. I have to to set it at the end of all the stuff I do. That's fine and all, but sometimes I make changes to the code and then I forget that I'm also setting the cursor.
I had same problem with setting keyboard focus to canvas in WPF user control.
My solution
In XAML set element to Focusable="True"
In element_mousemove event create simple check:
if(!element.IsKeyBoardFocused)
element.Focus();
In my case it works fine.

Resources