I have a grid control in which the first column and cell shows a trash icon. But the trash icon should be visible only when its row is selected.
I have a style:
<Style TargetType="{x:Type Image}" x:Key="ImageStatusStyle">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=RowData.IsFocused, UpdateSourceTrigger=PropertyChanged}" Value="true">
<Setter Property="Visibility" Value="Visible" />
</DataTrigger>
</Style.Triggers>
</Style>
and a data template:
<DataTemplate x:Key="TrashIconCellTemplate" >
<Button Height="15" Width="15" Command="{Binding ElementName=GroupCodeListView,Path=DataContext.MarkRowForDeletionCommand}">
<Button.Template>
<ControlTemplate>
<Image Source="../Resources/crane.png" Style="{StaticResource ImageStatusStyle}" Visibility="Hidden"/>
</ControlTemplate>
</Button.Template>
</Button>
</DataTemplate>
A grid control:
<dxg:GridControl ItemsSource="{Binding GroupCodes, Mode=TwoWay}"
SelectedItems="{Binding
SelectedGroupCodes,Mode=TwoWay}"
SelectionMode="Row"
x:Name="Grid"
ClipboardCopyMode="ExcludeHeader"
Margin="0,0,0,0"
Height="360"
MinWidth="400"
CustomRowFilter="FilterDeleted">
and the grid cell column referencing the above:
<dxg:GridColumn FieldName="IconUnbound"
UnboundType="Object"
CellTemplate="{StaticResource TrashIconCellTemplate}"
CellStyle="{StaticResource GroupCodeColorStyle}" />
The trash image in the first cell should appear when the row is selected only.
The image remains in the default state of hidden. The data trigger is not working. What am I doing wrong here?
If you want to check whether the row is selected then you need to use RowData.IsSelected property. Also, you must set the Visibility in your Style section, not in the Image itself.
Here is example:
0. Style:
<Style TargetType="{x:Type Image}" x:Key="ImageStatusStyle">
<Setter Property="Visibility" Value="Hidden" />
<Style.Triggers>
<DataTrigger Binding="{Binding Path=RowData.IsSelected, UpdateSourceTrigger=PropertyChanged}" Value="true">
<Setter Property="Visibility" Value="Visible" />
</DataTrigger>
</Style.Triggers>
</Style>
1. Image:
<Image Source="../Resources/crane.png" Style="{StaticResource ImageStatusStyle}" />
Related
I have the following style:
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock x:Name="Text" Text="{Binding Name}" Margin="0, 5" FontSize="16"/>
</DataTemplate>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
I want to change the foreground color of "Text" if the "ListBoxItem" is selected. I know from here: Change WPF DataTemplate for ListBox item if selected how to change the DataTemplate. but since I just want to change colors, this solution makes unnecessary duplication in codd - It would be a greater problem if my DataTemplate would be very complex and long.
How do I achieve change of a single property of an object inside the DataTemplate?
If you actually want the same item template always (whether the item is selected or not), but you want a different foreground color when the item is selected, that's easy. Don't set the ContentTemplate in a trigger, because ContentTemplate doesn't change. Just set the foreground color with a trigger. If you don't mess with the foreground color in the template, it will inherit whatever the ListBoxItem has for that property.
<Style TargetType="ListBoxItem">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock
x:Name="Text"
Text="{Binding Name}"
Margin="0, 5"
FontSize="16"
/>
</DataTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Foreground" Value="Red" />
</Trigger>
</Style.Triggers>
</Style>
A more elaborate version of the same style:
<Style TargetType="ListBoxItem">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Ellipse
Height="12"
Width="12"
VerticalAlignment="Center"
x:Name="Ellipse"
Fill="Yellow"
Stroke="DeepSkyBlue"
StrokeThickness="1"
/>
<TextBlock
x:Name="Text"
Text="{Binding Name}"
Margin="5,5,0,5"
FontSize="16"
/>
</StackPanel>
<DataTemplate.Triggers>
<DataTrigger
Binding="{Binding IsSelected, RelativeSource={RelativeSource AncestorType=ListBoxItem}}"
Value="True"
>
<Setter
TargetName="Ellipse"
Property="Stroke"
Value="Orange"
/>
<Setter
TargetName="Ellipse"
Property="StrokeThickness"
Value="3"
/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Foreground" Value="Red" />
</Trigger>
</Style.Triggers>
</Style>
I have the following xaml:
<DockPanel>
<DockPanel>
<CheckBox IsChecked="{Binding Path=Test}" />
<CheckBox IsChecked="{Binding Path=Test}" />
</DockPanel>
<DockPanel DockPanel.Dock="Left" Width="10" Background="Blue">
<DockPanel.Style>
<Style>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=Test}" Value="True">
<Setter Property="DockPanel.Background" Value="Yellow" />
</DataTrigger>
</Style.Triggers>
</Style>
</DockPanel.Style>
</DockPanel>
</DockPanel>
Now - the 2 checkboxes link properly - checking one will check the other - but the datatrigger is not firing at all.
What am I doing wrong?
The issue here is Property Value Precedence.
You are currently setting the Background to blue directly on the DockPanel. This explicit property will override any value set by the trigger.
Instead, you must set the original "Background" as a setter in the style.
<DockPanel DockPanel.Dock="Left" Width="10">
<DockPanel.Style>
<Style>
<Setter Property="DockPanel.Background" Value="Blue" />
<Style.Triggers>
<DataTrigger Binding="{Binding Path=Test}" Value="True">
<Setter Property="DockPanel.Background" Value="Yellow" />
</DataTrigger>
</Style.Triggers>
</Style>
</DockPanel.Style>
</DockPanel></DockPanel>
I want to have dynamic editable listbox in wpf application. I am using textbox inside listbox, and I am binding Observable collection to that listbox. Now, I want to make textbox editable on mouse click. So, user can make change to textbox and save new textbox text.
<ListBox Name="ListTwo" ItemsSource="{Binding CollectionUrl, Mode=TwoWay}" >
<ListBox.ItemTemplate>
<DataTemplate>
<TextBox Name="TextBoxList" Text="{Binding Path=urlString}" IsEnabled="False" >
</TextBox>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
You should use IsReadOnly property. In the trigger you should check IsFocused property.
In the following example, I changed foreground color to indicate which TextBox is in the edit mode.
Example:
<ListBox Name="ListTwo" ItemsSource="{Binding CollectionUrl, Mode=TwoWay}" >
<ListBox.ItemTemplate>
<DataTemplate>
<TextBox Name="TextBoxList" Text="{Binding Path=urlString}" MinWidth="100">
<TextBox.Style>
<Style TargetType="TextBox">
<Style.Triggers>
<Trigger Property="IsFocused" Value="True">
<Setter Property="Foreground" Value="Green"/>
<Setter Property="IsReadOnly" Value="False" />
</Trigger>
<Trigger Property="IsFocused" Value="False">
<Setter Property="Foreground" Value="Red"/>
<Setter Property="IsReadOnly" Value="True" />
</Trigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
If you want to allow users save changes after edit value in the TextBox, you can add button and show in the actual editing row:
<ListBox Name="ListTwo" ItemsSource="{Binding CollectionUrl, Mode=TwoWay}" >
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="50" />
</Grid.ColumnDefinitions>
<TextBox Name="TextBoxList" Text="{Binding Path=urlString}" MinWidth="100">
<TextBox.Style>
<Style TargetType="TextBox">
<Style.Triggers>
<Trigger Property="IsFocused" Value="True">
<Setter Property="Foreground" Value="Green"/>
<Setter Property="IsReadOnly" Value="False" />
</Trigger>
<Trigger Property="IsFocused" Value="False">
<Setter Property="Foreground" Value="Red"/>
<Setter Property="IsReadOnly" Value="True" />
</Trigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
<Button Content="Save" Grid.Column="1" Command="{Binding SaveChanges}">
<Button.Style>
<Style TargetType="Button">
<Setter Property="Visibility" Value="Collapsed" />
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=TextBoxList, Path=IsFocused}" Value="True">
<Setter Property="Visibility" Value="Visible" />
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
My approach to accessing the text box (which was proving a nightmare) was to use your save button approach and in the Button's Button_Click function I used sender to retrieve the Button's parent, cast to (in your case) Grid. Then you can use that to access the Grid's Children with .Children[0] being your TextBox.
Bit of a Kluge because your code has to 'know' the type of the parent and the index of the child TextBox but these will not change. If necessary the purists can iterate through the Children to identify the required child explicitly.
Hope this helps someone.
i hope you can help me. I got following Code in the Resources:
<UserControl.Resources>
<BitmapImage x:Key="img_src_lock" UriSource="/EEBase;component/Images/Lock_24x32.png" />
<BitmapImage x:Key="img_src_unlock" UriSource="/EEBase;component/Images/Unlock_24x32.png" />
<Style TargetType="{x:Type ToggleButton}">
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsChecked}" Value="True">
<Setter Property="Content">
<Setter.Value>
<Image Source="{StaticResource img_src_lock}" />
</Setter.Value>
</Setter>
</DataTrigger>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsChecked}" Value="False">
<Setter Property="Content">
<Setter.Value>
<Image Source="{StaticResource img_src_unlock}" />
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
<!-- TypeComboTemplateCollapsed -->
<DataTemplate x:Key="TypeComboTemplateCollapsed">
<TextBlock
Text="{Binding Path=Text, Mode=OneWay}"
VerticalAlignment="Center"
HorizontalAlignment="Left"
Margin="5,0,0,5"
/>
</DataTemplate>
<!-- TypeComboTemplateExpanded -->
<DataTemplate x:Key="TypeComboTemplateExpanded">
<TextBlock
Text="{Binding Path=Text, Mode=OneWay}"
VerticalAlignment="Center"
Margin="5,0,0,5"
/>
</DataTemplate>
<!-- EditCircleTemplate -->
<DataTemplate x:Key="EditCircleTemplate">
<!-- some content here, no ToggleButton -->
</DataTemplate>
<!-- EditRectangleTemplate -->
<DataTemplate x:Key="EditRectangleTemplate">
<!-- some other content here, including the ToggleButtons -->
<ToggleButton
IsChecked="{Binding Path=BaseLocked, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}"
Margin="5"
/>
<ToggleButton
IsChecked="{Binding Path=HeightLocked, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}"
Margin="5"
/>
</DataTemplate>
</UserControl.Resources>
To me that looks all correct.
Now, the problem is:
When i do the following, an exceptions occurs:
Specified element is already the logical child of another element. Disconnect it first.
1. load the control, selected type is CIRC
2. change the dropdown to select RECT (template triggers and togglebuttons are shown correctly)
3. change the dropdown back to CIRC
--> now the Exception occurs.
4. if i ignore the exception, the template "EditCircleTemplate" does not get loaded, and the normal ToString of the model object gets displayed.
Additional info:
originally there are 4 different types in the WPF, two of them with ToggleButtons (that's why i use templates). I cut them out, they dont differ really. But what i found out using all 4 templates is that the error does not occur when switching to a new Template, but when unloading a template with the toggle buttons. Which is kinda strange.
Also if i remove the DataTriggers for the ToggleButtons everything works like a charm.
The Exception comes from the XAML-Interpreter, so the Stacktrace is not useful at all.
Can anyone give me a hint what i am doing wrong?
Edit:
oops, i guess i forgot the content code:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="160"/>
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition />
</Grid.RowDefinitions>
<ComboBox
Margin="5"
Grid.Row="0"
Grid.Column="0"
ItemsSource="{Binding Path=PossibleTypes, Mode=OneTime}"
SelectedItem="{Binding Path=SelectedType, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<ContentControl x:Name="content" Content="{Binding}" ContentTemplate="{StaticResource TypeComboTemplateExpanded}"/>
</StackPanel>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=ComboBoxItem}}" Value="{x:Null}">
<Setter TargetName="content" Property="ContentTemplate" Value="{StaticResource TypeComboTemplateCollapsed}"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<ContentControl
Grid.Column="0"
Grid.Row="1"
Grid.ColumnSpan="2"
Content="{Binding Mode=OneWay}">
<ContentControl.ContentTemplate>
<DataTemplate >
<ContentControl
Name="inputContent"
Content="{Binding Mode=OneWay}"
ContentTemplate="{x:Null}"
/>
<DataTemplate.Triggers>
<DataTrigger
Binding="{Binding Path=SelectedType.Type, Mode=OneWay}"
Value="CIRC">
<Setter
TargetName="inputContent"
Property="ContentTemplate"
Value="{StaticResource EditCircleTemplate}"
/>
</DataTrigger>
<DataTrigger
Binding="{Binding Path=SelectedType.Type, Mode=OneWay}"
Value="RECT">
<Setter
TargetName="inputContent"
Property="ContentTemplate"
Value="{StaticResource EditRectangleTemplate}"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ContentControl.ContentTemplate>
</ContentControl>
</Grid>
Edit2/Solution:
I just found a workaround - it just does not satisfy me:
Instead of putting the style in the UserControl.Resources, which for me would be the more clean and intuitive solution, i have to set the style with the triggers on each ToggleButton separately.
So removing the and adding following code to each ToggleButton did the trick:
<ToggleButton.Style>
<Style TargetType="{x:Type ToggleButton}">
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsChecked}" Value="True" >
<Setter Property="Content">
<Setter.Value>
<Image Source="{StaticResource img_src_lock}" />
</Setter.Value>
</Setter>
</DataTrigger>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsChecked}" Value="False">
<Setter Property="Content">
<Setter.Value>
<Image Source="{StaticResource img_src_unlock}" />
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</ToggleButton.Style>
The big question still persists: WHY?
The problem is that if you create an Image in a style there is only one instance, so as soon as multiple controls use the style there is going to be a fight over this one instance which can only be owned by one control.
The easiest solution to this is placing the Style in a resource and setting x:Shared to false, that way a copy of the style is used whereever referenced.
Why do you need to create BitmapImages and set them as Source to your Content Images in Triggers? Why arent you using the URI source to Images directly?
<Style TargetType="{x:Type ToggleButton}">
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsChecked}" Value="True">
<Setter Property="Content">
<Setter.Value>
<Image Source="/EEBase;component/Images/Lock_24x32.png" />
</Setter.Value>
</Setter>
</DataTrigger>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsChecked}" Value="False">
<Setter Property="Content">
<Setter.Value>
<Image Source="/EEBase;component/Images/Unlock_24x32.png" />
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
Let me know if this helps.
I have a view, that when loaded contains a toolbar at the top, and two regions underneath.
I am currently using a grid, so:
row 0 contains the toolbar
row 1 contains region1 and
row 2 contains region2.
The toolbar has a toggle button, which when clicked, completely hides region1, and shows region 2, and visa-versa.
What is the best way to achieve this?
I have tried binding the 2 rows heights to get altered on the toggle, but the space is not filled correctly. VerticalAlignment="Stretch" and HorizontalAlignment="Stretch" are both used.
I have also tried enabling and disabling the itemcontrol hosting the region, but that doesn't seem to work at all.
Any pointers as to what I have done are much appreciated! :)
Not sure if I fully understand what you want. Something like this?
<DockPanel>
<ToggleButton Name="viewToggle" DockPanel.Dock="Top">Toggle Region</ToggleButton>
<Grid>
<ContentControl>
<TextBlock>I'm region 1</TextBlock>
<ContentControl.Style>
<Style>
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=viewToggle, Path=IsChecked}" Value="False">
<Setter Property="ContentControl.Visibility" Value="Visible"></Setter>
</DataTrigger>
<DataTrigger Binding="{Binding ElementName=viewToggle, Path=IsChecked}" Value="True">
<Setter Property="ContentControl.Visibility" Value="Hidden"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
<ContentControl>
<TextBlock>I'm region 2</TextBlock>
<ContentControl.Style>
<Style>
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=viewToggle, Path=IsChecked}" Value="True">
<Setter Property="ContentControl.Visibility" Value="Visible"></Setter>
</DataTrigger>
<DataTrigger Binding="{Binding ElementName=viewToggle, Path=IsChecked}" Value="False">
<Setter Property="ContentControl.Visibility" Value="Hidden"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
</Grid>
</DockPanel>
I used for this one row that contains region1 and region2 too. region2's Visibility set to Collapsed by default, and when an event occured (a checkbox for me, databound to a bool value) i flipped the Visibility of the regions. My 'regions' contained two different layout, and i don't experienced any issue.
A quick sample code without code-behind:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.Resources>
<Style x:Key="showOnToggled" TargetType="GroupBox" BasedOn="{StaticResource {x:Type GroupBox}}" >
<Setter Property="Visibility" Value="Visible" />
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=toggleButton, Path=IsChecked}" Value="True" >
<Setter Property="Visibility" Value="Collapsed" />
</DataTrigger>
</Style.Triggers>
</Style>
<Style x:Key="hideOnToggled" TargetType="GroupBox" BasedOn="{StaticResource {x:Type GroupBox}}" >
<Setter Property="Visibility" Value="Collapsed" />
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=toggleButton, Path=IsChecked}" Value="True" >
<Setter Property="Visibility" Value="Visible" />
</DataTrigger>
</Style.Triggers>
</Style>
</Grid.Resources>
<ToggleButton Content="Switch Region"
Grid.Row="0"
x:Name="toggleButton" />
<GroupBox Header="Region1"
Grid.Row="1"
Style="{StaticResource showOnToggled}" >
<!-- Region1's content -->
</GroupBox>
<GroupBox Header="Region2"
Grid.Row="1"
Style="{StaticResource hideOnToggled}" >
<!-- Region2's content -->
</GroupBox>
</Grid>