ItemControl custom style first item - c#

I have an "ItemsControl" with 4 buttons, and when applying a margin, the first button does not look as I would like. Is it possible to modify the margin of the first button? Or, is it possible to access each button and apply different properties to it? Thank you
<ItemsControl ItemsSource="{Binding PercentageList}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Columns="{Binding PercentageList.Count}" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Margin="5,0,0,0"
Content="{Binding Name}"
CommandParameter="{Binding}"
Style="{StaticResource ButtonStyle}"
Command="{Binding DataContext.SelectedPercentageCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
FINAL SOLUTION
<ItemsControl ItemsSource="{Binding PercentageList}"
AlternationCount="{Binding PercentageList.Count}">
<ItemsControl.ItemContainerStyle>
<Style>
<Setter Property="FrameworkElement.Margin"
Value="5,5,0,5" />
</Style>
</ItemsControl.ItemContainerStyle>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Columns="{Binding PercentageList.Count}" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Content="{Binding Name}"
CommandParameter="{Binding}"
Style="{StaticResource ButtonStyle}"
Command="{Binding DataContext.SelectedPercentageCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}" />
<DataTemplate.Triggers>
<Trigger Property="ItemsControl.AlternationIndex"
Value="0">
<Setter Property="Margin"
Value="0,5" />
</Trigger>
</DataTemplate.Triggers>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>

You could use a Trigger to address this.
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource PreviousData}}" Value="{x:Null}">
<Setter TargetName="myTargetElement" Property="SomeProperty" Value="SomeValue"/>
</DataTrigger>
</DataTemplate.Triggers>
This approach will let you customise properties in your DataTemplate for the first item.
If you want to appy unique styles to each button, it sounds like you might need to capture more information in your button item viewmodels.
If you just want the spacing to be even around everything, I would normally use a half margin in all directions around my items, and use the complement around the ItemsControl, which gets rid of these special snowflake cases.

You can have a simpler approach, just change how you apply margin like this:
<Button Margin="2,0,0,2"
Content="{Binding Name}"
CommandParameter="{Binding}"
Style="{StaticResource ButtonStyle}"
Command="{Binding DataContext.SelectedPercentageCommand,
RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type UserControl}}}" />

Related

How to force WPF textboxes contents to be displayed above other controls similar to excel cells

I have an ItemsControl that contains a textbox for each binding item and I want to allow overlaying text box content if its content is wider than the textbox width similar to excel cells overlaying behavior.
Is there a way to do this?
<ItemsControl ItemsSource="{Binding Path=MyCollection}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" Width="100"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBox Text="{Binding}" TextWrapping="WrapWithOverflow"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
You can use tooltip for that. You just need to bind the source with itself.
<ListView ItemsSource="{Binding Path=MyStringCollection}">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" Width="100"/>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemTemplate>
<DataTemplate>
<TextBox Text="{Binding}" TextWrapping="WrapWithOverflow" ToolTip="{Binding RelativeSource={RelativeSource Self}, Path=Text}"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
For further information:
DrawToolTip Event
Set ToolTipSize
To replicate a similar behavior, you can make use of a Popup.
To implement a similar behavior, you first must disable content wrapping of your TextBox.
Then replace the current TextBox with a TextBlock, which is used to display the text.
The Popup, which actually contains the editable TextBox, will then overlay this TextBlock at the exact position, thus hiding the TextBlock to make it appear to stretch and overlay the adjacent items.
A MultiTrigger will close the Popup as soon as the focus moved outside the ListBoxItem.
To improve performance you should use the VirtualizingStackPanel as items host.
<ListView ItemsSource="{Binding MyStringCollection}"
HorizontalAlignment="Left"
Width="800">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<Border BorderThickness="1"
BorderBrush="Gray">
<TextBlock Text="{Binding}" />
</Border>
<Popup x:Name="EditableTextSiteHost"
PlacementTarget="{Binding ElementName=TextSite}"
Placement="Relative"
Height="{Binding ElementName=TextSite, Path=ActualHeight}"
AllowsTransparency="True"
FocusManager.FocusedElement="{Binding ElementName=EditableTextSite}">
<TextBox x:Name="EditableTextSite"
Text="{Binding TextData}" />
</Popup>
</Grid>
<DataTemplate.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding RelativeSource={RelativeSource AncestorType=ListBoxItem}, Path=IsSelected}"
Value="True" />
<Condition Binding="{Binding RelativeSource={RelativeSource AncestorType=ListBoxItem}, Path=IsKeyboardFocusWithin}"
Value="True" />
</MultiDataTrigger.Conditions>
<Setter TargetName="EditableTextSiteHost"
Property="IsOpen"
Value="True" />
</MultiDataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ListView.ItemTemplate>
<ListView.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<!-- Make items overlap -->
<Setter Property="Margin"
Value="-2,0,0,0" />
<Setter Property="Padding"
Value="0" />
<Setter Property="Width"
Value="50" />
<Style.Triggers>
<!-- Apply zero Margin on the first item -->
<DataTrigger Binding="{Binding RelativeSource={RelativeSource PreviousData}}"
Value="{x:Null}">
<Setter Property="Margin"
Value="0,0,0,0" />
</DataTrigger>
</Style.Triggers>
</Style>
</ListView.ItemContainerStyle>
</ListView>
To-do
This is just a raw example, a proof of concept. You would have to improve the behavior. For example, you would want to close the Popup when the user scrolls or moves the Window. Otherwise, since Popup itself is a Window, the Popup would not move to follow the placement target. You could move the related logic to an attached behavior.
You likely also want to improve the selection behavior. Currently the selection highlight border does not (virtually) extend to surround the Popup. You have to mimic this by applying a Border on the TextBox that will replicate the ListBoxItem highlight border.
I managed to produce the excel cells overlay behavior by using a Grid with dynamic column count using this helper dependency properties https://rachel53461.wordpress.com/2011/09/17/wpf-grids-rowcolumn-count-properties/ as a container template of ItemsControl and binding the column index of each textbox to the ordered item index and binding Grid.ZIndex to the reversed index to be displayed above the adjacent text boxes.
<ItemsControl ItemsSource="{Binding MyCollection}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Grid HorizontalAlignment="Left" helpers:GridHelpers.ColumnCount="{Binding MyCollection.Count}"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style>
<Setter Property="Grid.Column" Value="{Binding ItemIndex}"/>
<Setter Property="Grid.ZIndex" Value="{Binding ReversedIndex}" />
<Setter Property="Grid.ColumnSpan" Value="{Binding MaxMergedCells}" />
</Style>
</ItemsControl.ItemContainerStyle>
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Left">
<TextBox MinWidth="30" Text="{Binding }"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>

how to show only selected item from treeview in wpf

I am working with a Wpf/XAML based application which has DataGrid with one of the DataGridColumn containing the TreeView control to let user select the item required.
<DataGrid.Columns>
<DataGridTextColumn Header="SerialNumber" Width="*" Binding="{Binding SerialNumber}" />
<DataGridTemplateColumn Header="Field" Width="*">
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<uControls:FieldTreeViewControl />
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding CurrentField.FieldName,Mode=TwoWay}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
Field column in above code is the one which displays treeviewcontrol in the DataGrid cell by referencing the FieldTreeViewControl and it works perfectly. The xaml code of FieldTreeViewControl is :
<UserControl>
.......
<Grid>
<TreeView x:Name="MyUITreeView" ItemsSource="{Binding Fields}">
<TreeView.Resources>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="IsExpanded" Value="{Binding IsNodeExpanded, Mode=TwoWay}" />
<Setter Property="IsSelected" Value="{Binding IsNodeSelected, Mode=TwoWay}" />
</Style>
<DataTemplate x:Key="NormalTemplate">
<StackPanel Orientation="Horizontal">
<!--<TextBlock Text="-" Margin="3"/>-->
<TextBlock Text="{Binding FieldName}" Margin="3"/>
<StackPanel.ContextMenu>
<ContextMenu Name="myChildMenu" DataContext="{Binding PlacementTarget,RelativeSource={RelativeSource Self}}">
<MenuItem Header="Add Field" Command="{Binding DataContext.AddFieldCommand}" CommandParameter="{Binding}">
</MenuItem>
</ContextMenu>
</StackPanel.ContextMenu>
</StackPanel>
</DataTemplate>
<!--<DataTemplate x:Key="EditTemplate">
<TextBox Text="{Binding FieldName}"/>
</DataTemplate>-->
</TreeView.Resources>
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Children}">
<ContentPresenter Content="{Binding}">
<ContentPresenter.Style>
<Style TargetType="{x:Type ContentPresenter}">
<Setter Property="ContentTemplate" Value="{StaticResource NormalTemplate}"/>
<Style.Triggers>
<DataTrigger
Binding="{Binding IsNodeSelected,
RelativeSource={RelativeSource
FindAncestor,
AncestorType={x:Type TreeViewItem}}}"
Value="True">
</DataTrigger>
</Style.Triggers>
</Style>
</ContentPresenter.Style>
</ContentPresenter>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
</Grid>
Now when user completes selecting an item from treeview I want to collapse treeview to show only that selected item. Later when user wants to change his selection , then the treeview should be available again by clicking on that column/cell. Is that possible to do this in wpf/XAML ? I tried to follow the link but not able to implement it for my scenario.

image binding to the drodown values in wpf

In my xaml form i have a dropdown button the dropdown values will bind from database and my requirement is i want to add one image for each dropdown value in the dropdown box, how can get this.....
<ctrl:DropDownButton Grid.Column="1"
Height="25"
Text="Add Question"
Width="125"
Margin="5,0,10,0">
<ctrl:DropDownButton.DropDownContextMenu>
<ContextMenu ItemsSource="{Binding Source={StaticResource QuestionTypes}}">
<ContextMenu.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Background="WhiteSmoke"/>
</ItemsPanelTemplate>
</ContextMenu.ItemsPanel>
<ContextMenu.ItemContainerStyle>
<Style TargetType="MenuItem">
<Setter Property="Command" Value="{Binding DataContext.AddQuestionCommand,
RelativeSource={RelativeSource AncestorType=UserControl}}" />
<Setter Property="CommandParameter" Value="{Binding}" />
</Style>
</ContextMenu.ItemContainerStyle>
<ContextMenu.ItemTemplate>
<DataTemplate>
<Grid Margin="-20,0,-50,0">
<TextBlock Grid.Column="1" Text="{Binding Converter={StaticResource EnumDescriptionConverter}}"/>
</Grid>
</DataTemplate>
</ContextMenu.ItemTemplate>
</ContextMenu>
</ctrl:DropDownButton.DropDownContextMenu>
</ctrl:DropDownButton>
*I wrote this outside of VisualStudio so please check the syntax
you should add an Image element to your DataTempalte and using a converter for the enum value resolve the path to the image you would like to present.
<ContextMenu.ItemTemplate>
<DataTemplate>
<Grid Margin="-20,0,-50,0">
<Grid>
<Grid.ColumnDefenitions>
<ColumnDefenition />
<ColumnDefenition />
</Grid.ColumnDefenitions>
<Image Source="{Binding Path=., Converter={StaticResource EnumImageConverter}}" />
<TextBlock Grid.Column="1" Text="{Binding Path=., Converter={StaticResource EnumDescriptionConverter}}"/>
</Grid>
</DataTemplate>
</ContextMenu.ItemTemplate>

(WPF) How to change button image background in listBox with buttons in each line ?

i have listbox, and the data template is button :
<ListBox x:Name="lbname" ItemsSource="{Binding myCollection}">
<ListBox.ItemTemplate>
<DataTemplate>
<Button x:Name="btnname" Content="{Binding name}" Click="btnname_Click">
<Button.Background>
<ImageBrush ImageSource="/myApplication;component/images/buttons/normal.png"/>
</Button.Background>
</Button>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
i have two image backgroud for this listBox image (normal.png for normal mode, click.png for selected item in listBox)
The listBox view items in list of buttons, the button image background is normally normal.png
my question is how to change the button image background to click.png for selected one and the old selected button retrieve to normal.png
How to change image background for selected item in listBox with buttons in each line ?
hope this clear, please i spend about one day about this issue
can any one help
Thanks
I haven't tested it, but you need some code that looks like this:
<ListBox x:Name="lbname" ItemsSource="{Binding myCollection}">
<ListBox.ItemTemplate>
<DataTemplate>
<Button x:Name="btnname" Click="btnname_Click">
<Grid>
<Image>
<Image.Style>
<Style>
<Setter Property="Image.Source"
Value="/myApplication;component/images/buttons/normal.png" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsSelected,
RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListBoxItem}}}"
Value="True">
<Setter Property="Image.Source"
Value="/myApplication;component/images/buttons/click.png" />
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
<TextBlock Text="{Binding name}" HorizontalAlignment="Center"
VerticalAlignment="Center" />
</Grid>
</Button>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
The idea is to bind directly to the IsSelected property of the ListBoxItem object. This is done using a RelativeSource binding. However, I'm guessing that this code doesn't do what you want... I suggest that you might want to use a ToggleButton instead... something like this:
<ListBox x:Name="lbname" ItemsSource="{Binding myCollection}">
<ListBox.ItemTemplate>
<DataTemplate>
<ToggleButton x:Name="btnname" Click="btnname_Click" IsChecked="{Binding
IsSelected, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type
ListBoxItem}}}">
<Grid>
<Image>
<Image.Style>
<Style>
<Setter Property="Image.Source"
Value="/myApplication;component/images/buttons/normal.png" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsSelected,
RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListBoxItem}}}"
Value="True">
<Setter Property="Image.Source"
Value="/myApplication;component/images/buttons/click.png" />
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
<TextBlock Text="{Binding name}" HorizontalAlignment="Center"
VerticalAlignment="Center" />
</Grid>
</ToggleButton>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
if you are using MVVM then make a property in viewModel and bind this to ImageBrush as ImageSource,
when you are selecting value in ListView then get selected record and change image path of this property.
Try using Togglebutton instead of button.Use a trigger to check when the IsChecked property of the toggleButton changes. And based on that change your image.

How to change the data template in runtime?

In my application, I have a CheckBox in it, I would like when it's checked, show one DataTemplate and when it's unchecked, show another one.
Here is the snippet with the two templates
<DataGrid x:Name="dataGrid" LoadingRow="dataGrid_LoadingRow_1" ItemsSource="{Binding Item3}"
<DataGrid.RowHeaderTemplate>
<DataTemplate>
<TextBlock Text="{Binding StudentId}"/>
</DataTemplate>
<DataTemplate>
<TextBlock Text="{Binding FullName}"/>
</DataTemplate>
</DataGrid.RowHeaderTemplate>
</DataGrid>
I'm not sure how to implement it, but I supposed that I need the interface INotifyPropertyChanged in my User control to fire or just determine when has changed.
You can do it only via triggers. If the above thing is your requirement. You can do it simply via triggers. I tried and it worked for me.
<Window.Resources>
<ControlTemplate x:Key="MyRowHeaderTemplate">
<TextBlock x:Name="RowHeaderTxt"
Text="{Binding StudentId, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"/>
<ControlTemplate.Triggers>
<DataTrigger Binding="{Binding Path=IsChecked, ElementName=MyCheckBox}"
Value="True">
<Setter TargetName="RowHeaderTxt" Property="Text"
Value="{Binding FullName, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"/>
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Window.Resources>
<StackPanel>
<CheckBox x:Name="MyCheckBox"/>
<DataGrid ItemsSource="{Binding Item3}" AutoGenerateColumns="True">
<DataGrid.RowHeaderTemplate>
<DataTemplate>
<ContentControl Template="{StaticResource MyRowHeaderTemplate}"/>
</DataTemplate>
</DataGrid.RowHeaderTemplate>
</DataGrid>
</StackPanel>
Try this.

Categories