Reputation: 22161
I have a view model that contains a collection of Item Attributes
, which in turn each contain a path to an image. There may be anywhere from 0 .. N
item attributes in the collection.
A stackpanel in my view contains three identical image controls. Each image control is bound to the path of an item attribute image:
If there are more than 3 attributes, they are ignored. In order to deal with the possibility of having 0 - 2 attributes (which means 1 or more of the image controls will be bound to null), which in turn gives the error stated in this post, I have added a data trigger like so:
<DataTrigger Binding="{Binding Attribute1}" Value="{x:Null}">
<Setter Property="Source" Value="{x:Null}"/>
</DataTrigger>
Also, in order to prevent an index out of bound issue, I have split the item attributes in my view model into three properties (i was initially returning String.Empty, but changed it to null to work with the data trigger):
public string Attribute1
{
get { return _item.Attributes.Count > 0 ? _item.Attributes[0].Image : null; }
}
public string Attribute2
{
get { return _item.Attributes.Count > 1 ? _item.Attributes[1].Image : null; }
}
public string Attribute3
{
get { return _item.Attributes.Count > 2 ? _item.Attributes[2].Image : null; }
}
So my problem is that I would like to have this data trigger work for all three image attributes and the corresponding image controls (along with some other properties like width, height, margin etc.). So I think, put it in a style and reference it as a static resource. This won't work when I have three different properties with different names (Attribute1, Attribute2, Attribute3). So now I am stuck doing it this way:
<Image>
<Image.Style>
<Style TargetType="Image">
<Setter Property="Source" Value="{Binding Attribute1}" />
<Setter Property="Width" Value="44" />
<Setter Property="Height" Value="45" />
<Setter Property="Margin" Value="5" />
<Style.Triggers>
<DataTrigger Binding="{Binding Attribute1}" Value="{x:Null}">
<Setter Property="Source" Value="{x:Null}" />
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
This is repeated for the other two image controls, except the Attribute1 is substituted with Attribute2 and Attribute3.
So then I was wondering if there is a way to bind to a collection instead, such as
<DataTrigger Binding="{Binding Attributes}" Value="{x:Null}">
<Setter Property="Source" Value="{x:Null}"/>
</DataTrigger>
... and then specifcy the index I'm interested in the image control binding, outside of the template (i guess like passing a parameter to the data trigger).
Any ideas... is there another approach if this isn't possible?
Upvotes: 3
Views: 101
Reputation: 44038
<ItemsControl ItemsSource="{Binding Attributes}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Image Source={Binding Something} x:Name=Image/>
<DataTemplate.Triggers>
<DataTrigger Binding={Binding Something} Value={x:Null}>
<Setter TargetName=Image Property=Source Value={x:Null}/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Typed this manually in the answer, not real XAML. But you should be able to understand what I mean.
Edit: If your Attributes
are just strings, use "{Binding}"
wherever I placed "{Binding Something}"
--UPDATE (I'll update your answer with what I did since your answer was correct)--
<ItemsControl ItemsSource="{Binding Attributes}"
Grid.Row="4" Grid.Column="0" Grid.ColumnSpan="2" Margin="5">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"
HorizontalAlignment="Left" VerticalAlignment="Top" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Image x:Name="Image"
Source="{Binding}"
Width="45" Height="44" Margin="5" />
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding}" Value="{x:Null}">
<Setter TargetName="Image"
Property="Source" Value="{x:Null}" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
And to limit it to the first three item attributes, this is what I had in my view model's constructor. Attributes is a SmartObservableCollection property (custom ObservableCollection with and AddRange method and a couple other goodies) with an _attributes backing field:
_attributes = new SmartObservableCollection<string>();
var images = from attributes in _item.Attributes
select attributes.Image;
Attributes.AddRange(images.Take(3));
Upvotes: 7