WPF databinding to interface cannot find property - c#

I am working from the solution presented here, which has worked well for me until this point. I'm now trying to perform datatrigger binding to an interface property via the following XAML:
<DataGrid.RowStyle>
<Style TargetType="{x:Type DataGridRow}">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=(selection:IChartDefinitionViewModel.SelectedItem).HasErrors}" Value="False">
<Setter Property="Background" Value="Transparent"/>
</DataTrigger>
<DataTrigger Binding="{Binding Path=(selection:IChartDefinitionViewModel.SelectedItem).HasErrors}" Value="True">
<Setter Property="Background" Value="Red"/>
</DataTrigger>
</Style.Triggers>
</Style>
</DataGrid.RowStyle>
When I enter this code I get a warning "The member 'SelectedItem' is not recognized or is not accessible", and I get a similar exception when I try to run. Only thing is, there is a member SelectedItem defined on the interface, and I can even navigate to it from the XAML:
public interface IChartDefinitionViewModel : IReactiveSelector<SomeClass>, IMayHaveErrors
{
// stuff
}
public interface IReactiveSelector<T> : // more stuff
{
T SelectedItem { get; set; }
}
Can anyone advise why this is happening and what I can do for a workaround? I'd like to manage this based on the interface definition or using a datatemplate for my IChartDefinitionViewModel implementation, if possible.
Update:
This also does not work, but for a different reason - when I attempt to bind to the object directly, the background doesn't change despite the fact that HasErrors toggles from true to false.
<DataGrid.RowStyle>
<Style TargetType="{x:Type DataGridRow}">
<Style.Triggers>
<DataTrigger Binding="{Binding SelectedItem.HasErrors}" Value="True">
<Setter Property="Background" Value="Transparent"/>
</DataTrigger>
<DataTrigger Binding="{Binding SelectedItem.HasErrors}" Value="False">
<Setter Property="Background" Value="Red"/>
</DataTrigger>
</Style.Triggers>
</Style>
</DataGrid.RowStyle>

There appear to have been two issues with my original post. The first is that there was a datacontext issue - thanks to James Durda for pointing this out. The row context is of type ChartDefinitionViewModel, so this code works as desired:
<DataGrid.RowStyle>
<Style TargetType="{x:Type DataGridRow}">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=(selection:ChartDefinitionViewModel.HasErrors)}" Value="False">
<Setter Property="Background" Value="Transparent"/>
</DataTrigger>
<DataTrigger Binding="{Binding Path=(selection:ChartDefinitionViewModel.HasErrors)}" Value="True">
<Setter Property="Background" Value="Red"/>
</DataTrigger>
</Style.Triggers>
</Style>
</DataGrid.RowStyle>
Interestingly, however, binding to the HasErrors property on the IChartDefinitionViewModel interface results in a thrown exception stating that the property path is invalid, which brings me back again to my original inquiry:
<DataGrid.RowStyle>
<Style TargetType="{x:Type DataGridRow}">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=(selection:IChartDefinitionViewModel.HasErrors)}" Value="False">
<Setter Property="Background" Value="Transparent"/>
</DataTrigger>
<DataTrigger Binding="{Binding Path=(selection:IChartDefinitionViewModel.HasErrors)}" Value="True">
<Setter Property="Background" Value="Red"/>
</DataTrigger>
</Style.Triggers>
</Style>
</DataGrid.RowStyle>
Things, however, begin to work as expected when I bind to the interface on which the HasErrors property is directly defined.
<DataGrid.RowStyle>
<Style TargetType="{x:Type DataGridRow}">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=(interfaces:IMayHaveErrors.HasErrors)}" Value="False">
<Setter Property="Background" Value="Transparent"/>
</DataTrigger>
<DataTrigger Binding="{Binding Path=(interfaces:IMayHaveErrors.HasErrors)}" Value="True">
<Setter Property="Background" Value="Red"/>
</DataTrigger>
</Style.Triggers>
</Style>
</DataGrid.RowStyle>
I'm not sure if this is an isolated case, but it appears that WPF binding can't locate properties defined upwards in the interface inheritance hierarchy, at least in this instance.

Related

Wpf mahapps collapse datagrid row by condition not working

I need to hide rows under a certain condition, I do this through a style trigger. But for some reason it doesn't work if you use Map apps styles. If I delete styles from the dictionary, everything works. What i need to do to make it work with Mah app styles as well?
<DataGrid.ItemContainerStyle>
<Style TargetType="DataGridRow">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsArchive}" Value="True">
<Setter Property="Visibility" Value="Collapsed" />
</DataTrigger>
</Style.Triggers>
</Style>
</DataGrid.ItemContainerStyle>
I also tried using baseOn but it still doesn't work
Set the RowStyle instead of ItemContainerStyle:
<DataGrid.RowStyle>
<Style TargetType="DataGridRow" BasedOn="{StaticResource MahApps.Styles.DataGridRow}">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsArchive}" Value="True">
<Setter Property="Visibility" Value="Collapsed" />
</DataTrigger>
</Style.Triggers>
</Style>
</DataGrid.RowStyle>

Window.Visibility won't update through trigger

I'm trying to set a trigger to hide my window whenever a property in my ViewModel changes. I tried using the same trigger on a different element and that worked exactly as expected, so it appears that I cannot change the visibility property of a window using a trigger. Are there any workarounds I can use to hide my window?
<Window.Style>
<Style TargetType="Window" BasedOn="{StaticResource Shell}">
<Setter Property="Visibility" Value="Hidden"/>
<Setter Property="Left" Value="{Binding SecondDisplayLeftSide}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding ShellType}" Value="InstructorMultiDisplay">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Window.Style>

How to apply non-default Foreground color for DataGridRow when IsEnabled is set to False?

How to apply non-default Foreground color for DataGridRow when IsEnabled is set to False?
I'm doing it like this, but Foreground color is not changed.
<DataGrid.RowStyle>
<Style TargetType="DataGridRow" BasedOn="{StaticResource {x:Type DataGridRow}}">
<Style.Triggers>
<DataTrigger Binding="{Binding Name, Converter={StaticResource Converterz}}" Value="true">
<Setter Property="IsEnabled" Value="False"/>
<Setter Property="Foreground" Value="Black"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</DataGrid.RowStyle>
EDIT 1
Ok, I applied style for the DataGrid.CellStyle instead of DataGrid.RowStyle and it worked, but only for cells with TextBlock's. Who can tell me why?
<DataGrid.CellStyle>
<Style TargetType="{x:Type DataGridCell}" >
<Style.Triggers>
<DataTrigger Binding="{Binding Name, Converter={StaticResource Converterz}}" Value="true">
<Setter Property="IsEnabled" Value="False"/>
</DataTrigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Foreground" Value="Black"/>
<Setter Property="FontWeight" Value="Bold"/>
</Trigger>
</Style.Triggers>
</Style>
</DataGrid.CellStyle>

Style Only One Column's Cells DataGrid C# WPF

I currently style a DataGridRow based on the value of a column. The style looks like this;
<DataGrid.RowStyle>
<Style TargetType="DataGridRow">
<Style.Triggers>
<DataTrigger Binding="{Binding Overdue}" Value="1">
<Setter Property="FontWeight" Value="Bold"/>
</DataTrigger>
<DataTrigger Binding="{Binding Priority}" Value="High">
<Setter Property="Background" Value="Red"/>
</DataTrigger>
<DataTrigger Binding="{Binding Priority}" Value="Medium">
<Setter Property="Background" Value="Orange"/>
</DataTrigger>
<DataTrigger Binding="{Binding Priority}" Value="Low">
<Setter Property="Background" Value="LightGreen"/>
</DataTrigger>
</Style.Triggers>
</Style>
</DataGrid.RowStyle>
This applies the style to the entire row based on the column's values. Now however I would to apply the style to only the columns in that cell. This is what the style currently looks like;
However I would like to remove the styling in the cells with a line through below;
i.e. only apply the formatting to the priority column's cells rather than the whole row.
You can try CellStyle for DataGridTemplateColumns.
Ref.
Like,
Add the following style "DGCellStyle" in the resource.
<Style x:Key="DGCellStyle" TargetType="DataGridCell">
<Style.Triggers>
<DataTrigger Binding="{Binding Overdue}" Value="1">
<Setter Property="FontWeight" Value="Bold"/>
</DataTrigger>
<DataTrigger Binding="{Binding Priority}" Value="High">
<Setter Property="Background" Value="Red"/>
</DataTrigger>
<DataTrigger Binding="{Binding Priority}" Value="Medium">
<Setter Property="Background" Value="Orange"/>
</DataTrigger>
<DataTrigger Binding="{Binding Priority}" Value="Low">
<Setter Property="Background" Value="LightGreen"/>
</DataTrigger>
</Style.Triggers>
</Style>
Then, refer this style in DataGridTemplateColumn.
<DataGridTemplateColumn Header="ColumnHeader" Width="SizeToHeader" CellStyle="{StaticResource DGCellStyle}"/>

Bind foreground color to control's IsEnabled state

I'm having trouble binding the label color on my Microsoft.Windows.Controls.Ribbon.RibbonTab objects to their Enabled state.
I tried the following first:
<Style TargetType="{x:Type r:RibbonTab}">
<Setter Property="Foreground" Value="White" />
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=IsEnabled}" Value="False">
<Setter Property="Foreground" Value="Gray" />
</DataTrigger>
</Style.Triggers>
</Style>
But it has no affect on the foreground. It looks like something in the ribbonTab library code is programatically overwriting the foreground.
I then tried this:
<Style x:Key="BaseRibbonTabStyle" TargetType="{x:Type r:RibbonTab}">
<EventSetter Event="IsEnabledChanged" Handler="RibbonTab_IsEnabledChanged"
</Style>
private void RibbonTab_IsEnabledChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if( (bool)e.NewValue == false )
((RibbonTab)sender).Foreground = (new System.Windows.Media.BrushConverter()).ConvertFromString("Gray") as System.Windows.Media.Brush;
else
((RibbonTab)sender).Foreground = (new System.Windows.Media.BrushConverter()).ConvertFromString("White") as System.Windows.Media.Brush;
}
But that also failed with the following compile time error:
System.Windows.UIElement.IsEnabledChanged="RibbonTab_IsEnabledChanged_Event" is not valid. 'IsEnabledChanged' must be a RoutedEvent registered with a name that ends with the keyword "Event".
How can I get this to work?
Try a simple property trigger:
<Style TargetType="{x:Type r:RibbonTab}">
<Style.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Foreground" Value="Gray" />
</Trigger>
</Style.Triggers>
<Setter Property="Foreground" Value="White" />
</Style>
Did you try this:
<Style TargetType="{x:Type r:RibbonTab}">
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=IsEnabled}" Value="False">
<Setter Property="Foreground" Value="Gray" />
</DataTrigger>
</Style.Triggers>
<Setter Property="Foreground" Value="White" />
</Style>

Categories