How Can I know if the DataGridCell is currently in edit mode (not IsSelected), I mean, for example a DataGridTextColumn cell is clicked it becomes a TextBox and not a TextBlock, that's what I call IsEditMode.
I wanna set a trigger-setter for this mode.
EDIT:
I tried to set a general style for DataGridCell.IsEditing but it doesn't seem to do anything.
Here is a snippet of my current code:
<Style TargetType="{x:Type tk:DataGridCell}">
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="{x:Null}"/>
</Trigger>
<Trigger Property="IsEditing" Value="True">
<Setter Property="BorderBrush" Value="#FF62B6CC"/>
<Setter Property="Background" Value="#FFF4F4F4"/>
</Trigger>
</Style.Triggers>
<Setter Property="Foreground" Value="Black"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="BorderThickness" Value="0.5"/>
<Setter Property="BorderBrush" Value="{x:Null}"/>
</Style>
Thanks.
Here's how to do it:
<Trigger Property="IsEditing" Value="True">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="DataGridCell">
<TextBox Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Content.Text, Mode=TwoWay, UpdateSourceTrigger=Default}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Trigger>
then style the textbox as you please
If you take a look at DataGridCell.cs file, IsEditing should be good way to find out if cell is in edit mode. But you can't set this property from style, because there is local value assignment in DataGridCell class (which has higher priority from style setter).
So, the answer would be: it should work from trigger, but it will not from the style setter.
Update: Shimmy, it really works. Snoop your application, make sure DataGridCell is using your implicit style. Select DataGridCell in the tree, and check its background property. Every time you go in Edit mode it is updated. But you don't see it, by default, since TextBox doesn't inherit Background property. But that's another story. I think you can tweak CellEditingTemplate to make it working.
The proper way to turn on edit mode is to find the DataGridCell's parent DataGrid and call BeginEdit() on that. If you set it directly, you're sidestepping a lot of DataGrid goo that maintains proper state transitions.
Related
I am using the latest version of WPF Toolkit. I am trying to style an AutoCompleteBox and I can't seem to get the "IsFocused" trigger to work. Basically I want it to behave like my TextBox style so I made one for the AutoCompleteBox. I even tried assigning my TextBox style to the TextBoxStyle property of the AutoCompleteBox and I still never see the IsFocused trigger fire.
I did try playing around in the code behind and noticed that if I override OnGotFocus and OnLostFocus those never get called. But if I wire some event handlers to the GotFocus and LostFocus events, THEN I finally see something happen. If wiring to the events is the only way to see the IsFocused change then that seems like an ugly hack. Is there some work around for this or something I should do different?
My TexBox Style
<Style TargetType="TextBox" x:Key="TextBoxStyle">
<Setter Property="Background" Value="{StaticResource TextBoxBackground}"/>
<Setter Property="Foreground" Value="{StaticResource Foreground}"/>
<Setter Property="CaretBrush" Value="{StaticResource Foreground}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
<Grid Background="{TemplateBinding Background}" SnapsToDevicePixels="true">
<ScrollViewer x:Name="PART_ContentHost" Margin="1"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Background" Value="{StaticResource TextBoxBackgroundSelected}"/>
</Trigger>
<Trigger Property="IsFocused" Value="true">
<Setter Property="Background" Value="{StaticResource TextBoxBackgroundSelected}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
My AutoCompleteBox Style
<Style TargetType="WpfToolkitInput:AutoCompleteBox" x:Key="AutoCompleteBoxStyle">
<Setter Property="Background" Value="{StaticResource TextBoxBackground}"/>
<Setter Property="Foreground" Value="{StaticResource Foreground}"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="TextBoxStyle" Value="{StaticResource TextBoxStyle}"/>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Background" Value="{StaticResource TextBoxBackgroundSelected}"/>
</Trigger>
<Trigger Property="IsFocused" Value="true">
<Setter Property="Background" Value="{StaticResource TextBoxBackgroundSelected}"/>
</Trigger>
</Style.Triggers>
Any ideas?
Thank you for your time!
I was unsuccessful in finding an elegant solution to the problem. I ended up inheriting from AutoCompleteBox and performing my logic with the event handlers.
public class AutoCompleteTextBox : AutoCompleteBox
...
public AutoCompleteTextBox()
{
// Register the event handler for GotFocus.
base.GotFocus += this.AutoCompleteTextBoxGotFocus;
// Register the event handler for LostFocus.
base.LostFocus += this.AutoCompleteTextBoxLostFocus;
}
Nothing fancy here. I just made my own type. The only thing I do is wire up the got and lost focused event handlers in the constructor. I'm not sure why but the IsFocused trigger does not pick up these events. Also, if you try to override these: "OnGotFocus" or "OnLostFocus", they don't work either. So the only way I could find if the AutoCompleteBox is focused is to register directly to the event. If someone comes across this in the future and has a better way, please comment.
I have a ListBox which I need to gray out when it's disabled. Per user request it's not enough to disable it, but it also has to appear differently. shrugs I've looked in several other places and followed the examples, and it seems as if it should work, but it does not. Here are some examples I looked at: Example1, Example2.
Here is my code:
<Style x:Key="ListBoxStyle" TargetType="ListBox">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBox}">
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="BorderBrush" Value="Black"></Setter>
<Setter Property="Foreground" Value="LightGray"></Setter>
<Setter Property="Background" Value="LightGray"></Setter>
<Setter Property="BorderBrush" Value="LightGray"></Setter>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
It seems fairly straightforward. I did the same basic process on ComboBox and TextBox with success. Can anyone help me see where my code is wrong? An example of how to do it correctly would be great. The first example listed above seemed to be exactly what I needed, but the correct answer was "The only way to do this is by overriding the template" which doesn't help me.
I've already tried several simple solutions. It's possible some other style may be affecting this because we're working with a couple different Resource Dictionaries. Does anybody know what may be a good way to track this down?
Edit:
I did a search on the entire solution and the only place ListBox is being used is my portion and the only place it's being styled is the styles I've set. According to MSDN there are no "parts" of a ListBox, so it's not possible I inadvertently styled part of the ListBox in the process of styling for some other control. With no styling, when I disable the ListBox, it is frozen but visible with no text, and has a default background. When I try to apply the Property="Background" Value="LightGray" it seems to be hidden (i.e. nothing is visible). If anybody knows why it may be doing this or how to accomplish my task, I'd appreciate the help.
sa_ddam213's answer didn't work for me so i thought i'd add what i found i had to do. In my case, i had set transparent background, but when i disabled the box it would turn gray. I wanted to be able to control the background of the listbox when the control was disabled and here's what i found to work.
note: For your case, you'd want to change the Transparent color to whatever shade of Gray you want.
note2: This will likely only work if you haven't changed the template for the listbox. (changing the datatemplate is ok).
<ListBox.Style>
<Style TargetType="{x:Type ListBox}">
<Style.Resources>
<SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}" Color="Transparent"/>
</Style.Resources>
</Style>
</ListBox.Style>
Both answers didn't really work for me so I found a solution that overwrites the ControlTemplate which works for me:
<Style TargetType="{x:Type ListBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBox}">
<Grid Width="Auto" Height="Auto">
<Border x:Name="Border"
BorderThickness="1"/>
<ScrollViewer Focusable="false" IsTabStop="False" HorizontalScrollBarVisibility="Disabled">
<StackPanel IsItemsHost="true"/>
</ScrollViewer>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="false">
<Setter TargetName="Border" Property="Border.Background" Value="{StaticResource DisabledBackgroundBrush}"/>
</Trigger>
<Trigger Property="IsGrouping" Value="true">
<Setter Property="ScrollViewer.CanContentScroll" Value="false"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="Background" Value="{StaticResource DefaultBackground}"/>
</Style>
This helped me: https://social.msdn.microsoft.com/Forums/vstudio/en-US/4b033268-864e-488c-b371-80818daf7f71/can-i-override-the-disabled-background-color-for-a-listbox?forum=wpf
I don't think you need to override the ControlTemplate, just adding a Style.Trigger worked fine for me.
Example:
<ListBox>
<ListBox.Style>
<Style TargetType="{x:Type ListBox}">
<Style.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Foreground" Value="LightGray" />
<Setter Property="Background" Value="LightGray" />
</Trigger>
</Style.Triggers>
</Style>
</ListBox.Style>
</ListBox>
I have come accross a very strange behavior with the DataGrid. I have following Trigger on the DataGridRow
<Style TargetType="{x:Type DataGridRow}">
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="{StaticResource SelectionBackgroundBrush}"/>
<Setter Property="Foreground" Value="White"/>
</Trigger>
</Style.Triggers>
</Style>
Initially when the row is selected, I get the behavior from the above trigger. However, after selection, if the DataGrid loses focus (say for example I click some other button on window) the Foreground property loses its value, but the background remains as specified in the trigger. Has anyone ever come accross this behavior, or there is some problem with my code above (or elsewhere in my applicaion for that matter). Any workarounds for the above issue ?
I've used DataGridCell instead of DataGridRow and it works for me
<Style TargetType="{x:Type DataGridCell}">
<Style.Triggers>
<Trigger Property="DataGridCell.IsSelected" Value="True">
<Setter Property="BorderBrush" Value="#CCDAFF" />
<Setter Property="Background" Value="#3399ff"/>
<Setter Property="Foreground" Value="White"/>
</Trigger>
</Style.Triggers>
</Style>
Hope it helps someone!
It almost gets me mad in recent days. I have a textbox and the style in xaml file.
But the style without a control template cannot take effect on textbox. Whereas, a control template works, but control template seems to overwrite the textbox totally, the default behaviors loses of textbox such as editing, inputing or selecting...
Here is content of xaml with the control template:
<Style TargetType="{x:Type TextBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Border Name="tbBorder" Background="White" BorderThickness="0.6" BorderBrush="#B9B9B9">
<ContentPresenter/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsFocused" Value="true">
<Setter Property="BorderBrush" Value="#4D90FE" />
</Trigger>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="BorderBrush" Value="#4D90FE" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
And here is the simple style which does not work at all,
<Style TargetType="{x:Type TextBox}">
<Style.Triggers>
<Trigger Property="IsFocused" Value="true">
<Setter Property="BorderBrush" Value="#4D90FE" />
</Trigger>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="BorderBrush" Value="#4D90FE" />
</Trigger>
</Style.Triggers>
</Style>
Thanks!
update: the entire textbox's code snipt:
<TextBox Height="23" HorizontalAlignment="Left" Margin="114,53,0,0" Name="textBox1" VerticalAlignment="Top" Width="150" Text="{Binding Path=TraderAccount, Mode=OneWayToSource, NotifyOnValidationError=True}" BorderBrush="#FFB9B9B9" BorderThickness="1" >
<TextBox.Style>
<Style TargetType="{x:Type TextBox}">
<Style.Triggers>
<Trigger Property="IsFocused" Value="true">
<Setter Property="BorderBrush" Value="Red" />
</Trigger>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="BorderBrush" Value="Red" />
</Trigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
The style setter is working for me but the issue I see is that the controls animations are animating away the style that's just been set.
You may want to extract the original control template and redefine that rather than completely redefining it. As far as I know The textbox control is more complex than just a border with a content presenter (I've never extracted the control template for it though!) and its likely to have a couple of borders that work to give it all it's states etc
You can use Blend to do this - in the absence of Blend there is the MSDN resource for control templates and styles:
http://msdn.microsoft.com/en-us/library/aa970773.aspx
Edit:
For starters it looks to me like you are missing the content 'PART' in your redefined template
<ScrollViewer Margin="0" x:Name="PART_ContentHost" />
Edit 2:
You are saying it doesn't work... this works for me on WPF using .NET Framework 4.0 - I changed the border colour to 'Red' instead to make sure I could see the effect and it definitely works, aside from the red fading immediately because the controls visual state is changed by the Visual State Manager (which is why you need to edit the control template and change the visual states)
<TextBox>
<TextBox.Style>
<Style TargetType="TextBox">
<Style.Triggers>
<Trigger Property="IsFocused" Value="true">
<Setter Property="BorderBrush" Value="Red" />
</Trigger>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="BorderBrush" Value="Red" />
</Trigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
When you hover over the box, you get a red border which immediately fades
Does this XAML not work for you at all??
You did not post TextBox code but I assume (it happened to me too) that you simply forgot to set BorderThickness of your textbox:
<TextBox BorderThickness="4">
<TextBox.Style>
<Style TargetType="{x:Type TextBox}">
<Style.Triggers>
<Trigger Property="IsFocused" Value="true">
<Setter Property="BorderBrush" Value="#4D90FE" />
</Trigger>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="BorderBrush" Value="#4D90FE" />
</Trigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
Your style does work, set a property like Background in your style without the template and you will see that it does get applied. However, like someone else mentioned, the reason you do not see any changes is because of animation in the default WPF control template for TextBox (Animation values always take precedence over local values, setters and triggers). When you redefine the control template, those animations are no longer there and so your example works. What you could do is take the default TextBox template and modify it to suit your purposes (can be found here: http://msdn.microsoft.com/en-us/library/cc645061%28VS.95%29.aspx).
I want to bind the selected Background color of MyDataGrid to another IsSelected Background color so they share the same color. I'm thinking it can be done something like below. How can I do it?
<DataGrid.Resources>
<Style TargetType="{x:Type DataGridCell}">
<Style.Triggers>
<Trigger Property="DataGridCell.IsSelected" Value="True">
<Setter Property="Background" Value="{Binding ElementName=OtherDataGrid, Path=??Background??" />
</Trigger>
</Style.Triggers>
</Style>
</DataGrid.Resources>
The best way to share the background is to use a StaticResource.
You can create a brush in resources and refer that in both the data grids.
Like:
<Style.Triggers>
<Trigger Property="DataGridCell.IsSelected" Value="True">
<Setter Property="Background" Value="{StaticResource selectedCellBackground}" />
</Trigger>
</Style.Triggers>
Another way is to declare a notify property in the view model and bind both colors to it.