Changing the content of button using a style - wpf

I'm creating an application that contains two types of users; staff, admin. Each user has his/her own permissions. For example, an admin can add, edit, delete etc; while the staff can only view. Currently within my app, I use a ListView to display data and then use a DataTemplate where by I set my buttons within, as shown below.
However, I want to change the content of the edit button to show View, rather then edit if the user is a staff user. I tried implementing the following code, but it doesn't seem to change.
<Button Content="Edit" Command="{Binding ShowEditCommand}" Width="50">
<Button.Style>
<Style TargetType="{x:Type Button}" BasedOn="{StaticResource MetroButton}">
<Setter Property="Content" Value="View" />
<Style.Triggers>
<DataTrigger Binding="{Binding Role}">
<DataTrigger.Value>
<enum:EnumPermission>Admin</enum:EnumPermission>
</DataTrigger.Value>
<Setter Property="Content" Value="Edit"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
I'm not very good with creating styles and therefore would appreciate some guidance in what I am doing wrong and what can be done to change it. Thanks in advance.
Edit:
Originally, as pointed out, I forgot to remove the `Content="Edit" from the button. However, when I remove that, the style still doesn't fully work.

Remove Content="Edit" from Button definition
<Button Content="Edit" ...
Style.Trigger will not be able to overwrite that value according to Dependency Property Setting Precedence List. It's enough that you set default value in Style as
<Setter Property="Content" Value="View" />

first just FYI you should not change the content in the style , you can bind the content to a property and change that property value
to solve this just remove Content="Edit" from the first line

Related

How to put a tooltip to a button for enabling and disabling in WPF

I want to put a tooltip to a button for enabling and disabling in WPF. I have mentioned the tried code below. But My tried code does not solve my problem. I have no idea should I use the separate property for this.
Code:
<dc:GeometryButton
Grid.Column="11"
Command="{Binding Path=GeneratePrintTemplateFilesCommand}"
Geometry="{StaticResource {x:Static dc:Geometries.Print}}"
ToolTip="{Binding Path=GeneratePrintTemplateFilesFeatureToolTip}"
Style="{StaticResource FormBuilderClient_TopToolbarGeometryButton_Style}"/>
I need your help to solve this. Thank you.
Same tool tip when disabled
If you want to show the same tool tip for both the enabled and disabled state of the button, you have to set the ShowOnDisabled property of the ToolTipService to True on your button.
ToolTipService.ShowOnDisabled="True"
Different tool tips through binding
If want to show different tool tips by changing the bound property GeneratePrintTemplateFilesFeatureToolTip in your view model on button click e.g. in your GeneratePrintTemplateFilesCommand, the first solution also works. However, you must implement INotifyPropertyChanged in this case, otherwise the button will not get notified of the changed tool tip text.
Different tool tips with style
An alternative for showing different tool tips for the enabled and disabled states of your button is to add a trigger to the Style of the button and make it depend on the IsEnabled property. You can merge this with your existing style. Note that I use two different properties to bind to, one for enabled and one for disabled. In practice, you would rather use static resources here, instead of properties on a view model, because they do not change here.
<Style x:Key="FormBuilderClient_TopToolbarGeometryButton_Style"
TargetType="{x:Type dc:GeometryButton}"
BasedOn="{StaticResource {x:Type dc:GeometryButton}}">
<Setter Property="ToolTip"
Value="{Binding GeneratePrintTemplateFilesFeatureToolTipEnabled}"/>
<Style.Triggers>
<Trigger Property="IsEnabled"
Value="False">
<Setter Property="ToolTip"
Value="{Binding GeneratePrintTemplateFilesFeatureToolTipDisabled}"/>
</Trigger>
</Style.Triggers>
</Style>
Make sure to remove the tool tip property from the button control itself and add the ShowOnDisabled property setting from above., otherwise your tooltip either will not change or not be displayed in disabled state.
<dc:GeometryButton Grid.Column="11"
Command="{Binding Path=GeneratePrintTemplateFilesCommand}"
Geometry="{StaticResource {x:Static dc:Geometries.Print}}"
ToolTipService.ShowOnDisabled="True"
Style="{StaticResource FormBuilderClient_TopToolbarGeometryButton_Style}"/>

WPF DataBinding and Validation

I have a WPF User Interface and I've implemented bound ValidationRules with UpdateSourceTrigger="Explicit". I'm finding that it works perfectly when I have the tab page where the fields being validated is visible:
but if I'm on the third tab page where the form ends and trigger the UpdateSources method on the BindingExpressions for the fields being Validated then when I step back to the first tab the fields aren't actually highlighted in red. Even once I'm back on that tab page and re-trigger they don't highlight even though they're empty. I need to enter a value, re-trigger, then delete the value and re-trigger, THEN the modified ones get highlighted.
Anyone know how to address this behaviour?
Also is there a way to force a specific tab page to be switched to when the Validation fails, switching to the page which has the first field to fail?
I know there's an option to go with PropertyChanged and LostFocus but I'd like to get full form entry first and do all validation in one hit at the end.
It's because of the way the TabControl handles the AdornerLayer. They are obviously not preserved when the TabItem is switched. It works when you force to re-render the AdornerLayer when switching back to the TabItem.
<!-- Custom error template -->
<ControlTemplate x:Key="ValidationErrorTemplate">
<StackPanel>
<!-- Placeholder for the TextBox itself -->
<AdornedElementPlaceholder />
<TextBlock Text="{Binding ErrorContent}"
Foreground="Red" />
</StackPanel>
</ControlTemplate>
<!-- Style to trigger the rendering of the AdornerLayer by setting the error template -->
<Style TargetType="TextBox">
<Setter Property="Validation.ErrorTemplate"
Value="{x:Null}" />
<Style.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="Validation.HasError"
Value="True" />
<Condition Property="IsVisible"
Value="True" />
</MultiTrigger.Conditions>
<Setter Property="Validation.ErrorTemplate"
Value="{StaticResource ValidationErrorTemplate}" />
</MultiTrigger>
</Style.Triggers>
</Style>
Consider to disallow leaving the current tab if it has validation errors to avoid this behavior.

Is it possible to hide rows according to some condition?

I have a DataGrid that binding an ObservableCollection of self tracking entities
Users can "delete" records in the DataGrid, however the items don't actually get deleted from the database.
How can I only display rows that aren't marked as deleted?
I am using MVVM pattern.
Use CollectionView.Filter technique. Its very MVVM oriented.
Just add a DataGrid.RowStyle, you could use DataTriggers to set the Visibility to Collapsed or change the Background (code example).
Maybe it's a little bit more information then you're after, but I was met with the exact same case and chose to display rows as greyed out, or 'redded' out when their state is toggled to deleted. You trigger properties and style target type might be a little different since I'm using an Xceed DataGrid and you're using the built-in Datagrid, but it'll be essentially the same: https://stackoverflow.com/a/10431650/529618
<Style TargetType="{x:Type xcdg:DataRow}" >
<Style.Triggers>
<DataTrigger Binding="{Binding Path=ObjectState}"
Value="{x:Static Member=objectmodel:EnumObjectState.Deleted}" >
<!-- You can do anything in this trigger such as hide, collapse, or disable the row. I chose to apply a custom effect. -->
<Setter Property="Background" Value="#FFEED5D2"/>
<Setter Property="ToolTip" Value="This entry will be permanently deleted the next time you save."/>
<Setter Property="Effect">
<Setter.Value>
<ui:ColourAdjustEffect Saturation="0" Gamma="0.6" BrightnessAdjustment="-0.2" RedAdjustment="0.04" />
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
For what it looks like, check out the last 3 images in the combined image below:

Style Triggers not working when object is bound to other object

I am having a problem with the style of a few items that are bound to a set of radio buttons. Basically, I have the following code for my styles:
<Window.Resources>
<Style x:Key="boxStyle" TargetType="TextBox">
<Setter Property="Background" Value="Black"/>
<Style.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Background" Value="Blue"/>
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
Then I have two radio buttons as shown here:
<RadioButton Name="optionA" IsChecked="True">Option A</RadioButton>
<RadioButton Name="optionB'>Option B</RadioButton>
And two text boxes as shown here:
<TextBox Style="{StaticResource boxStyle}" IsEnabled="{Binding ElementName=optionA, Path=IsChecked}"/>
<TextBox Style="{StaticResource boxStyle}" IsEnabled="{Binding ElementName=optionB, Path=IsChecked}"/>
The binding works correctly (when Option A it checked, one box is enabled and the other is not). However, when either of the boxes becomes disabled, it does not follow the style defined above. The background goes to white no matter what I change the style color to.
Anyone have any ideas? Thanks.
The color used when disabled is hard-coded in the template as far as i know, you cannot easily change it unless it references a system-color in which case you can override.
The default Aero theme uses a ListBoxChrome control, not sure if that can be made to change its background accordingly, it has no template so it might be hard to modify it. You could of course throw it out and use whatever you want (which you can modify).

WPF DataGrid Hyperlink Appearance and Behaviour

I am quite new to WPF, there is so much to learn and I think I'm getting there, slowly. I have a DataGrid which is used for display and user input, it's quite a tricky Grid as it is the main focus of the entire application. I have some columns that are read-only and I have used a CellStyle Setter to set KeyboardNavigation.IsTabStop to False to keep user input focused on the important columns and that works fine. I would like a couple of the read-only columns to be hyperlinks that show a tooltip and do not receive the focus, however I am struggling to write the XAML that will achieve all three requirements at the same time.
One of the columns is to indicate if the item on the row has any Notes. I have used the following XAML to display a HasNotes property in the cell in a DataGridTemplateColumn and on the Tooltip show the actual notes, in the Notes property:
<DataGridTemplateColumn x:Name="NotesColumn" Header="Notes">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding HasNotes, Mode=OneWay}">
<TextBlock.ToolTip>
<TextBlock Text="{Binding Notes}" MaxWidth="300" TextWrapping="Wrap" />
</TextBlock.ToolTip>
</TextBlock>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellStyle>
<Style>
<Setter Property="KeyboardNavigation.IsTabStop" Value="False"/>
</Style>
</DataGridTemplateColumn.CellStyle>
</DataGridTemplateColumn>
That works fine but I would like to make it a Hyperlink instead so the user can do something with the Notes when they click on the cell contents.
I have another column which is a DataGridHyperlinkColumn used to display a Unit of Measurement on a hyperlink and when clicked the user can change the unit. (The reason I have done it like this, rather than a ComboBox for example, is because as much as I want the user to be able to change the unit I want to make the interface such that it is a very deliberate act to change the unit, not something that can be done accidentally). The following XAML puts the Hyperlink column on for Unit
<DataGridHyperlinkColumn x:Name="ResultUnitLink" Binding="{Binding Path=Unit.Code}" Header="Unit" Width="Auto" IsReadOnly="True">
<DataGridHyperlinkColumn.CellStyle>
<Style>
<Setter Property="KeyboardNavigation.IsTabStop" Value="False"/>
</Style>
</DataGridHyperlinkColumn.CellStyle>
<DataGridHyperlinkColumn.ElementStyle>
<Style>
<EventSetter Event="Hyperlink.Click" Handler="ChangeUnit" />
</Style>
</DataGridHyperlinkColumn.ElementStyle>
</DataGridHyperlinkColumn>
One problem with the XAML for the Hyperlink column is that the IsTabStop = False doesn't appear to work, when tabbing through the Grid my hyperlink column still receives the focus, unlike the other columns where I've used a setter to change IsTabStop. If push comes to shove I could live with that but I'd rather not.
What I actually want from both those columns is an amalgamation of the two appearances/behaviours i.e. Columns where the data is displayed on a hyperlink, where TabStop = False and which display a tooltip of a different property when hovered over.
Can anyone help advise me how to get a column that achieves the following:
Hyperlink displaying one property
Tooltip displaying a different property
IsTabStop = False that actually works when used with a hyperlink
Thanks in advance to anyone who can help.
I've had issues with the Hyperlink in the past, so have this Style which I use for Labels or Buttons to make them look like Hyperlinks. Try making your column Template into a Button or a Label and applying this style.
<Style x:Key="ButtonAsLinkStyle" TargetType="{x:Type Button}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<TextBlock HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<ContentPresenter ContentStringFormat="{TemplateBinding ContentStringFormat}" />
</TextBlock>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="Foreground" Value="Blue" />
<Setter Property="Cursor" Value="Hand" />
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Foreground" Value="Red" />
</Trigger>
</Style.Triggers>
</Style>

Resources