Why does this WPF button stretch across the window? - wpf

The button below always expands to be as wide as the TextBlock. I've tried StackPanel, DockPanel, Width="Auto", etc.
How can I make the button expand to the size of its own text (as in HTML) and not to the size of text in its environement?
<DockPanel HorizontalAlignment="Left">
<Button x:Name="ButtonFavorite"
DockPanel.Dock="Top"
Content="Customers"
Margin="10"
Width="Auto"
Click="ButtonFavorite_Click">
</Button>
<TextBlock DockPanel.Dock="Top" Text="this is a long text which makes the button stretch across the window, if this text is just a couple words, the button will be smaller, and this drives me up the wall" Margin="10" TextWrapping="Wrap" />
</DockPanel>
ANSWER:
Thanks Greg, that did it. Here is the full XAML that works now, you can right-click the button to change its Content so see that the button expands and contracts appropriately.
<Window x:Class="Test3784234.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<DockPanel HorizontalAlignment="Left">
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal" >
<Button x:Name="ButtonFavorite"
Padding="5"
Cursor="Hand"
DockPanel.Dock="Top"
Content="Customers"
Margin="10"
Click="ButtonFavorite_Click">
<Button.ContextMenu>
<ContextMenu>
<MenuItem x:Name="menuItemReports" Header="Reports" Click="MenuItem_Click" />
<MenuItem x:Name="menuItemContracts" Header="Contracts" Click="MenuItem_Click"/>
<MenuItem x:Name="menuItemCustomers" Header="Customers" Click="MenuItem_Click" />
<MenuItem x:Name="menuItemDocumentation" Header="Documentation Creation Instructions" Click="MenuItem_Click" />
<MenuItem x:Name="menuItemEmail" Header="E-Mail" Click="MenuItem_Click" />
</ContextMenu>
</Button.ContextMenu>
</Button>
</StackPanel>
<TextBlock x:Name="TheMessage" DockPanel.Dock="Top" Text="Right-click the 'favorites' button to change its function." Margin="10" TextWrapping="Wrap"/>
</DockPanel>
</Window>

All you need to do is set the HorizontalAlignment property on your button. It defaults to stretch therefore filling the available space.
<Button x:Name="ButtonFavorite"
HorizontalAlignment="Left"
Content="Customers"
Margin="10"
Width="Auto"
Click="ButtonFavorite_Click">

Regarding your annoyance at the sizing of buttons, this is something that seems to be targeted at the designer in the designer/developer workflow, while you're clearly working on the developer portion. For the sake of development, I always apply a few styles in my App.xaml to ensure somewhat better button sizing. For example, in the application tag in your app.xaml file:
<Application.Resources>
<Style TargetType="Button">
<Setter Property="MinWidth" Value="60" />
<Setter Property="MinHeight" Value="23" />
<Setter Property="Margin" Value="3" />
</Style>
</Application.Resources>
Regarding your actual question:
The problem is that your DockPanel is stretching to the width of the text and the button will naturally expand to fill the available area. If you want the quick and dirty solution you can do something like:
<DockPanel HorizontalAlignment="Left">
<Button x:Name="ButtonFavorite"
DockPanel.Dock="Top"
Content="Customers"
Margin="10"
Width="Auto"
MaxWidth="100"
Click="ButtonFavorite_Click">
</Button>
</DockPanel>
Note the MaxWidth. If you want a more composable result, isolate your button in another panel. (I'm using a stackpanel because I believe someone else already used a grid in their example):
<DockPanel HorizontalAlignment="Left">
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal">
<Button x:Name="ButtonFavorite"
Content="Customers"
Margin="10"
Width="Auto"
Click="ButtonFavorite_Click" />
</StackPanel>
<TextBlock DockPanel.Dock="Top" Text="this is a long text which makes the button stretch across the window, if this text is just a couple words, the button will be smaller, and this drives me up the wall" Margin="10" TextWrapping="Wrap" />
</DockPanel>
I like the StackPanel in this case because I find myself using it to create the horizontal "bar" of buttons along the bottom of a Form- err- Window in the right corner.

You could try isolating the button from the main panel by putting it in another panel.
<DockPanel HorizontalAlignment="Left">
<Grid DockPanel.Dock="Top">
<Button x:Name="ButtonFavorite"
Content="Customers"
Margin="10"
Width="Auto"
Click="ButtonFavorite_Click">
</Button>
</Grid>
<TextBlock DockPanel.Dock="Top" Text="this is a long text which makes the button stretch across the window, if this text is just a couple words, the button will be smaller, and this drives me up the wall" Margin="10" TextWrapping="Wrap" />
</DockPanel>

Can you place them in a two column Grid with the button spanning just one column and the text spanning two columns?

Here's an example using a Grid layout versus a DockPanel. The idea is to have 2 columns and 2 rows. Put the Button it a single cell and make that row/column pair auto-sizing. Then put the TextBox into the second row and have it span both of the columns. This will essentially make the top-right cell just filler space and will achieve the behavior you're looking for.
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Button
x:Name="ButtonFavorite"
Grid.Column="0"
Grid.Row="0"
Content="Customers"
Margin="10"
Width="Auto"
Click="ButtonFavorite_Click">
</Button>
<TextBlock
Grid.Column="0"
Grid.ColumnSpan="2"
Grid.Row="1"
Margin="10"
TextWrapping="Wrap"
Text="this is a long text which makes the button stretch across the window, if this text is just a couple words, the button will be smaller, and this drives me up the wall" />
</Grid>

As another method to do this: You could change the button's template so it's essentially wrapped in a centered StackPanel. Something like this:
<Button Content="Back">
<Button.Template>
<ControlTemplate>
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<Button Content="{TemplateBinding Content}"></Button>
</StackPanel>
</ControlTemplate>
</Button.Template>
</Button>
Or you could add a style to app.xaml (or any other place where you're storing your global styles) like this:
<Style TargetType="{x:Type Button}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<Button Style="{x:Null}" Content="{Binding Path=Content, RelativeSource={RelativeSource AncestorType={x:Type Button}} }" FontWeight="Bold" Padding="5"></Button>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Note that it's important to include the Style="{x:Null}" attribute on the button within the template if adding to the global styles, otherwise you'll get an infinite loop when it comes to rendering the button.

Related

Border that bulges near mouse pointer

I have a ListView populated with ListViewItems, like navigation bar style menu options.
I would like to create the effect of the ListViewItem border "bulging" like in the Mail application on Win10 as shown in this picture
The border "bulges" (fisheye?) as the mouse moves left and right along the ListViewItem. It's a nice effect that I'd like to replicate but am struggling to even get started on how to tackle this.
My list items are bound to a content control which is templated with a ControlTemplate. The ItemsControl ItemTemplate is a DataTemplate containing an image and a Textbox wrapped inside a button control, like this .... (although I suspect how it's created is probably not relevant to my question)
<ContentControl Content="{Binding Path=MenuModel.AllMenuItems}"
x:Name="menuCtrl1"
Template="{StaticResource MenuListItemControlTemplate}"
VerticalAlignment="Top" />
...
<ControlTemplate x:Key="MenuListItemControlTemplate" TargetType="ContentControl">
<Border Background="Transparent" >
<ScrollViewer Margin="{StaticResource DefaultNoMargin}" HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto">
<ItemsControl ItemsSource="{TemplateBinding Content}"
ItemTemplate="{StaticResource MenuListItemDataTemplate}" />
</ScrollViewer>
</Border>
</ControlTemplate>
...
<DataTemplate x:Key="MenuListItemDataTemplate" DataType="local:SingleMenuItem">
<Button Command="{Binding MenuCommand}" Style="{StaticResource MenuButtonStyle}" >
<StackPanel Orientation="Horizontal" >
<Image Source="{Binding MenuIconSource}" Style="{StaticResource MenuItemImage}" />
<TextBox Text="{Binding DisplayText}" Style="{StaticResource MenuItemStyle}" />
</StackPanel>
</Button>
</DataTemplate>
Any tips on how to achieve it or even where to start would be gratefully received.

Wpf change the background colour of an expander's header only

I have looked at many questions/answers but couldn't find what I was exactly looking for,
I am trying to change the background colour of the expander's header only and not have the same colour continue for the content within the expander. Preferably within xaml but a vb.net solution would suffice.
(Any comments or suggestions will be helpful)
If this is a duplicated question please direct me to the answer and leave the question open to help others avoid the same issue in the future!
Thanks.
I am not sure whether this is what you are exactly looking for, but you could change the header background by simply doing that:
<Expander VerticalAlignment="Center">
<Expander.Header>
<Grid Background="LightBlue">
<TextBlock Text="Expander Header"/>
</Grid>
</Expander.Header>
<StackPanel>
<TextBlock Text="Cotent"></TextBlock>
</StackPanel>
</Expander>
Or you could override the default Expander's Header DataTemplate by using HeaderTemplate
<Window.Resources>
<DataTemplate x:Key="HeaderText">
<Border Height="25" Background="LightBlue">
<TextBlock Text="{Binding}"
Margin="4 0"
VerticalAlignment="Center"
Foreground="White"
FontSize="11"
FontWeight="Normal"
/>
</Border>
</DataTemplate>
<Style TargetType="{x:Type Expander}">
<Setter Property="HeaderTemplate" Value="{StaticResource HeaderText}"/>
</Style>
</Window.Resources>
<Grid x:Name="LayoutRoot">
<Expander VerticalAlignment="Center" Header="Expander Header">
<StackPanel>
<TextBlock Text="Cotent"></TextBlock>
</StackPanel>
</Expander>
</Grid>
I had a lot of problems with getting the header background set.
I found the easiets weay to do it was to simply make a coloured rectangle and put it behind the expander. (use Margin and Height to make it fit)
<Rectangle Grid.Row="1" Grid.Column="0" Fill="LightBlue" Height="33" Margin="0,0,0,-35" />
or use a border if you want rounded corners:
<Border CornerRadius="15" Height="33" Margin="0,0,0,-35" Background="LightBlue" />

WPF Net Framework 3.5 Window Metro Style

I want to make Window with Metro style.
I found the 3 following libraries:
http://elysium.asvishnyakov.com/en/
https://github.com/MahApps/MahApps.Metro
http://mui.codeplex.com/
All are for Net Framework 4+.
Is there anything for 3.5?
I also tried to make it on my own (Didnt finish - still need to design it and add Resize [which I dont know how]) but I dont really like how it's made...:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit" x:Class="Windows_Hider.MainWindow"
Title="Windows Hider" Height="350" Width="525" WindowStartupLocation="CenterScreen"
AllowsTransparency="True"
ResizeMode="CanResize" WindowStyle="None" BorderBrush="Black" BorderThickness="1" Icon="windowshider.ico">
<Grid>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Left" VerticalAlignment="Top">
<Image Width="24" Height="24" Source="{Binding Icon, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}"/>
<Label VerticalAlignment="Center" FontSize="14" Content="{Binding Title, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}"/>
</StackPanel>
<Grid MouseDown="Grid_MouseDown" Background="Transparent"/>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" VerticalAlignment="Top" Grid.Row="0">
<Button ToolTip="minimize" Background="White">
<Grid Width="30" Height="25">
<TextBlock Text="0" FontFamily="Marlett" FontSize="14" VerticalAlignment="Center" HorizontalAlignment="Center" Padding="3.5,0,0,3" />
</Grid>
</Button>
<Grid Margin="1,0,1,0">
<Button x:Name="Restore" ToolTip="restore" Visibility="Collapsed">
<Grid Width="30" Height="25" UseLayoutRounding="True">
<TextBlock Text="2" FontFamily="Marlett" FontSize="14" VerticalAlignment="Center" HorizontalAlignment="Center" Padding="2,0,0,1" />
</Grid>
</Button>
<Button x:Name="Maximize" ToolTip="maximize">
<Grid Width="31" Height="25">
<TextBlock Text="1" FontFamily="Marlett" FontSize="14" VerticalAlignment="Center" HorizontalAlignment="Center" Padding="2,0,0,1" />
</Grid>
</Button>
</Grid>
<Button x:Name="Close" ToolTip="close">
<Grid Width="30" Height="25">
<TextBlock Text="r" FontFamily="Marlett" FontSize="14" VerticalAlignment="Center" HorizontalAlignment="Center" Padding="0,0,0,1" />
</Grid>
</Button>
</StackPanel>
</Grid>
</Grid>
</Window>
Ok, it took me few days but in the end I managed to do something.
I had to make it by myself because there's no Metro Window for Net Framework 3.5.
I combined some of the references below:
Launch window's System Menu on custom window
http://www.codeproject.com/Articles/107994/Taskbar-with-Window-Maximized-and-WindowState-to-N
http://blog.magnusmontin.net/2013/03/16/how-to-create-a-custom-window-in-wpf/
http://codekong.wordpress.com/2010/11/10/custom-window-style-and-accounting-for-the-taskbar/
http://blog.creativeitp.com/posts-and-articles/c-sharp/simple-methods-to-drag-and-resize-your-c-transparent-wpf-application-with-the-windowstyle-property-set-to-none/
this is the final solution
Known problems / bugs:
1. When resizing the arrow cursor appear instead of the resizing cursor.
2. Designer cant display the custom window.
3. When maximizing, randomly there's blue (the color of the borders) in big area of the screen - for split second
If you can fix any of the problems above it will be even better but I am satisfied with what I achieved.
EDIT:
Updated to allow resize modes (also added sample)
It's relatively easy to do this yourself... all you need to do is copy the Style that you see in the Metro UI, as you call it. To start you off, here is a very simple Style that changes the ControlTemplate of the Button elements to remove their default look:
<Style TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid>
<ContentPresenter HorizontalAlignment="Center"
VerticalAlignment="Center" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Of course, you'll want something to happen when the user moves their mouse pointer over the Button and you can do that by adding VisualStateManager.VisualStateGroups to the ControlTemplate. You can find a full example of this in the ControlTemplate Class page on MSDN.
The other controls Metro-style controls can be easily developed by creating simple ControlTemplates in the same way. Basically, you'll just need to remove the default WPF look and for the most part, just replace it with just a ContentPresenter as in the above example, or an ItemsPresenter for collection controls. Luckily the Metro look is very plain and simple, just remember to keep everything spaced out and plain.
To address another point you mad about resizing; you can set the Window.ResizeMode property to CanResizeWithGrip to add the resize grip in the bottom right corner of the Window as is often seen in these applications.

TextBox in UserControl doesn't take all the space

I have a WPF listbox with custom items. Each item is a user control consisting of a grid with two textboxes. I want that the right one takes all the space to fill the ListBoxItem. But all I get working is that the item itself takes the whole space but the textbox takes the size of its content.
So this is the listbox:
<ListBox x:Name="leftListBox" Grid.Column="0" Margin="10"
HorizontalContentAlignment="Stretch">
<ListBox.ItemTemplate>
<DataTemplate>
<local:CustomLine />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
And the user control:
<UserControl x:Class="SharpComparer.CustomLine"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="30">
<UserControl.Resources>
<Style TargetType="{x:Type TextBox}">
<Setter Property="VerticalAlignment" Value="Center" />
</Style>
</UserControl.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="40" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBox x:Name="NumberColumn" x:FieldModifier="public"
Text="{Binding LineNumber}"
Grid.Column="0" HorizontalAlignment="Right" />
<TextBox x:Name="TextColumn" x:FieldModifier="public"
Text="{Binding Text}"
Grid.Column="1" HorizontalAlignment="Left" />
</Grid>
</UserControl>
What I have already tried after some research at some MSDN posts and around here on Stack Overflow: Setting the HorizontalContentAlignment to Stretch for Listbox.ItemContainerStyle. I used some borders to find the piece which makes problems. The ListBoxItems seem to take the whole width, the usercontrol and its grid, too. The textbox does not take all the space although I thought that Width="*" inside the grid's ColumnDefinition would do that.
Another idea was to bind the textbox width to its parent size, but then it also takes the space of the left textbox (which makes sense, because it gets the whole width) and subtracting this width doesn't seem to work.
What am I doing wrong?
You have to change your UserControl code from this:
<TextBox x:Name="TextColumn" x:FieldModifier="public"
Text="{Binding Text}"
Grid.Column="1" HorizontalAlignment="Left" />
to this:
<TextBox x:Name="TextColumn" x:FieldModifier="public"
Text="{Binding Text}"
Grid.Column="1" HorizontalAlignment="Stretch" />

Borderless ImageButtons in WrapPanel

I am attempting to create a WrapPanel with seamless ImageButtons containing Artwork. I put together the following ContentTemplate in the hopes that it would provide the seamless look required; however a thin white-line remained around each of the buttons. Can anyone steer me in the right direction?
<Button.ContentTemplate>
<DataTemplate DataType="{x:Type local:ArtInfo}">
<Border Name="border" BorderThickness="0" BorderBrush="blue" Height="280" Width="250" Background="#262c40">
<StackPanel>
<Grid>
<Grid.Resources>
<local:MyConverter x:Key="MyConverter"></local:MyConverter>
<ObjectDataProvider x:Key="Properties.Settings" ObjectType="{x:Type lcl:Properties.Settings}" />
</Grid.Resources>
<Image Name="ArtImage" Margin="10,15,0,0" Height="195" Width="195" VerticalAlignment="Top" >
<Image.Source>
<Binding Path="ArtImage"/>
</Image.Source>
</Image>
</Grid>
<TextBlock Text="{Binding Path=ArtClass}" Margin="10,-17,0,0" FontSize="11" Foreground="white" />
<TextBlock Text="{Binding Path=Student}" Margin="10,0,0,0" FontSize="11" Foreground="white" />
<TextBlock Text="1998" Margin="10,0,0,0" FontSize="11" Foreground="white" />
</StackPanel>
</Border>
</DataTemplate>
</Button.ContentTemplate>
The ContentTemplate tells WPF how to display the content within the Button -- the Button chrome (such as the border and background) remains, and the templated content is displayed within and over that chrome.
You want to replace the entire appearance of the Button, border and all, rather than just customising how its content is displayed. To do this, you need to use the Template property instead. The value of Button.Template is a ControlTemplate rather than a DataTemplate. Within that ControlTemplate, you can use the ContentPresenter to display the "data-templated" content.
In your case, since your DataTemplate is doing all the work, you could get away with a raw ContentPresenter as your template:
<Button.Template>
<ControlTemplate TargetType="Button">
<ContentPresenter />
</ControlTemplate>
</Button.Template>
However, if all your buttons are using the same background, you could move this into the ControlTemplate:
<Button.Template>
<ControlTemplate TargetType="Button">
<Border BorderBrush="Blue" ...>
<ContentPresenter />
</Border>
</ControlTemplate>
</Button.Template>
You could then remove the Border from the DataTemplate. This would really only matter if you were planning to reuse the same Button.Template with other content templates and wanted to keep the appearance of the Button consistent across different kinds of content.
create a usercontrol, put the botton & image in a grid.
<Grid>
<Image Source="icon.png" Panel.ZIndex="1" />
<Button
Panel.ZIndex="2"
FocusVisualStyle="{x:Null}"
Background="Transparent"/>
</Grid>

Resources