I'm building a touch screen application that needs to give the user the ability to quickly copy and paste text in a listview. I've created the menu, but now I am trying to prevent repetitive XAML. I have the following template for the Cell:
<DataTemplate x:Key="copyPaste">
<Button Click="cell_click" Tag="{Binding Tag, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Grid}}}" Foreground="{Binding Foreground, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListViewItem}}}">
<Button.Template>
<ControlTemplate TargetType="{x:Type Button}">
<ContentPresenter />
</ControlTemplate>
</Button.Template>
<TextBlock Text="{Binding Tag, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Border}}}" />
</Button>
</DataTemplate>
I want to implement it similar to this:
<GridViewColumn.CellTemplate>
<DataTemplate>
<Grid Tag="{Binding Serial}" DataTemplate="{DynamicResource copyPaste}"></Grid>
</DataTemplate>
</GridViewColumn.CellTemplate>
I don't necessarily want a "Grid" element, but I need a way to reference the value that is suppose to be entered on that cell.
Grid -> DataTemplate does not exist. Is there another element / tag or another way I should be trying to do this? Am I going about this the wrong way?
I've gotten the following to work in a way that I think is acceptable. I don't know if it was the best way or not.
In the DefaultResources.XAML, I have:
<ControlTemplate x:Key="copyPaste" TargetType="Button">
<TextBlock Text="{Binding Tag, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Button}}}" />
</ControlTemplate>
<Style x:Key="copyPasteStyle" TargetType="Button">
<Setter Property="Foreground" Value="{Binding Foreground, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListViewItem}}}"></Setter>
</Style>
Then in the actual list view, I have
<GridViewColumn.CellTemplate>
<DataTemplate>
<Button Tag="{Binding Serial}" Template="{DynamicResource copyPaste}" Click="cell_click" Style="{DynamicResource copyPasteStyle}" />
</DataTemplate>
</GridViewColumn.CellTemplate>
The ContentPresenter is apparently no longer necessary to remove the button graphic since the "Template" for the button is being set.
Related
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}}}" />
I have a Control template defined for my custom control say ControlA:
<Style TargetType="local:ControlA">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:ControlA">
<Grid>
<FlipView VirtualizingStackPanel.VirtualizationMode="Recycling"
ItemsSource="{Binding Items, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}">
<FlipView.ItemTemplate>
<DataTemplate>
<Grid>
<Canvas
ZIndex="1"
Visibility="Collapsed">
<Border BorderBrush="Black"
BorderThickness="1">
<TextBlock Name="CurrentTimeMarkerTB"/>
</Canvas>
</Grid>
</DataTemplate>
</FlipView.ItemTemplate>
</FlipVIew>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I want to bind the test property of CurrentTimeMarkerTB to some property of ControlA. I tried
Text="{Binding SomeDateTimePropertyOfControlA,
RelativeSource={RelativeSource TemplatedParent},
Converter={StaticResource TimelineFormatter},
ConverterParameter='0:hh:mm tt', TargetNullValue='CurrentTime'}"
But it never triggeres the converter's TimelineFormatter code.
There is no TemplatedParent in a DataTemplate, only in ControlTemplate. You need to retrieve the Parent using FindAncestor:
Text="{Binding SomeDateTimePropertyOfControlA,
RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:ControlA}},
Converter={StaticResource TimelineFormatter},
ConverterParameter='0:hh:mm tt', TargetNullValue='CurrentTime'}"
If you can't use FindAncestor mode of RelativeSource you can use ElementName:
Text="{Binding SomeDateTimePropertyOfControlA,
ElementName=MyControlA,
Converter={StaticResource TimelineFormatter},
ConverterParameter='0:hh:mm tt', TargetNullValue='CurrentTime'}"
And then name your control:
<local:ControlA x:Name="MyControlA"/>
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.
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.
So I have a template for a button with an image and a textblock. The images I have are too large, and I'd like to scale them down.
<Style x:Key="ImageButton" TargetType="Button">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<StackPanel Orientation="Vertical">
<Image Source="{Binding Path=(local:ButtonProperties.Image), RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Button}}}" />
<ContentPresenter Content="{Binding Path=Content, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Button}}}"></ContentPresenter>
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
Is the specific block of code I have. However, when I try to add Height="X" to the template, I get errors. Is there a way to specify the image size within the template itself?