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();
Related
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.
First, let me state my intentions. This is the final result I am looking for.
Mockup Of Intent http://s18.postimg.org/x818zbfbb/image.png
The output of my code, however, fails to achieve this. Here's what I did. This is my MainWindow XAML.
<Window x:Class="App.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="" Height="200" Width="400"
WindowStartupLocation="CenterScreen" Name="ViewData">
<Grid Name="splMain" Background="{StaticResource GreyGradient}"></Grid>
</Window>
And this is the C# code for the dynamic RowDefitions creation:
private void ViewImgData(SubPod subPod)
{
var wb = new WebBrowser();
wb.Navigate(subPod.Image.Src);
var rowDefinition = new RowDefinition();
rowDefinition.Height = GridLength.Auto;
splMain.RowDefinitions.Add(rowDefinition);
Grid.SetRow(wb, 0);
((MainWindow)System.Windows.Application.Current.MainWindow).splMain.Children.Add(wb);
}
This I am calling from over here. It is guaranteed that this foreach loop would run more than once. However, my output window shows only 1 image instead of 2 or more, that too not taking up the whole space of the Window.
foreach (SubPod subPod in pod.SubPods)
{
Application.Current.Dispatcher.BeginInvoke(
DispatcherPriority.Background,
new Action(() => ViewImgData(subPod)));
}
Where have I mistaken? Thanks.
You add new rows, but place the new webbrowser component in the 0th row.
Try
Grid.SetRow(wb, splMain.RowDefinitions.Count-1);
instead, since you need to place new content in the new row.
EDIT:
To fit the grid height and width try adding this to your splMain grid
Width="{Binding ActualWidth,RelativeSource={RelativeSource AncestorType={x:Type Window}}" Height="{Binding ActualHeight,RelativeSource={RelativeSource AncestorType={x:Type Window}}"
see also Stretch Grid to window size
I use MVVM framework and got this tutorial on net: https://code.msdn.microsoft.com/windowsdesktop/How-to-use-MVVM-Pattern-0e2f4571 and http://www.c-sharpcorner.com/UploadFile/raj1979/simple-mvvm-pattern-in-wpf/
Now, my problem is:
I can't display the mainpage.xaml even there is no semantic error. Here's my code on app.xaml.cs:
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
BasicWPF.View.MainPage window = new MainPage();
UserViewModel VM = new UserViewModel();
window.DataContext = VM;
window.Show();
}
Can anyone help me? Thanks for any help! :)
Thanks to everyone who helped.
[SOLVED]
Change the startupuri in app.xaml to where the page you want to load. In my case
1: I change it:
StartupUri="View/MainPage.xaml"
2: In app.xaml.cs, I typed in this code:
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
BasicWPF.View.MainPage window = new MainPage();
UserViewModel VM = new UserViewModel();
window.DataContext = VM;
}
from my previous code, delete this code: window.show(); because it startup the page twice coming from app.xaml and app.xaml.cs. To prevent that, delete: window.show();
Thank you again! :)
Set the starting page in app.xaml, not the app.xaml.cs file - in the Application tag, if there is no property StartupUri - add one and set its value to your page name, this way the page will be automatically shown as soon as your application is started. It should look something like this:
<Application x:Class="WpfApplication1.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainPage.xaml">
I am considering that you are doing it this way because you wish to set the DataContext of the page, but there is a better way to set the DataContext of your page and it is by setting it directly into your XAML code. Here is an example:
<Page x:Class="WpfApplication1.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication1"
Title="MainWindow" Height="350" Width="525" >
<Page.DataContext>
<local:UserViewModel/>
</Page.DataContext>
xmlns:local is a prefix mapping to the namespace you have set for it. Having this you are able to access the types contained in the namespace using the prefix - local:UserViewModel.
what you can do is instead of setting data context in app.xaml.cs, just hook up the loaded event of main window and add the following code.
public MainWindow()
{
InitializeComponent();
this.Loaded += MainWindow_Loaded;
}
void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
UserViewModel VM = new UserViewModel();
this.DataContext = VM;
}
This should work. Dont forget to remove the codes from App.xaml.cs.
Thanks
SO in your case you have a main window inside that main window you need to load the page.
What you can do is add a frame to your mainwindow like
<Frame x:Name="myFrame"/>
then inside the mainwindow loaded event add the below code
void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
UserViewModel VM = new UserViewModel();
this.DataContext = VM;
myFrame.Content = new MainPage();
}
This is like we are adding a frame and loading your view to that frame.
In WPF app I have created WindowsFormsHost and wanted to insert in it a Form containing COM/Activex control. But then I get:
A first chance exception of type 'System.ArgumentException' occurred in WindowsFormsIntegration.dll
at System.Windows.Forms.Integration.WindowsFormsHost.set_Child(Control value)
at HomeSecurity.MainWindow..ctor() w c:\Users\R\Documents\Visual Studio 2013\Projects\HomeSecurity\HomeSecurity\MainWindow.xaml.cs:row 26
'HomeSecurity.vshost.exe' (CLR v4.0.30319: HomeSecurity.vshost.exe): Loaded 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\UIAutomationTypes\v4.0_4.0.0.0__31bf3856ad364e35\UIAutomationTypes.dll'. Symbols loaded.
This is the contstructor of MainWindow. Class VideoStream extends class Form
public MainWindow() {
InitializeComponent();
VideoStream VideoStream = new VideoStream();//creating a Form containing Activex control
WindowsFormsHost Host = new WindowsFormsHost();//creating a host
try {
Host.Child = VideoStream;//setting content of Host, CAUSES THE EXCEPTION PRINTED ABOVE
}catch(Exception e){
Console.WriteLine(e.StackTrace);//output above
}
}
I cannot deal with it for long time and I have no more time. How to fix this problem?
Well, You can't add a Form(TopLevelControl) inside it. You'll have to make it child control first. Setting TopLevel is set to false should make it work.
VideoStream.TopLevel = false;
Note: Not only with WindowsFormsHost, even with Winforms application also you can't add a Form inside a Form unless TopLevel is set to false.
Why not derive VideoStream from UserControl rather than from Form? IMO, that'd be more appropriate for re-using and hosting it inside a WPF app, and the problem would have been gone.
[EDITED] You should first add the WindowsFormsHost control to the WPF window, then add your UserControl-derived VideoStream control to the WindowsFormsHost control:
using System.Windows;
using System.Windows.Controls;
using System.Windows.Forms.Integration;
namespace WpfWinformsTest
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
// add a grid first (optional)
var grid = new Grid();
this.Content = grid;
// create and add a WinForms host
WindowsFormsHost host = new WindowsFormsHost();
grid.Children.Add(host);
// add a WinForms user control
var videoStream = new VideoStream();
host.Child = videoStream;
}
}
}
You can do the same with XAML:
<Window x:Class="WpfWinformsTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:wf="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"
xmlns:local="clr-namespace:WpfWinformsTest"
Title="MainWindow" Height="350" Width="525">
<Grid>
<WindowsFormsHost Name="wfHost" Focusable="True" Margin="10,10,10,10">
<local:VideoStream x:Name="videoStream" />
</WindowsFormsHost>
</Grid>
</Window>
Here's how VideoStream may look like (of course, you can use VS Designer to add controls like axVideoPlayer to it, rather than doing it manually):
using System.Windows.Forms;
namespace WpfWinformsTest
{
public partial class VideoStream : UserControl
{
AxWMPLib.AxWindowsMediaPlayer axVideoPlayer;
public VideoStream()
{
InitializeComponent();
this.axVideoPlayer = new AxWMPLib.AxWindowsMediaPlayer();
this.axVideoPlayer.Size = new System.Drawing.Size(200, 100);
this.Controls.Add(this.axVideoPlayer);
}
}
}
I suggest you read the following articles:
Walkthrough: Hosting a Windows Forms Composite Control in WPF
Walkthrough: Hosting an ActiveX Control in 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>