Im new to WPF. I try to bind to the click event on the listBox element. Element is TextBlock so it doesnt work as expected so that I decided to create custom control:
ClickableTextBlock:
xaml:
<Button VerticalAlignment="Center" Name="btnButton" HorizontalAlignment="Center" >
<Button.Template>
<ControlTemplate>
<TextBlock Name="tbText"></TextBlock>
</ControlTemplate>
</Button.Template>
</Button>
What I would like to achive is to be able to control from the main xaml code where is the listBox, what property of the dataContext to bind to the custom control and what command bind to thje click event of this custom control:
<ListBox ItemsSource="{Binding Items.Result}" Margin="0,5,0,10" x:Name="listBox" >
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<StackPanel Orientation="Horizontal" Grid.Row="0" VerticalAlignment="Center">
<!-- my custom control here: -->
<controls:ClickableTextBlock ... <HERE PUT THE CODE...> >
</controls:ClickableTextBlock>
</StackPanel>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
what is the best aproach if possible to do sth like that ?
Related
I have a simple app that has three columns in the window. In the middle column, I have a ListBox component.
What I want is the ListBox to stretch the full height of the column, but also be scrollable when it has a lot of stuff in it. Right now, it's not scrollable. I can fix this by adding a Height (e.g. Height="300") property to it, but then it won't stretch with the column anymore. What do I do?
<Window x:Class="UI.MainWindow"
<!-- window stuff -->
<Border Padding="10">
<StackPanel>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" MinWidth="150" MaxWidth="200" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<!-- column 1 stuff -->
<StackPanel x:Name="LogLines" Grid.Column="1">
<StackPanel Orientation="Horizontal">
<Label>Search</Label>
<TextBox x:Name="Searchbox" Height="20" TextWrapping="Wrap" Text="TextBox" Width="120" />
<CheckBox x:Name="ErrorsOnlyCheckbox" HorizontalAlignment="Right">
Errors only
</CheckBox>
</StackPanel>
<ListBox
x:Name="LogLinesList"
ScrollViewer.CanContentScroll="True" />
</StackPanel>
<GridSplitter Grid.Column="1" Width="10" />
<!-- column 3 stuff -->
</Grid>
</StackPanel>
</Border>
</Window>
Container of your ListBox is StackPanel. StackPanel will increase regarding child controls. You should use another container, try to use Grid instead
<Grid x:Name="LogLines" Grid.Column="1">
<Grid.RowDefinitions>
<RowDefinition Width="Auto"/>
<RowDefinition Width="*" />
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal" Grid.Row="0">
....
</StackPanel>
<ListBox Grid.Row="1"/>
</Grid>
I'm building a grid via WPF, and it works great. I need to add a row, or bar, or something to display above the grid, that will have several text items on it that will get populated by code. I've been tooling around, and I can't seem to figure out how to put another panel above my existing (and working) grid. This is my code:
<Window x:Class="GridWPF.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Board" SizeToContent="WidthAndHeight" Height="Auto" Width="Auto">
<Window.Resources>
<DataTemplate x:Key="DataTemplate_2">
<Button Content="{Binding}" Height="25" Width="25" Margin="0,0,0,0"/>
</DataTemplate>
<DataTemplate x:Key="DataTemplate_1">
<ItemsControl ItemsSource="{Binding}" ItemTemplate="{DynamicResource DataTemplate_2}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</DataTemplate>
</Window.Resources>
<Grid Name="GridBoard" ShowGridLines="True">
<ItemsControl x:Name="GridItems" ItemTemplate="{DynamicResource DataTemplate_1}"/>
</Grid>
</Window>
The GridItems gets populated by a jagged array, and displays fine. I just need to put a few text objects above it, be it boxes, or just a horizontal panel that fits the width of the grid.
May be the simplest option is to add a wrapper Grid and put your inner Grid in the second row. So, you will have the first row (row 0) to put anything you need there.
<Window x:Class="GridWPF.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Board" SizeToContent="WidthAndHeight" Height="Auto" Width="Auto">
<Window.Resources>
<DataTemplate x:Key="DataTemplate_2">
<Button Content="{Binding}" Height="25" Width="25" Margin="0,0,0,0"/>
</DataTemplate>
<DataTemplate x:Key="DataTemplate_1">
<ItemsControl ItemsSource="{Binding}" ItemTemplate="{DynamicResource DataTemplate_2}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</DataTemplate>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid>
<!-- WHATEVER YOU NEED -->
</Grid>
<Grid Name="GridBoard" ShowGridLines="True" Grid.Row="1">
<ItemsControl x:Name="GridItems" ItemTemplate="{DynamicResource DataTemplate_1}"/>
</Grid>
</Grid>
There are a few ways to achieve it.
1 - you can add a row and columns to your grid definition:
<Grid.ColumnDefinitions>
<ColumnDefinition width="*" />
<ColumnDefinition width="*" />
<ColumnDefinition width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
Then you can just assign 'headers' to each column, like so:
<TextBlock ... Grid.Column="0" />
<TextBlock ... Grid.Column="1" />
<TextBlock ... Grid.Column="2" />
And place your ItemsControl in the second row:
<ItemsControl ... Grid.Row="1" Grid.ColumnSpan="3" />
A half-assed way that may or may not work in your case. No way of knowing without taking a look at the DataTemplate.
2 - StackPanel at the top, with margin applied to the ItemsControl
You can use a similar half-solution - set the top margin of your ItemsControl to a fixed value, like so:
<ItemsControl ... Margin="2,48,2,2" />
And add a StackPanel to your grid:
<StackPanel Height="48" VerticalAlignment="Top">
<TextBlock Text="First Header" Width="300" />
...
</StackPanel>
I'm sure you get the idea.
3 - Use a GridView -RECOMMENDED-
This would require you to change your ItemsControl to a ListView, though.
Here is a well-written tutorial on GridViews for WPF. Granted, it might not be what you're looking for, but again - without knowing what you're trying to present it's difficult to find best solution.
I don't know what you expect the output to look like, but you can nest your "GridBoard" Grid within another Grid. The new outer Grid defines two rows, whereby in the first row you can put your boxes or whatever you like. This could look like this for example:
<Window x:Class="GridWPF.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Board" SizeToContent="WidthAndHeight" Height="Auto" Width="Auto">
<Window.Resources>
<DataTemplate x:Key="DataTemplate_2">
<Button Content="{Binding}" Height="25" Width="25" Margin="0,0,0,0"/>
</DataTemplate>
<DataTemplate x:Key="DataTemplate_1">
<ItemsControl ItemsSource="{Binding}" ItemTemplate="{DynamicResource DataTemplate_2}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</DataTemplate>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid Grid.Row="0">
<TextBlock Text="Put something here ..." />
</Grid>
<Grid Grid.Row="1" Name="GridBoard" ShowGridLines="True">
<ItemsControl x:Name="GridItems" ItemTemplate="{DynamicResource DataTemplate_1}"/>
</Grid>
</Grid>
</Window>
Note that you could use any element for the content of the first row of your outer Grid. This depends on your actual needs. In this example I used another Grid which contains a single TextBlock.
So I am having some trouble getting the binding of a lisbox height to work. I have a user control that holds a listbox, this box is dynamically populated on the fly but it seems that if too many items are added it extends past the boundaries of the parent objects and refuses to stop and use the scoll bar...
<UserControl x:Class="TransaltionModule.Views.NoteView"
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">
<Grid>
<ListBox ItemsSource="{Binding noteList}" ScrollViewer.HorizontalScrollBarVisibility="Disabled" ScrollViewer.VerticalScrollBarVisibility="Auto" >
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="1*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="1*"/>
<RowDefinition Height="5*"/>
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal" Grid.Column="0">
<TextBlock Text="Type :" VerticalAlignment="Center" FontSize="14" Width="65"/>
<TextBox Text="{Binding noteType}" Width="auto" IsEnabled="False" VerticalAlignment="Center" FontSize="14"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Grid.Column="1" HorizontalAlignment="Right">
<TextBlock Text="Date :" VerticalAlignment="Center" FontSize="14" Width="65"/>
<TextBox Text="{Binding timeStamp}" Width="auto" IsEnabled="False" VerticalAlignment="Center" FontSize="14"/>
</StackPanel>
<TextBlock Grid.Row="1" Text="{Binding text}" Grid.ColumnSpan="2"/>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
If i hardcode the maxheight property everything works as intended, but with the multiple display resolutions I will be working against that is not a solution I can use. Can anyone recommend a fix
You can bind it to an element by using Path=ActualHeight
For this to work don't forget to name the Grid containing the Listbox
Try something like this :
<Grid x:Name = "grdListBoxTest">
<ListBox x:Name="lstBoxTest"
MaxHeight="{Binding ElementName=grdListBoxTest, Path=ActualHeight}">
<!-- Your Listbox Stuff Here -->
</ListBox>
</Grid>
By doing this you link the height of the Listbox to it's parent Grid. That way if the grid's size changes the MaxHeight of the Listbox will change.
The main issue people seem to have with the vertical scrollbar not appearing is because they use a stackpanel. I went through my complete visual tree and my listbox is not in a stackpanel anywhere.
Here is the XAML that I use:
<Grid>
<Grid.Resources>
<local:ReportToListItem x:Key="reportToListItem" />
</Grid.Resources>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="3" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<ListBox Background="PaleGoldenrod" x:Name="Controller_Domain_Reports_OpenReports">
<ListBox.ItemTemplate>
<DataTemplate>
<ContentControl cal:View.Model="{Binding Converter={StaticResource reportToListItem}}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Border Grid.Row="1" Background="Black" Height="3" HorizontalAlignment="Stretch" />
<ListBox Background="Magenta" Grid.Row="2" x:Name="Controller_Domain_Reports_ClosedReports">
<ListBox.ItemTemplate>
<DataTemplate>
<ContentControl cal:View.Model="{Binding Converter={StaticResource reportToListItem}}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
Neither listbox gets a scrollbar if it extends beyond the height of the window for me. What am I overlooking?
Just putting this up to close this off properly:
Do'h.. The shellview had a nice copy pasted list of rowdefinitions all set to auto. Changed the one that contains this view to * and now it works as expected.
I have a problem with the selection of items in a Listbox, when the Listbox is in a Tabcontrol.
I can't select any item in the Listbox.
I am filling the Listbox dynamically via code-behind, also I am using drag and drop on it, though, Drag and drop is working with the tabcontrol.
Here is my XAML code:
<Window x:Class="SPInstallApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:toolkit="clr-namespace:Microsoft.Windows.Controls;assembly=WPFToolkit.Extended"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="SharePoint 2010 - wspSync" Height="450" Width="700" AllowDrop="True" Icon="/SPInstallApp;component/Images/favicon.ico">
<Window.Resources>
<DataTemplate x:Key="CustomListBoxTemplate">
<StackPanel>
<Grid Margin="4">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="48 "/>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Image Source="{Binding Path=ImageSource}" Grid.Column="0" Grid.RowSpan="3" Margin="0,0,5,0" />
<TextBlock
Padding="0,5,0,0"
Text="{Binding Path=Title}"
Grid.Column="1"
Grid.Row="0"
FontWeight="Bold"/>
<TextBlock
Padding="0,0,0,5"
Text="{Binding Path=Description}"
Grid.Column="1"
Grid.Row="1"
FontStyle="Italic" />
<TextBlock
Padding="0,0,0,5"
Text="{Binding Path=Status}"
Grid.Column="1"
Grid.Row="2"
FontStyle="Italic" Foreground="#FFDE2B2B" />
</Grid>
</StackPanel>
</DataTemplate>
</Window.Resources>
<toolkit:BusyIndicator IsBusy="True" BusyContent="Bitte warten..." Name="busyIndicator">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="50"/>
</Grid.RowDefinitions>
<Label Content="Websitecollection wählen:" Grid.Row="0" Grid.Column="0" Margin="5,0,0,0" />
<ComboBox Grid.Row="1" Grid.Column="0" Height="20" Margin="10,0,10,10" Name="cbWebsitecollection" SelectionChanged="CbWebsitecollectionSelectionChanged" />
<TabControl Grid.Row="2" Grid.Column="0" Name="tc" SelectionChanged="TcSelectionChanged" Margin="10,0,10,0">
<TabItem Header="Installieren">
<ListBox AllowDrop="True" Background="#CCC" Drop="ListBoxDrop" Name="lbDropbox" IsSynchronizedWithCurrentItem="True" ItemTemplate="{StaticResource CustomListBoxTemplate}" KeyUp="LbDropboxKeyUp" />
</TabItem>
<TabItem Header="Websitecollection">
<CheckBox Content="test" />
</TabItem>
</TabControl>
<Label Grid.Row="2" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Center" FontWeight="Bold" Content="drag 'n' drop" Margin="10" Drop="ListBoxDrop" Name="lbDescription" />
<Button Grid.Row="3" Grid.Column="0" Name="cmdSync" Content="Synchronisieren" Margin="10" Width="100" HorizontalAlignment="Right" Click="CmdSyncClick" />
<Image Grid.Row="3" HorizontalAlignment="Left" Name="Logo" Source="/SPInstallApp;component/Images/logo.gif" Margin="10" MouseUp="LogoMouseUp" MouseEnter="LogoMouseEnter" MouseLeave="LogoMouseLeave" />
</Grid>
</toolkit:BusyIndicator></Window>
If i remove the Tabcontrol, everything is working.
I hope someone can help me or know what the problem is.
greets
I have found the problem.
The problem is how Microsoft designed the MessageHandles.
If a child of an item throws a message (for example selectionChanged) and the message is not handles, the message goes to the parent Item.
So, in my case, if I click on an item in the ListBox, the (unhandled) message "selectionChanged" was sent to the TabControl, this was the problem. Because i have custom code in the TabControl.selectionChanged it always ran my code, instead of selecting the item in the ListBox.
The workaround is, to put this code in the selectionChanged eventhandler of the ListBox:
private void ListBox_selectionChanged(object sender, DragEventArgs e)
{
e.handled = true;
}
This avoids the transfer of the message from the child messagehandler to the parent messagehandler.
I hope u can undersand my explanation.