Reputation: 2519
Is there a way to apply a style based on conditions in multiple view models.
For example, I have a list of items that can be conditionally formatted at the item level, but I also want to be able to turn the formatting on or off at the whole list level:
Main view model
class ParentViewModel : ViewModelBase
{
public ParentViewModel ()
{
Items = new ObservableCollection<ChildViewModel> {
new ChildViewModel{ Display = "I am red", Format=1 },
new ChildViewModel{ Display = "I am red", Format=1 },
new ChildViewModel{ Display = "I am blue", Format=2 },
new ChildViewModel{ Display = "I am blue", Format=2 },
};
ShowFormatting = false;
}
public ObservableCollection<ChildViewModel> Items { get ... }
// I would like to use this property to turn formatting off for the whole list
public bool ShowFormatting { get ... }
}
Contains many sub-view models
class ChildViewModel: ViewModelBase
{
public string Display { get ... }
public int Format { get ... }
}
Displayed in a window
<Window ...>
<Grid>
<Grid.Resources>
<Style x:Key="MyStyle" TargetType="{x:Type TextBlock}">
<Style.Triggers>
<!-- How can I access ShowFormatting from the main view model here? -->
<DataTrigger Binding="{Binding Format}" Value="1">
<Setter Property="Foreground" Value="Red"></Setter>
</DataTrigger>
<DataTrigger Binding="{Binding Format}" Value="2">
<Setter Property="Foreground" Value="Blue"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</Grid.Resources>
<ListView ItemsSource="{Binding Items}">
<ListView.View>
<GridView>
<GridViewColumn>
<GridViewColumn.CellTemplate>
<!-- Or can I apply the conditional formatting here? -->
<DataTemplate DataType="{x:Type local:ChildViewModel}">
<TextBlock Text="{Binding Display}" Style="{StaticResource MyStyle}"></TextBlock>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
</Grid>
</Window>
The problem that I see is that the style is targeting a ChildViewModel
and the ShowFormatting
property is not accessible. The best solution that I can come up with is to have a backlink from the ChildViewModel
to the ParentViewModel
, but having backlinks generally seems bad to me. Is there a better way to do this?
Upvotes: 1
Views: 78
Reputation: 16106
One way of doing this is to have two different child view models, ChildViewModel1
and ChildViewModel2
. The ParentViewModel
would populate Items
with one or both of these types: you could use an ObservableCollection<object>
if you wish. When you define a datatemplate for ChildViewModel1
and another for ChildViewModel2
, then depending which child view model was resident in the ObservableCollection
, you'd get the respective rendering.
Upvotes: 1
Reputation: 114
How about using a RelativeSource
for your Binding? (I'm assuming here that the DataContext of your Window is of Type ParentViewModel
)
<Grid.Resources>
<Style x:Key="MyStyle" TargetType="{x:Type TextBlock}">
<Style.Triggers>
<DataTrigger Binding="{Binding Format}" Value="1">
<Setter Property="Foreground" Value="Red"></Setter>
</DataTrigger>
<DataTrigger Binding="{Binding Format}" Value="2">
<Setter Property="Foreground" Value="Blue"></Setter>
</DataTrigger>
<DataTrigger Binding="{Binding Path=DataContext.ShowFormatting, RelativeSource={RelativeSource AncestorType=Window}}" Value="SomeValue">
<Setter Property="SomeProperty" Value="SetToThisValue"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</Grid.Resources>
Upvotes: 1