WPF TabControl header issue - c#

I am making an app in WPF that displays an image which can be dragged and zoomed. Bottom, right and upper sides contain some UI elements like buttons and in the center I have a TabControl to which I add TabItems in the code of ViewModel. These TabItems consists of their content (an image) and a header where I have tab buttons. The problem I have is that an image I drag covers the header but not the buttons as you can see on the screenshot. The behavior I expect is to have this image hidden underneath the entire header, not only buttons. It only happens with the bottom side. When I drag the image to the top or right it gets hidden behind the sides like it's supposed to.
Header issue
I tried to change its background, opacity and ZIndex but nothing worked for me.
Here is my code.
XAML:
<TabControl Grid.Row="1" Grid.Column="0" TabStripPlacement="Bottom" Background="LightGray" ItemsSource="{Binding LayoutTabs}"
SelectedIndex="0" SelectedItem="{Binding SelectedTab, Mode=OneWayToSource}"/>
C#:
LayoutTabs = new BindableCollection<TabItem>();
for (int i = 0; i < _content.LayoutImages.Count; i++)
{
DrawingImage drawing = _content.LayoutImages.ElementAt(i);
Image image = new Image() { Source = drawing };
image.MouseMove += OnMouseMove;
var container = new LayoutContainer()
{
Background = Brushes.WhiteSmoke,
Child = image,
Focusable = true,
};
var tabItem = new TabItem()
{
Header = _content.GetLayoutName(i),
Content = container
};
LayoutTabs.Add(tabItem);
}

That behaviour is due to the headerpanels background being set to transparent in the default control template. If you right click the tabcontrol in the Designer window (not xaml editor) and click on Edit Template->Edit a Copy you get a copy of that tempalte and can then modify the headerpanel with your BackgroundColor and if need be increase the Zindex:
[....]
//this is the line to make your changes on:
<TabPanel x:Name="headerPanel" Background="Transparent" Grid.Column="0" IsItemsHost="true" Margin="2,2,2,0" Grid.Row="0" KeyboardNavigation.TabIndex="1" Panel.ZIndex="1"/>
[....]

Related

UWP XAML ScrollViewer how to show visual indicator of scrollable content

Is there a way to visually indicate that there is scrollable content below the visible area of a <ScrollViewer>?
I see this effect in applications like Microsoft Teams. A shadow appears at the bottom of the scrollable area to indicate that more content is present.
None of the properties of <ScrollViewer> seem to be a clear match. But I'm hoping I can avoid having to programmatically show/hide an element below the <ScrollViewer> based on the scroll position.
I have to say that currently there is no built-in API in ScrollViewer that could directly show a shadow there if the content is not ended.
You might still need to check it programmatically by handling the ViewChanged event of the ScrollViewer and add a custom element.
You could use the following code to check if the ScrollViewer reaches the end:
<Grid>
<ScrollViewer Name="MyScrollViewer" ViewChanged="MyScrollViewer_ViewChanged">
<Rectangle
x:Name="MyRectangle"
Width="3000"
Height="3000"
Fill="Blue"
Margin="20" />
</ScrollViewer>
</Grid>
Code behind:
private void MyScrollViewer_ViewChanged(object sender, ScrollViewerViewChangedEventArgs e)
{
var verticalOffset = MyScrollViewer.VerticalOffset;
var maxVerticalOffset = MyScrollViewer.ScrollableHeight;
if (maxVerticalOffset < 0 || verticalOffset == maxVerticalOffset)
{
// content reaches the end
MyRectangle.Fill = new SolidColorBrush(Colors.Red);
}
else
{
// content does not reach the end
MyRectangle.Fill = new SolidColorBrush(Colors.Blue);
}
}

How to add TabControl content as button dynamically?

I am working on a project where I want to add button in content property of TabControl in WPF.
I tried lot many ways but I failed.
This is the code Example :
XAML File
c# File
1. XAML File
<TabControl TabStripPlacement="Left" Name="DynamicTab">
<TabControl.ItemTemplate>
<DataTemplate>
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
<DataTemplate>
</DataTemplate>
</TabControl.ContentTemplate>
2. C# File
foreach(DataContextClass glist in groupsList)
{
TabItem tab = new TabItem();
StackPanel sp = new StackPanel();
tab.Header = glist.ItemGroup;
DynamicTab.Items.Add(tab);
itemsList = itemsDALObj.ItemsGroupWise(glist.ItemGroup);
for(int i =0 ; i<itemsList.Count;i++)
{
Button b = new Button();
b.Name = "Button" + (i + 1);
b.Content = itemsList[i].ItemName;
b.Height = 80;
b.Width = 100;
tab.Content = sp;
sp.Children.Add(b);
}
};
I tried following options:
By adding stackpanel, Grid, Button in <DataTemplate> of <TabControl.ContentTemplate>.
By adding Dynamic Grid and in that Grid I add Dynamic Button.
Many other ways also which I am not able to explain.
You have to replace in XAML instead of <TabControl.ContentTemplate> replace it with <TabControl.DataContext> and that's the solution it takes me hours to find this little mistake.
<TabControl.DataContext>
<DataTemplate>
</DataTemplate>
</TabControl.DataContext>
The above is the change in XAML part.
A TabControl is designed around the idea that the only controls that will be added to it are TabItem controls.
You can in fact, add other controls directly to the parent TabControl object, but when you do, it automatically creates an implicit TabItem anyway to hold those objects.
For instance, if you add two Button controls directly to the TabControl, two implicit TabItem controls are created, one to hold each Button:
<TabControl>
<Button/>
<Button/>
</TabControl>
This works, but is very much the wrong way to go about it.
To properly add content to a TabControl, first create a TabItem. Add your other controls to the TabItem, and then add the TabItem to the TabControl. (You can add the TabItem to the TabControl first if you want, it doesn't really matter)
In XAML:
<TabControl>
<TabItem Header="This is the label for the tab item.">
<Button Content="My Button"/>
</TabItem>
</TabControl>
In code (assuming a pre-existing TabControl):
TabItem ti = new TabItem();
ti.Header = "Tab Header Text";
Button bt = new Button();
bt.Content = "Button Text";
ti.Content = bt;
myTabControl.Items.Add(ti);
A TabControl, like all WPF controls is a container. It can hold multiple objects, but all of those objects are actually TabItem objects. The TabItem control can only hold one object, so if you want it to contain more than just the Button, you have to add a different container to the TabItem first; like a Grid or StackPanel.

How to programatically add an image to a textblock?

I'm trying to set an icon to be attached to a textblock when it is saved but I'm not sure how I would do this programatically.What I'm thinking is you could set the value to the left of the textbox to an image.I have tried this but I'm not sure how I would set it to an image icon:
NoteGridView.SetValue(Canvas.LeftProperty(double)block.GetValue(Canvas.LeftProperty));
This is how I'm adding the notes to the layout:
// Creates a new textblock that for this note.
TextBlock block = new TextBlock();
//block.SetValue
notepadTxtBox.SetValue(Canvas.LeftProperty, (double)block.GetValue(Canvas.LeftProperty));
block.Width = 250;
block.Height = 125;
block.Text = notepadTxtBox.Text;
// Add that note to the grid.
NoteGridView.Items.Add(block);
Does anyone have any idea how I would acheive this or is it possible to do in the xaml code?
This might give a better understanding of what I'm trying to do:
You could put a StackPanel inside of the TextBlock, containing an Image, and another TextBlock, like so:
<TextBlock>
<StackPanel Orientation="Horizontal">
<Image Name="YourImage" Source="image/Under-Construction.png" />
<TextBlock Text="Your Text Block Text" />
</StackPanel>
</TextBlock>
You would then be able to set the Image programmatically like so:
YourImage.Source = "path.to.image.file"

how to maintain the Width of tabItems should be equal in WPF?

how to maintain the width of the tabItems should be equal if i open multiple tabItems. know i am not getting this thing. i tried the following code
HorizontalContentAlignment="stretch"
i used the above code but it is not working. but i am getting like this
for tabcontrol i write the following code
<TabControl Name="tabControl1" Margin="175,44,0,0" >
<Grid></Grid>
</TabControl>
tabItems will dynamically adding to the Tabcontrol
TabItem tabitem2 = new TabItem();
Page2 pgobj1 = new Page2();
Frame tabframe1 = new Frame();
tabframe1.Content = pgobj1;
tabitem2.Header = "Tab 2Tab 2Tab 3";
tabitem2.Width = 300;
tabitem2.Content = tabframe1;
tabControl1.Items.Add(tabitem2);
tabitem2.IsSelected = true;
i don't want those spaces in between the tabItems. and they automatically resize if more number of tabs are opened. kindly help me out in this.
After removing the Hardcoded width property
it comes like this
Remove hardcoded width you are setting on TabItem. No need to set that, TabItem will automatically adjust its width base on header content.
tabitem2.Width = 300; // Remove this line
If you want items to come in single line and scroll using ScrollViewer, you need to modify Template of TabControl like mentioned here. I am posting the code from there for the sake of completeness of answer:
<TabControl Name="tabControl1">
<TabControl.Template>
<ControlTemplate TargetType="TabControl">
<StackPanel>
<ScrollViewer HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Disabled">
<TabPanel x:Name="HeaderPanel"
Panel.ZIndex ="1"
KeyboardNavigation.TabIndex="1"
Grid.Column="0"
Grid.Row="0"
Margin="2,2,2,0"
IsItemsHost="true"/>
</ScrollViewer>
<ContentPresenter x:Name="PART_SelectedContentHost"
SnapsToDevicePixels="{TemplateBinding
SnapsToDevicePixels}"
Margin="{TemplateBinding Padding}"
ContentSource="SelectedContent"/>
</StackPanel>
</ControlTemplate>
</TabControl.Template>
</TabControl>
Also check out this answer here.
If I understand you correctly, you want that all tab items should have equal width. You can achieve that by wrapping each tab item header inside a Grid with a ColumnDefinition that uses a SharedSizeGroup. Furthermore, you must mark the TabControl like this:
<TabControl x:Name="tabControl1" Grid.IsSharedSizeScope="True">
The following code shows how to set the Header property programmatically:
Grid grid = new Grid();
grid.ColumnDefinitions.Add(new ColumnDefinition
{
SharedSizeGroup = "MySharedSizedGroupName",
Width = new GridLength(1.0, GridUnitType.Auto)
});
grid.Children.Add(new TextBlock{Text="Tab 5"});
tabitem2.Header = grid;
EDIT: And one other point: I think the <Grid></Grid> you have added as a child to the TabControl is unnecessary, because it creates that empty tab on the left side in the first tab row.

Make Child control more Opaque than Parent

I have a Page like in the Xaml below which i want to use like a ModalDialog.
The Problem is that when I Pop the Dialog up, that the Opacity of the second Grid which holds the Content is not changed back to 100% and I see from the Page where it is Popuped the underlying controls. For more Detail see the Screenshot.
Is there a way that I can change back the Opacity of the second Grid to 100% that no control behind it can see through?
For completneness I have added the Code which i'm using to bring up the Popup.
ModalDialog Xaml:
<Page>
<Grid x:Name="RootPanel" Background="{StaticResource LucentBlue}" Opacity=".75">
<Border >
<Grid VerticalAlignment="Center"
Height="300" Background="{StaticResource PremiumBlue}" Opacity="1">
</Grid>
</Border>
</Grid>
</Page>
Code Behind Hosted Page:
private Popup _saveDialog;
private void SaveSettingsCommandLogic(object obj)
{
ModalDialog dlg = new ModalDialog();
dlg.CloseRequested += DlgOnCloseRequested;
_saveDialog = new Popup();
_saveDialog.Child = dlg;
_saveDialog.IsOpen = true;
}
Here's a solution in metro :
Please remove the Opacity property of both the elements and from the code behind of the ModalDialog class use the following code:
public ModalDialog()
{
this.InitializeComponent();
Color color = Color.FromArgb(150,255,0,0);
RootPanel.Background = new SolidColorBrush(color);
}
The method FromArgb is used to specify the transparency red green and blue values respectively and can rancge from 0-255 .. please test according to ur convinience :)

Categories

Resources