Adding a UserControl to a TabItem - c#

Originally I had my MainWindow(.xaml) that had a stackpanel and a frame. Within the stackpanel were three navigation buttons and the frame had one of the three Pages (based on which navigation button the user clicked). However, it seems that since I'm not doing a web app, that using Frame (and Pages?) is not the right way to go about it. So I changed the stackpanel and frame to a single tabcontrol (with tabs being what were the three buttons before). I also changed the Pages to usercontrols.
However, I'm having trouble finding a way to put the Pages (now UserControls) into the content of the tabitem, without using a Frame. I'm trying to do all of this within the MainWindow xaml.
my MainWindow.xaml:
<Window x:Class="ConstructedLanguageOrganizerTool.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" mc:Ignorable="d" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" Height="454" Width="573">
<Grid>
<TabControl HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Name="tabControl1">
<TabItem Header="Basics" Name="basicsTab">
//What can I use here instead of Frame?
</TabItem>
<TabItem Header="Words" Name="wordsTab">
<Grid>
<Frame Source="WordsPage.xaml"/>
</Grid>
</TabItem>
...
</TabControl>
</Grid>
</Window>
Am I going about this the wrong way? I think that I'm suppose to use some sort of databinding, maybe? Although, the more I look at things on data binging, the more I just get confused on that as well.
edit: here is my BasicsPage.xaml
<UserControl x:Class="ConstructedLanguageOrganizerTool.BasicsPage"
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"
mc:Ignorable="d" x:Name="basicsPage" Height="349" Width="334">
<Grid>
// Grid Row and Column defs here
//Number of textboxs and textblocks here.
</Grid>
</UserControl>

You just need to create an instance of UserControl and put it inside TabItem.
Say BasicsPage is your UserControl you want to put inside TabItem. All you have to do this:
<TabItem Header="Basics" Name="basicsTab">
<local:BasicsPage/>
</TabItem>
Define local namespace at root window where BasicsPage is defined in something like:
<Window x:Class="ConstructedLanguageOrganizerTool.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:ConstructedLanguageOrganizerTool"> <-- HERE

Related

changing text in parent UserControl from Child UserControl WPF

If a ParentUserControl contains a TextBlock. The ParentUserControlalso contains ChildUserControl that has a TextBox. I want to set the TextBlock of ParentUserControl value from ChildTextBox. how can i ?
In other words somehow accessing the ParentUserControl and it's TextBlock element and then modifying it's value from ChildUserControl !
Update
i have a xaml window that contains a ParentUserControl that has a TextBlock. Now i am loading or adding another ChildUserControl into it on runtime. This newly added ChildUserControl contains a ChildTextBox. Now i want that when i input some value into this ChildTexBox the ParentUserControl's TextBlock should get that value and update itself.
Assuming we are not following any MVVM and a simple approach for this problem is,
Create a ChildUserControl with a textbox inside it as below,
<UserControl x:Class="SO52840402.ChildUserControl"
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:local="clr-namespace:SO52607887"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<TextBox x:Name="ChildTextBox" />
</Grid> </UserControl>
Create a ParentUserControl which contains a TextBlock and ChildUserControl instance as shown below,
<UserControl x:Class="SO52840402.ParentUserControl"
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:local="clr-namespace:SO52607887"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<TextBlock x:Name="ParentTextBlock" Text="Hallo World!"/>
<local:ChildUserControl x:Name="ChildUserControl" Grid.Row="1" />
</Grid> </UserControl>
Now create a TextChanged event for the TextBox which is under ChildUserControl from code behind of ParentUserControl constructor after "InitializeComponent" as shown below,
public ParentUserControl()
{
InitializeComponent();
ChildUserControl.ChildTextBox.TextChanged += OnChildTextBox_TextChanged;
}
private void OnChildTextBox_TextChanged(object sender, EventArgs e)
{
ParentTextBlock.Text = (sender as TextBox).Text;
}
Note:- This is a not a recommended approach. For best approach, follow MVVM pattern and understand your requirements and do the design. Since you need something from a child user control from a parent user control, a best approach is to have a ViewModel bind to parent and child and access child view model in parent viewmodel and do "what ever you want".

Grid control can't cover the whole page and leaves a space at the top

I have a default grid control defined in xaml:
<Page
x:Class="App.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:App"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid>
</Grid>
</Page>
And this grid does not start from the top of the page as you can see from the picture below:
One way to achieve this is to set a negative margin like this:
<Page
x:Class="App.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:App"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid Margin="0,-26.667,0,0">
</Grid>
</Page>
So it will look like in this picture:
However, I've watched some of Bob Tabor's videos like this one and all of his default controls starts right from the top of the page.
What is the problem here and how can I solve it without setting a negative margin?
Well status bar is there by default.
You have 2 options:
Hide it -> Hide Status bar in Windows Phone 8.1 Universal Apps
put your content under it:
var applicationView = Windows.UI.ViewManagement.ApplicationView.GetForCurrentView();
applicationView.SetDesiredBoundsMode(Windows.UI.ViewManagement.ApplicationViewBoundsMode.UseCoreWindow);
You may wish to read this for additional info:
http://blogs.msdn.com/b/amar/archive/2014/05/12/status-bar-in-windows-phone-8-1.aspx

ReactiveUI - Views not rendering properly (or in full)

I'm in the process of starting a new project, using ReactiveUI and MahApps.Metro. The first hurdle I've hit is a problem of views not showing in their entirety. I have a Window, and in that Window I have a ViewModelViewHost from the RxUI library. It is a simple container for a nested view-model. The ActiveItem binding is properly binded to the view-model of the User Control, and the Button from the user control is visible on screen.
What I expect to see is a Window with a dark gray background and a button in the middle. What I see is the Window with its default background and a Button in the middle. This is not right. If I remove the button, I see nothing on the Window, only the default background.
It seems the ViewModelViewHost is only showing the actual contents of a UserControl and is disregarding what isn't considered a real Control, such as grids etc.
Has anyone come across this behaviour before?
<mah:MetroWindow x:Class="...MainWindow"
xmlns:mah="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:rx="clr-namespace:ReactiveUI;assembly=ReactiveUI"
WindowStartupLocation="CenterScreen"
ShowTitleBar="False"
ShowCloseButton="False"
ShowMaxRestoreButton="False"
ShowMinButton="False"
Height="768"
Width="1024">
<Grid HorizontalAlignment="Center" VerticalAlignment="Center">
<rx:ViewModelViewHost ViewModel="{Binding ActiveItem}" />
</Grid>
</mah:MetroWindow>
<UserControl x:Class="...NestedView"
Name="TheUserControl"
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"
mc:Ignorable="d"
TextOptions.TextHintingMode="Auto"
TextOptions.TextRenderingMode="Auto"
d:DesignHeight="768" d:DesignWidth="1024">
<Grid Background="DarkGray">
<Button Width="200" Height="100" />
</Grid>
</UserControl>
This won't be a ReactiveUI problem, just a simple WPF one.
The ViewModelViewHost is centered in your window. While your UserControl has a DesignHeight and DesignWidth set, when it's rendered at runtime it will automatically size itself to the height and width of its content - the Button.
Add VerticalContentAlignment="Stretch" HorizontalContentAlignment="Stretch" to your ViewModelViewHost declaration and remove the other two Alignment attributes (they default to Stretch) and it should stretch its contents to the size of the Window while centering any item that has a fixed size.

How to define UserControl with custom content?

I want to define my custom decorator that has user content in it. But it always fail when I try to set some control's name. I always get this exception when trying to do it:
Cannot set Name attribute value 'butt' on element 'Button'. 'Button'
is under the scope of element 'UserControl1', which already had a name
registered when it was defined in another scope.
I don't understand why that happens. Here's teh codez:
<UserControl x:Class="WpfApplication5.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"
mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="300"
x:Name="control">
<ContentPresenter Content="{Binding ElementName=control, Path=DataContext}" />
</UserControl>
<Window x:Class="WpfApplication5.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication5"
Title="MainWindow" Height="350" Width="525">
<local:UserControl1>
<local:UserControl1.DataContext>
<Button x:Name="butt" />
</local:UserControl1.DataContext>
</local:UserControl1>
</Window>
How to do that properly?
You cannot name elements inside UserControls, someone considered this to be a bug but i do not know if this is the case, either way, this will not work. You could declare the Button as a resource of your Window and then insert it via StaticResource, then however the name will not be registered as a field in the window class.
Either way, do you really need the name?
Edit: Also see this question.

Bringing a user control to the front in Expression Blend, C#, WPF

I have a window with a Grid on.
On this I have some buttons, one of which when clicked will create a new 'PostIt' which is a user control I have created.
What I want to do is click on a 'PostIt' and have that control on top of all the others.
I have tried...
Grid.SetZIndex(sender, value);
Which seems to be the correct code, no errors, just not movement of the control :(
The problem may lie in the fact that the code for the click is in the user control and not the mainwindow cs file. Does this matter?
The 'PostIt' is simply a border with a text box in it.
Are you calling Grid.SetZIndex(sender, value) in a handler of the PostIt mouse click, or a handler for a control inside the PostIt? What is the value that you are setting?
Here is an example that works:
<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"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300" MouseUp="UserControl_MouseUp">
<Grid>
</Grid>
</UserControl>
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
}
private void UserControl_MouseUp(object sender, MouseButtonEventArgs e)
{
Panel.SetZIndex(this, Panel.GetZIndex(this) + 2);
}
}
<Window x:Class="WpfApplication1.MainWindow"
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">
<Grid>
<local:UserControl1 Background="Green" Margin="40,40,100,100" Panel.ZIndex="0" />
<local:UserControl1 Background="Red" Margin="140,140,10,10" Panel.ZIndex="1" />
</Grid>
</Window>
Jogy
This may not be the best solution, but it's the one that worked for me; I was re-ordering two grids:
GridOnBottom.SetValue(Grid.ZIndexProperty, (int)GridOnTop.GetValue(Grid.ZIndexProperty) + 1);
...with GridOnBottom and GridOnTop renamed to the instances of the objects you're re-ordering. Granted, it's not the best solution, but it works.

Categories