Border that bulges near mouse pointer - wpf

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.

Related

WPF Popup inside a DataTemplate

I need a WPF Popup inside a DataTemplate, something like this:
<ScrollViewer>
<ItemsControl ItemsSource="{Binding Collection}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<TextBox Name="MyTextboxBrief" Text="{Binding TextBrief}"/>
<Popup PlacementTarget="{Binding ElementName=MyTextboxBrief}" Placement="Center">
<TextBox Name="MyTextboxVerbose" Text="{Binding TextVerbose}"/>
</Popup>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
But, this Popup should behave like this:
it must scroll together with relevant ItemsControl item
when app window is minimized - it shouldn't stay visible on desktop
it will be taller than ItemsControl, its content mustn't be clipped, but it mustn't change ItemsControl height
it will be wider than relevant ItemsControl item - but it shouldn't shift other ItemsControl items to the left or to the right
I have a strong feeling that I should somehow use ComboBox template - but I don't understand how to get it's Popup behavior
I don't think that Popup will help you here, nor ComboBox. See if this helps you any further:
<DataTemplate>
<Grid>
<TextBox Name="MyTextboxBrief" Text="{Binding TextBrief}" />
<!-- You might want to bind visibility against
some kind of property -->
<Canvas >
<Canvas.RenderTransform>
<!--In case you want to move-->
<TranslateTransform Y="-5" />
</Canvas.RenderTransform>
<Border Width="100" Height="20" Background="Black">
<TextBlock Text="Test" />
</Border>
</Canvas>
</Grid>
</DataTemplate>

Attach Flyout to Listview

I have a Listview defined like this:
<ListView x:Name="lvPlaylist" Width="530" Height="337" IsItemClickEnabled="True" ItemClick="gvPlaylist_ItemClick">
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<Image Stretch="Fill" Source="{Binding albumArtURI}" Height="48" Width="48" />
<TextBlock Text="{Binding GetPlaylistFormat}" Width="500" Height="18"/>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
I want to open a "context"-Flyout on each Item on click.
So far I was only able to attach the flyout to the whole but then the flyout is shown at the border of the listview - not directly attached to the selected item.
Buttons have a Flyout property. All you have to do is wrap the contents of the template in a Button, create a Style for the button which removes all visuals for it, then create a Flyout for it.
<DataTemplate>
<Button Style="{StaticResource ButtonWrapperStyle}">
<Button.Content>
<Grid>
<Image Stretch="Fill" Source="{Binding albumArtURI}" Height="48" Width="48" />
<TextBlock Text="{Binding GetPlaylistFormat}" Width="500" Height="18"/>
</Grid>
</Button.Content>
<Button.Flyout>
<!-- Make Flyout Here -->
</Button.Flyout>
</Button>
</DataTemplate>
Obviously there is stuff left to do here, but you get the idea.
Hope this helps and happy coding!
Looks like you can also do it like this
From MSDN
"The next example shows a Flyout attached to a TextBlock. As noted earlier, you can attach a Flyout to any FrameworkElement by using the FlyoutBase.AttachedFlyout attached property."
<TextBlock Text="{Binding ElementName=MyTextBox, Path=Text}"
Tapped="TextBlock_Tapped" FontSize="18">
<FlyoutBase.AttachedFlyout>
<Flyout>
<TextBox x:Name="MyTextBox" Text="You can edit this text by tapping it."/>
</Flyout>
</FlyoutBase.AttachedFlyout>
</TextBlock>

How to make Buttons in ListBox all the same width

My WPF application contains a window that has a single ListBox in it. The View Model for the window contains an ObservableCollection of DomainViewModel objects.
The window defines the following DataTemplate:
<DataTemplate x:Key="DomainTemplate" DataType="DomainViewModel">
<Border BorderBrush="{Binding Converter={StaticResource BrushConverter}, Path=IsSelected}"
BorderThickness="2"
Name="SelectedBorder">
<Button Click="SelectDomain_Click"
Content="{Binding Path=Name}"
FontSize="16"
FontWeight="Bold"
Height="60"
HorizontalAlignment="Stretch" />
</Border>
</DataTemplate>
And here's the ListBox's declaration:
<ListBox FontSize="16"
FontWeight="Bold"
Grid.Row="2"
ItemsSource="{Binding Path=Domains}"
ItemTemplate="{StaticResource DomainTemplate}"
Name="DomainListBox" />
When the window renders, each button is exactly wide enough to display the text in its Content property. But that's not what I want. I want each button to be the width of the ListBox, which is going to vary with the width of the window itself.
How do I get the Buttons to keep their width set to the ListBox's width?
<ListBox HorizontalContentAlignment="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>

Why does this WPF button stretch across the window?

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.

Resources