WPF: Popout existing usercontrol - c#

Imagine next situation: I do have application window with several usercontrols inside. They was displayed side by side in past, but now I want to show one of them in popup window. Not in Popup control but new Window.
See example XAML:
<Window x:Class="WpfApplication3.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:wpfApplication3="clr-namespace:WpfApplication3"
Title="MainWindow"
Height="350"
Width="525">
<Grid>
<wpfApplication3:UserControl1 Visibility="Hidden"
x:Name="UserControl1"/>
<Button Click="ButtonBase_OnClick"
Width="100"
Height="60">open window</Button>
</Grid>
In code behind I need to deattach usercontrol from current Window and assign to new one:
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
var parent = VisualTreeHelper.GetParent(UserControl1);
if (parent != null)
{
parent.RemoveChild(UserControl1);
}
var w = new Window
{
Content = UserControl1,
Title = "sample",
SizeToContent = SizeToContent.WidthAndHeight,
ResizeMode = ResizeMode.CanResize
};
w.Show();
}
And after calling w.Show() I always getting blank white window.
If in button click handler change
Content = UserControl1
to
Content = new UserControl1()
I will get right content as well.
But I can't use this way because I want to keep my usercontrol state during pop-out and pop-in events.
So how can I show in new window existing usercontrol without recreating it?

I am not sure how you are calling RemoveChild on a DependencyObject as that method doesn't seem to exist. Note that VisualTreeHelper.GetParent returns a DependencyObject so, the code you posted should not compile unless you have an Extension method somewhere defining RemoveChild.
In your case what you want to do is cast your parent object to type Grid or Panel and then remove the UserControl from the Children property, then set your UserControl as the Content of your window.
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
Grid parent = VisualTreeHelper.GetParent(UserControl1) as Grid;
if (parent != null)
{
parent.Children.Remove(UserControl1);
}
var w = new Window
{
Content = UserControl1,
Title = "sample",
SizeToContent = SizeToContent.WidthAndHeight,
ResizeMode = ResizeMode.CanResize
};
w.Show();
}

There was a similar question asked here
that gives a very detailed answer.
The quick answer is that you will have to remove the control from the main window and then add it to the popup window.

Related

return to MainWindow after using adding a UserControl with .Child

In MainWindow.xaml.cs I switch to a userControl using .Child like so:
Grid1.Visibility = Visibility.Hidden;
Stage.Child = new UserControlName();
Where Grid1 is the grid where the content sits in the main window, (which should be hidden because there's some content that will peek out from behind the usercontrol), and Stage is a border element where I want the UserControl to fill
<Grid >
<Border x:Name="Stage" Grid.RowSpan="4" Grid.ColumnSpan="2"/>
<Grid x:Name="Grid1" FocusManager.FocusedElement="{Binding ElementName=textBox}" Margin="10,10,10,10" Width="1200" Height="649" >
How can UserControlName be closed or hidden from its own xaml.cs file and the view be returned to the main window while simultaneously returning MainWindow's Grid1 to Visible?
I would implement that using Regions from PRISM (https://msdn.microsoft.com/en-us/library/ff921098(v=pandp.40).aspx). But if you created simple application and you don't want to invest time to learn PRISM you can for example extend constructor of UserControlName class by adding parameter of MainWindow type and invoke on this object some method that would change the view to your desire state.
Example of uglly code:
MainWindow:
private void Button_Click(object sender, RoutedEventArgs e)
{
grid1.Visibility = Visibility.Hidden;
br.Child = new UserControl2(this);
}
public void CloseView()
{
grid1.Visibility = Visibility.Visible;
br.Child = null;
}
UserControl:
private MainWindow window;
public UserControl2(MainWindow window)
{
this.window = window;
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
window.CloseView();
}
Another option is to use (for example) the Mvvm Light toolkit and messaging (https://msdn.microsoft.com/en-us/magazine/jj694937.aspx).
The child view would send a message to get closed, the main window would receive this message and hide the grid.
The advantage is that the main window and the child control are still uncoupled meaning that the child does not need to know anything about the main window.
Take this chance and invest some time in the Mvvm pattern and libraries such as Mvvm light.

My inputcommand keybinding to main window does not work when child window is focussed(same wpf window)?

I am facing one problem with input command key binding.
Here i explain my situation...
I have binded the input command key binding like below,
<Window x:Class="DefaultBehavior_KeyBinding.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Window.InputBindings>
<KeyBinding Key="F2" Command="{Binding TestCommand}"/>
</Window.InputBindings>
<Grid>
<Button Content="Add" Width="100" Height="35" Grid.Row="0" Name="EmptyButton" Click="EmptyButton_Click"/>
</Grid>
It works fine. Then i opened the new wpf child window in button click event like below,
public partial class MainWindow : Window
{
public ICommand TestCommand { get; private set; }
public MainWindow()
{
this.TestCommand = ........some command is attached here...
InitializeComponent();
this.DataContext = this;
}
private void EmptyTabButton_Click(object sender, RoutedEventArgs e)
{
Window childwindow = new Window() { Title = "ChildWindow", Width = 200, Height = 300 };
childwindow.Show();
}
}
After opening the child window, the key binding to main window not working when child window is focused. If i switch the focus to main window means, it fine.
I know, both the main window and child window are independent to each other.
But my question is, how can i make it as work my child window is focussed when i binded the keybinding to main window only. i don't want to set this binding to each child window because in my case i am using lot of child windows.
Any one please provide your suggestion to me?
The key bindings will only work if the Form is focused.
You could redirect every Command in your new Window to the Main Window
Change your Constructor to of the new Window to accept a Main Window and save this window:
MainWindow mainWindow;
public Window(MainWindow w)
{
mainWindow = w;
}
Whenever a Keybinding executes just do something like this:
mainWindow.TabPress();
And show the Window with
Window childwindow = new Window(this) { Title = "ChildWindow", Width = 200, Height = 300 };
childwindow.Show();
Can you try setting the Input Bindings in Window style (that should defined in App.xaml), so that it will apply to all Window objects.
This code is NOT TESTED! (but it should work anyways :D)
You could add the InputBindings from the MainWindow to the childwindows InputBindingCollection as follows:
private void EmptyTabButton_Click(object sender, RoutedEventArgs e)
{
Window childwindow = new Window() { Title = "ChildWindow", Width = 200, Height = 300 };
childWindow.InputBindings.AddRange(this.InputBindings);
childwindow.Show();
}
By doing so, the childwindow should react to your input and execute the commands from the MainWindow.

Assign tab content in WPF to a page

I am trying to add dynamic tabs to my application. Right now if I click a button, it will open a new page. What I want is to open this page in a new tab. But when I set up the tab content to a page , the code complains. I wanna do something like this
private void bttnGoToClientsOnClick(object sender, RoutedEventArgs e)
{
var content = new TextBlock();
TabItem tab = new TabItem();
tab.Header = "Search Page";
SearchPage sp = new SearchPage();
tab.Content = sp;
tabControl.Items.Add(tab);
this.NavigationService.Navigate(sp);
}
is there any way I can convert my page to usercontrol or cast it as user control
Thank you!
But when I set up the tab content to a page , the code complains.
It wouldn't hurt if you were more specific here :)
What is SearchPage class? It doesn't seem to be the part of the WPF framework. I googled it up on the
http://www.intersoftpt.com/ website. Is that it?
TabItem.Content needs to be of ContentControl type, which SearchPage - apparently - is not. I'm sure you need to embed this SearchPage object in some control presenter, such as a panel, before you can assign it to TabItem.Content.
Update:
Try this, then:
TabItem tab = new TabItem();
tab.Header = "Search Page";
SearchPage sp = new SearchPage();
this.NavigationService.Navigate(sp);
// ----------------------------------------------------
var frame = new Frame(); // !
frame.Navigate(sp); // !
tab.Content = frame; // !
// ----------------------------------------------------
tabControl.Items.Add(tab);
While I believe this should work, I haven't tested it. Please let me know if it doesn't do the trick.
You can always create your own UserControls, directly in the XAML definition (even if they are partial pages or windows).
In this example I assume that your SearchClass is defined in the [YourProject].Model namespace (where [YourProject] is the name of your project)
<UserControl x:Class="WpfApplication1.UserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:search="clr-namespace:[YourProject].Model">
<search:SearchClass>
<!--<Grid>
...ANYTHING YOU WANT HERE ! ...
</Grid>-->
</search:SearchClass>
</UserControl>
Now you can create an instance of the UserControl, even in XAML or in code-behind (remember only to declare the namespaces correctly!):
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:ctrls="clr-namespace:WpfApplication1"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<UserControl1 />
</Grid>
</Window>
...and this my code-behind...
UserControl1 myControl = new UserControl1();

InputBinding and WebBrowser control

I have a very simple application where I'm trying to bind keyboard shortcuts to a WPF command that is bound to a menu item. The application itself consists of just a Menu and a WebBrowser control.
When I'm within the WebBrowser, the keyboard shortcuts are not routed up to the WPF Menu. For example, typing 'Ctrl+O' when focused in the web browser shows the IE open page. Additionally, in this application, unless I have the Menu focused (by typing in Alt) the input bindings don't fire. For example, I can't focus on the WPF window by clicking on the title bar and then type the shortcuts. The full code is replicated below:
MainWindow.xaml
<Window x:Class="TestInputBindingsOnMenu.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="600" Width="800">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Menu IsMainMenu="True" x:Name="_mainMenu" Grid.Row="0" />
<WebBrowser Source="http://google.com" Grid.Row="1" />
</Grid>
</Window>
MainWindow.xaml.cs
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
namespace TestInputBindingsOnMenu
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Initialize();
}
private void Initialize()
{
MenuItem fileMenu = new MenuItem();
MenuItem fileNew = new MenuItem();
MenuItem fileOpen = new MenuItem();
MenuItem fileExit = new MenuItem();
fileMenu.Header = "File";
fileNew.Header = "New";
fileOpen.Header = "Open";
fileExit.Header = "Exit";
fileMenu.Items.Add(fileNew);
fileMenu.Items.Add(fileOpen);
fileMenu.Items.Add(fileExit);
_mainMenu.Items.Add(fileMenu);
var fileNewCommand = CreateCommand("New");
var fileOpenCommand = CreateCommand("Open");
var fileExitCommand = CreateCommand("Exit");
_mainMenu.CommandBindings.Add(new CommandBinding(fileNewCommand, ExecuteNew));
_mainMenu.CommandBindings.Add(new CommandBinding(fileOpenCommand, ExecuteOpen));
_mainMenu.CommandBindings.Add(new CommandBinding(fileExitCommand, ExecuteExit));
fileNew.Command = fileNewCommand;
fileOpen.Command = fileOpenCommand;
fileExit.Command = fileExitCommand;
_mainMenu.InputBindings.Add(new InputBinding(fileNewCommand, new KeyGesture(Key.N, ModifierKeys.Control)));
_mainMenu.InputBindings.Add(new InputBinding(fileOpenCommand, new KeyGesture(Key.O, ModifierKeys.Control)));
_mainMenu.InputBindings.Add(new InputBinding(fileExitCommand, new KeyGesture(Key.F4, ModifierKeys.Alt)));
}
private void ExecuteNew(object sender, ExecutedRoutedEventArgs e)
{
MessageBox.Show("New!!");
}
private void ExecuteOpen(object sender, ExecutedRoutedEventArgs e)
{
MessageBox.Show("Open!!");
}
private void ExecuteExit(object sender, ExecutedRoutedEventArgs e)
{
MessageBox.Show("Exit!!");
}
private static RoutedCommand CreateCommand(string label)
{
return new RoutedCommand(label, typeof(MainWindow));
}
}
}
Easy Solution
Add the input bindings to the WebBrowser control as well as the main menu:
Browser.InputBindings.Add(new KeyBinding(ApplicationCommands.Open,
new KeyGesture(Key.O, ModifierKeys.Control)));
Hard Solution
What is happening here is that the UIElement is using the KeyDown event, while you want to use PreviewKeyDown event, or add a handler that also handles Handled routed events. Look up Tunnelling and Bubbling if you don't know about this.
Since this is handled in the UIElement class, I would advise using a different pattern in this situation. The MVVM Light framework provides an EventToCommand behavior. If you can route the PreviewKeyDown event of the window to the right commands instead of using KeyBinding with the InputBindings collection of the UIElement you will have your solution.
You will need some custom code to check which key was pressed and to which command the routing should be.

How to access Main Form Public Property WPF

I have a user control from where I have to call the property of the window which contain the user control how can I access that property.
Suppose I have Title Property in my window and I want to access Title property of the window from the user control. Any idea
is That OK
(App.Current.MainWindow as MainWindow).Title;
Thanks in advance
This code will get the parent window where the user control resides:
FrameworkElement parent = (FrameworkElement)this.Parent;
while (true)
{
if (parent == null)
break;
if (parent is Page)
{
//Do your stuff here. MessageBox is for demo only
MessageBox.Show(((Window)parent).Title);
break;
}
parent = (FrameworkElement)parent.Parent;
}
Why dont you bind title property of parent window with your control's property?
Window x:Class="Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window Title" Height="500" Width="650" ResizeMode="NoResize" x:Name="us1">
TextBox Name="txtBlk" Text="{Binding Path=Title, ElementName=us1}"/>
/Window>

Categories

Resources