I am trying to make a button in WPF that will show progress but still have its button text visible.
I tried adding a Grid as a child to the button and adding a ProgressBar and Label to the grid, thinking the Grid will fill the button and using VerticalAlignment="Stretch" HorizontalAlignment="Stretch" on the progress bar and label will get me, basically, a clickable progress bar, that can show progress and have a label on top of it. However, I'm having problem with the sizing.
This is my XAML:
<Button Grid.Column="0" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" MinWidth="100" MinHeight="25" Margin="3">
<Grid>
<ProgressBar Value="10" Maximum="20" VerticalAlignment="Stretch" HorizontalAlignment="Stretch"/>
<Label Content="asd2" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" VerticalContentAlignment="Center" HorizontalContentAlignment="Center"/>
</Grid>
</Button>
This is what I see:
If I change to explicit sizing:
<Button Grid.Column="0" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" MinWidth="100" MinHeight="25" Margin="3">
<Grid>
<ProgressBar Value="10" Maximum="20" Width="100" Height="30" VerticalAlignment="Stretch" HorizontalAlignment="Stretch"/>
<Label Content="asd2" Width="100" Height="30" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" VerticalContentAlignment="Center" HorizontalContentAlignment="Center"/>
</Grid>
</Button>
I get this:
Which, visually, is an improvement, but XAML-programatically is worse, since I want the button to resize with the window, if the user can't see it well or something like that. Also, visually - I don't like that little border between the actual button and the start of the progressbar and I've tried setting both "padding" and "margin" to 0, it's not from that.
What I'd like to see - the progress bar taking up ALL the space of the button and the label text staying centered both vertically and horizontally, with respect to the total size of the button.
Put your <Grid> inside of a ControlTemplate and override your <Button.Template>:
<Button Grid.Column="0" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" MinWidth="100" MinHeight="25" Margin="3">
<Button.Template>
<ControlTemplate TargetType="Button">
<Grid>
<ProgressBar Value="10" Maximum="20" VerticalAlignment="Stretch" HorizontalAlignment="Stretch"/>
<Label Content="asd2" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" VerticalContentAlignment="Center" HorizontalContentAlignment="Center"/>
</Grid>
</ControlTemplate>
</Button.Template>
</Button>
What you were doing before is putting your <Grid> inside of the Button's ContentTemplate, not its Template. The problem with the ContentTemplate is that it has some of the default button's styling, such as the little border you don't like. By moving it to the Button's overall Template, you're saying I don't care about how the default button looks, I want it to look exactly like THIS.
What it can look like:
What it can look like if you resize the window:
Related
I am building a WPF MVVM application.
What I have:
I have a ShellWindow which looks like this:
It is composed by 2 rows:
1: the hamburger menu (not important) with Height="*"
2: the console with Height="100"
The console is a UserControl:
<UserControl
//namespaces>
<Grid Name="LoggingGrid" Background="Black">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Margin="{StaticResource SmallLeftMargin}">
<Button
x:Name="CollapseBtn"
Width="25"
Height="25"
Click="CollapseBtn_Click"
Content="▲">
<Button.Template>
<ControlTemplate TargetType="{x:Type Button}">
<Grid>
<Ellipse Fill="White" />
<ContentPresenter
HorizontalAlignment="Center"
VerticalAlignment="Center"
Content="{TemplateBinding Content}" />
</Grid>
</ControlTemplate>
</Button.Template>
</Button>
<StackPanel Margin="5,0,0,0" Orientation="Horizontal">
<Image
Height="25"
Source="/Images/console-icon.png"
Visibility="Visible" />
<Label
Content="Console"
FontSize="16"
Foreground="White" />
</StackPanel>
</TextBlock>
<Border Grid.Row="1">
<ListView
x:Name="LoggingList"
Margin="5"
Background="Black"
BorderThickness="0"
Foreground="White"
ItemsSource="{Binding Logs, UpdateSourceTrigger=PropertyChanged}"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ScrollViewer.VerticalScrollBarVisibility="Auto" />
</Border>
</Grid>
</UserControl>
I have omitted the non-important things.
What I want to do:
Whenever the user clicks on the button, the console should collapse and look something like this:
The arrow is also changed.
How can I implement this? What is the best approach using MVVM?
What I have tried:
I have tried using a button click event handler in the code behind - CollapseBtn_Click, just to see what will happen:
private void CollapseBtn_Click(object sender, System.Windows.RoutedEventArgs e)
{
LoggingGrid.Visibility = System.Windows.Visibility.Hidden;
}
Apparently it removes the user control and leaves a white background where it used to be.
Instead of setting the Visibility of the whole LoggingGrid to Hidden, you should set the Visibility of the LoggingList to Collapsed. (For the difference between Hidden and Collapsed, see here: Difference between Visibility.Collapsed and Visibility.Hidden).
Depending on your layout in the ShellWindow you probably have to adjust your row height configuration in the UserControl such that the collapsed LoggingGrid leads to a row with a height of zero.
Regarding MVVM the best approach would be to bind the Button to a bool property ConsoleVisible on your ViewModel such that clicking the button toggles the property between true and false. The styling of the button can be bound to the same property. For the LoggingList Visibility you could use a Binding with a BooleanToVisibilityConverter on the same property.
I'm trying to create a screen, or border where if the user click anywhere inside within this border. It should turn my border color RED. Currently i have my XAML setup as...
<StackPanel VerticalAlignment="Top" Orientation="Horizontal">
<Border Margin="10" Padding="10" BorderBrush="Blue" BorderThickness="1" MouseDown="OnMouseDown" Width="200" Height="200">
<TextBlock VerticalAlignment="Center" HorizontalAlignment="Center" TextWrapping="Wrap" Text="Click anywhere in here, the border should turn red" />
</Border>
<Border Margin="10" Padding="10" BorderBrush="Blue" BorderThickness="1" MouseDown="OnMouseDown" Width="200" Height="200">
<TextBlock VerticalAlignment="Center" HorizontalAlignment="Center" TextWrapping="Wrap" Text="Click anywhere in here, the border should turn red" />
</Border>
<Border Margin="10" Padding="10" BorderBrush="Blue" BorderThickness="1" MouseDown="OnMouseDown" Width="200" Height="200">
<TextBlock VerticalAlignment="Center" HorizontalAlignment="Center" TextWrapping="Wrap" Text="Click anywhere in here, the border should turn red" />
</Border>
</StackPanel>
And the output looks like this...
The problem now is that the "Border" is unable to recognize my MouseDown button. It doesnt register my mousedown anywhere inside the border, but only on the border itself. I want it so that if the user click anywhere inside, it should change my border color. How can i do that?
Please note that i need to eventually put content inside my border, be it a video, images, multiple UI controls, or whatever, so if user click anything inside this border, it should "select" my border and turn it red.
I experimented with other things like a Rectangle but Rectangle i cannot use because i am unable to put other UI elements or control in there.
Anyone know what is the correct way to do it?
Requirement:
within border selection, turn border red.
within border unselection, turn border back to blue.
border should eventually allow contents inside, such as the textblock, images, video, or anything.
Just add a transparent background to capture mouse clicks
<Border Background="Transparent" Margin="10" Padding="10" BorderBrush="Blue" BorderThickness="1" MouseDown="OnMouseDown" Width="200" Height="200">
<TextBlock VerticalAlignment="Center" HorizontalAlignment="Center" TextWrapping="Wrap" Text="Click anywhere in here, the border should turn red" />
</Border>
Note that any controls inside the border could steal events away from the border. In that case you may need a transparent border over the top of everything, or handle routed events. or just use a ToggleButton instead and change its template.
<StackPanel VerticalAlignment="Top" Orientation="Horizontal">
<StackPanel MouseDown="OnMouseDown">
<Border Margin="10" Padding="10" BorderBrush="Blue" BorderThickness="1" Width="200" Height="200">
<TextBlock VerticalAlignment="Center" HorizontalAlignment="Center" TextWrapping="Wrap" Text="Click anywhere in here, the border should turn red" />
</Border>
</StackPanel>
Wrap it inside container..
I have a problem on how to correctly set the Panel.ZIndex of a Popup inside a Grid. The goal is that when I click the Emergency button, a Popup window will display with an image on it and overlay (cover) the buttons (see screenshot below).
I have set the Grid Panel.ZIndex="0"and the Popup to Panel.ZIndex="1" However, the Popup window doesn't overlay the buttons.
This is the XAML implementation.
<StackPanel Background="Black">
<Grid Background="#253341" Panel.ZIndex="0">
<Popup HorizontalOffset="-5" VerticalOffset="0" IsOpen="False"
HorizontalAlignment="Left" VerticalAlignment="Top"
Name="EmergencyPopup" Placement="RelativePoint" AllowsTransparency="True"
PlacementTarget="{Binding ElementName=EmergencyButton}"
Width="1080" Height="1920" Panel.ZIndex="1">
<Border BorderBrush="Black" BorderThickness="2" CornerRadius="2">
<Grid>
<Image Source="{StaticResource EdenParkInfoImg}"/>
<Label FontWeight="Bold" Foreground="Red" HorizontalAlignment="Right" FontSize="25"
MouseLeftButtonDown="Label_MouseLeftButtonDown">close X</Label>
</Grid>
</Border>
</Popup>
</Grid>
</StackPanel>
Screenshot of the Popup window and buttons (the red box indicates that the image inside the Popup is behind the buttons)
Have I correctly set the Panel.ZIndex of the Grid and Popup? What is the correct way of doing it?
Any help is greatly appreciated.
I did find a way on how to solve the issue. In my Popup dialog xaml implementation, I set HorizontalOffset to 0 and VerticalOffset to 180. In that way, Popup dialog vertically overlays the buttons and ZIndex no longer matters. WPFUser is right, it should work without explicitly defining ZIndex.
<Popup HorizontalOffset="0" VerticalOffset="180" IsOpen="False" Width="1080"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Height="1920"
Name="EmergencyPopup" Placement="Top" AllowsTransparency="True">
<Border BorderBrush="Black">
<Grid>
<Image Source="{StaticResource EdenParkInfoImg}" />
<Label FontWeight="Bold" Foreground="Red" HorizontalAlignment="Right" FontSize="25"
MouseLeftButtonDown="Label_MouseLeftButtonDown" Margin="0,0,15,0">close X
</Label>
</Grid>
</Border>
</Popup>
I'm new in XAML for Windows Phone 8.1 and have some troubles with
making a Stackpanel clickable
collapse Item, when clicked
My work so far looks like that:
And the Code to that (please correct me, if there are major flaws):
<Border CornerRadius="15" Background="#FF595656" Margin="0" Grid.ColumnSpan="2" Height="80">
<StackPanel Orientation="Horizontal">
<StackPanel Width="20" HorizontalAlignment="Left" VerticalAlignment="Top" />
<StackPanel HorizontalAlignment="Left" Height="80" Margin="0,0,0,0" VerticalAlignment="Center" Width="51">
<Image HorizontalAlignment="Left" Height="51" Margin="0,15,0,0" Width="51" Source="Assets/fish.png" Stretch="Fill" RenderTransformOrigin="2.307,0.881" VerticalAlignment="Center"/>
</StackPanel>
<StackPanel Width="10" HorizontalAlignment="Left" VerticalAlignment="Top" />
<StackPanel HorizontalAlignment="Left" Height="80" Margin="0" VerticalAlignment="Top" Width="310">
<TextBlock HorizontalAlignment="Left" Height="25" Margin="0,20,0,0" TextWrapping="Wrap" Text="Entry 1" Width="310" VerticalAlignment="Top" FontSize="18" Foreground="Black" FontWeight="Bold"/>
<TextBlock HorizontalAlignment="Left" Height="17" Margin="0" TextWrapping="Wrap" Text="Short description Entry 1" Width="310" VerticalAlignment="Top" Foreground="#FF0097FF"/>
</StackPanel>
</StackPanel>
</Border>
This code will later be wrapped inside a ListBox with Image, Entry 1 and the short description being bound:
<ListBox x:Name="ListBox1" Margin="0"
Width="400" Height="200" HorizontalAlignment="Left"
ItemsSource="{Binding}" Grid.Row="1" VerticalAlignment="Top" Grid.ColumnSpan="2" >
<ListBox.ItemTemplate>
<DataTemplate>
// the code above
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
So my question is:
How can I make a nice looking expansion/collapse of each Item in the ListBox, whenever I click on it?
Thank you very much in advance.
The real question is here is what do you want it to collapse to? There are too many possible ways to collapse some visual data item. Do you just want to change the height of the item or do you want some fancy animation that collapse some property?
If the height is what you're looking for it's pretty easy. Just attach an Tap Event on that Border of yours. On a sidenote, you probably want to edit the ItemContainerStyle to have <Setter Property="HorizontalContentAlignment" Value="Stretch"/> so the Listbox will stretch across the screen, otherwise imho it's un-useable.
<ListBox.ItemTemplate>
<DataTemplate>
<Border BorderBrush="Red" BorderThickness="0,1" Tap="Border_Tap">
<StackPanel>
<!--- rest of template --->
</StackPanel>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
Then calculate the Minimum height you want to show (make sure it's actually useable, meaning... I can Tap on it again to show the whole thing without using a Mag Glass).
private void Border_Tap(object sender, System.Windows.Input.GestureEventArgs e)
{
int minHeight = 40; // change to whatever you want
Border b = sender as Border;
if (b.ActualHeight > minHeight)
{
b.Height = minHeight;
}
else
{
b.Height = double.NaN; // this will change the height back to Auto, showing everything
}
}
Code In Action
This is just a quick solution to your question. Some people on here would rather have you create a StoryBoard Animation on the Height Property of the Selected state in the VisualStateManager. If you reword or create a new question explicitly stating you want a VisualStateManager solution, I will provide you one as well. Good luck.
I have a custom control ButtonRow which will end up going into a different control.
It is very simple, it has one Border, on label and one button.
I need to make it so that the border will extend its width to fill up to where the button is.
This is not happening as you can see in the below image:
The XAML can be found below. I have tried fiddling about with the horizontal alignment of both he label and the border, but they will only ever re-size to fit the text content of the label.
I know there are existing question with very similar problems and names, but none have needed to do quite the same thing or have helped me solve my problem.
I have tried using a StackPanel in horizontal alignment but all it did was make the button go next to the border.
How can I make the border expand to fill the available space?
<Grid>
<DockPanel Height="Auto" HorizontalAlignment="Stretch" Margin="0" Name="dockPanel1" VerticalAlignment="Top" Width="Auto">
<Border BorderBrush="#FFDADFE1" Background="#FFECF0F1" BorderThickness="1" Height="20" Name="bdrFilter" HorizontalAlignment="Stretch">
<Label Content="Filter..." FontStyle="Italic" Foreground="#FF6C7A89" Height="20" Name="lblFilter" Padding="5,0" HorizontalContentAlignment="Stretch" HorizontalAlignment="Stretch" />
</Border>
<Button Style="{StaticResource FlatButtonStyle}" Content="+" Height="20" HorizontalAlignment="Right" Name="btnAddFilter" VerticalAlignment="Top" Width="20" Foreground="#FF6C7A89" ForceCursor="True" BorderBrush="{x:Null}" />
</DockPanel>
</Grid>
(The button style does not affect its alignment or any other relevant properties)
A DockPanel is not the correct Panel to use for this requirement... like a StackPanel, it does not resize its contents. Instead, just use a regular Grid (which also uses less resources than a DockPanel):
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Border BorderBrush="#FFDADFE1" Background="#FFECF0F1" BorderThickness="1"
Height="20" Name="bdrFilter" VerticalAlignment="Top">
<Label Content="Filter..." FontStyle="Italic" Foreground="#FF6C7A89"
Height="20" Name="lblFilter" Padding="5,0" />
</Border>
<Button Grid.Column="1" Content="+" Height="20" HorizontalAlignment="Right"
Name="btnAddFilter" VerticalAlignment="Top" Width="20" Foreground="#FF6C7A89"
ForceCursor="True" BorderBrush="{x:Null}" />
</Grid>
Please see the Panels Overview page on MSDN for more information about the different Panels in WPF.
This might help you out. Setting LastChildFill=True inside a DockPanel does exactly what the name suggests.