Reputation: 1100
I am working on expression Blend for VS2015, I have aListBox
binded to an ObservableCollection
of custom objects. Those objects expose Properties
that arise the NotifyPropertyChanged
, and everything works nice.
I can bind parts if the ItemTemplate
to those Properties
and my list work nice but what I want to do is to set the VisualState
according to a certain bool
(already configured or not). I also created some events (configured, confLost) and tried to target those events in the triggers panel but .. nothing worked.
How do I bind VisualStates
to members of the bound object ??
Upvotes: 1
Views: 931
Reputation: 1100
Although Kylo's solution would provably work, the people at Microsoft already worked a code-free, 3-clicks-away solution for such a simple action to do.
Solution is on Behaviors, there is one behavior called GoToStateAction
you have to add one of them to your control and there you can set your trigger (that can be set as DataTrigger). In my case I binded to a property of the type enum.
Then you can set the Comparison and the value (equals to "ReadyToUse")
Then as an outcome of the comparison you can trigger a state change for a particular object, you set your object, and you select the state from a nice combobox. There is even a checbox for using your transitions.
Upvotes: 1
Reputation: 8823
ItemTemplate
property works like any other DependencyProperty
, it can be set/reset anytime and it's visual impact will be reflected on UI
. see below example where I have bound a bool
value to ToggleButton
state and ItemControl's
ItemTemplate
is changed accordingly rendering different visual
.
Update: I designed a Device
class that has device name and it's state to make a similar situation. And another class MyVisualStateManager
to create a bindable property. Cause VisualStateManager
class doesn't expose any property to bind directly. code is as below:
XMAL
<Window x:Class="WpfStackOverflowTempProject.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Width="525"
DataContext="{Binding RelativeSource={RelativeSource Mode=Self}}"
xmlns:local="clr-namespace:WpfStackOverflowTempProject"
>
<ItemsControl ItemsSource="{Binding list}" >
<ItemsControl.ItemTemplate>
<DataTemplate>
<local:UserControl1 DataContext="{Binding Name}" Width="200" BorderBrush="Black" BorderThickness="2" Padding="2">
<local:UserControl1.Style>
<Style TargetType="{x:Type local:UserControl1}">
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=DataContext.DeviceState}" Value="0">
<Setter Property="local:MyVisualStateManager.VisualState" Value="State1" />
</DataTrigger>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=DataContext.DeviceState}" Value="1">
<Setter Property="local:MyVisualStateManager.VisualState" Value="State2" />
</DataTrigger>
</Style.Triggers>
</Style>
</local:UserControl1.Style>
</local:UserControl1>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
UserControl:
<UserControl x:Class="WpfStackOverflowTempProject.UserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="Common">
<VisualState x:Name="State1">
<Storyboard>
<DoubleAnimation To="1" Duration="0:00:2" Storyboard.TargetName="State1Panel" Storyboard.TargetProperty="(UIElement.Opacity)" />
<DoubleAnimation To="0" Duration="0:00:3" Storyboard.TargetName="State2Panel" Storyboard.TargetProperty="(UIElement.Opacity)" />
</Storyboard>
</VisualState>
<VisualState x:Name="State2">
<Storyboard>
<DoubleAnimation To="0" Duration="0:00:3" Storyboard.TargetName="State1Panel" Storyboard.TargetProperty="(UIElement.Opacity)" />
<DoubleAnimation To="1" Duration="0:00:2" Storyboard.TargetName="State2Panel" Storyboard.TargetProperty="(UIElement.Opacity)" />
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Border Name="State2Panel" Background="Green" Opacity="0"/>
<Border Name="State1Panel" Background="Red" Opacity="1"/>
<TextBlock Text="{Binding Path=.}" Foreground="White" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
DataContext:
public partial class MainWindow : Window
{
public MainWindow()
{
list = new List<Device>();
list.Add(new Device() {Name="Device 1",DeviceState = 0 });
list.Add(new Device() { Name = "Device 2", DeviceState = 1 });
list.Add(new Device() { Name = "Device 3", DeviceState = 0 });
list.Add(new Device() { Name = "Device 4", DeviceState = 2 });
list.Add(new Device() { Name = "Device 5", DeviceState = 1 });
InitializeComponent();
}
public List<Device> list { get; set; }
}
public class Device : INotifyPropertyChanged
{
private string name;
public string Name
{
get { return name; }
set
{
name = value;
updateProperty("Name");
}
}
private int deviceState;
public int DeviceState
{
get { return deviceState; }
set
{
deviceState = value;
updateProperty("DeviceState");
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void updateProperty(string name)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}
}
Helper Class: This class exposes an attached property VisualState
that could be bound to any value in xaml
.
public class MyVisualStateManager
{
public static string GetVisualState(DependencyObject obj)
{
return (string)obj.GetValue(VisualStateProperty);
}
public static void SetVisualState(DependencyObject obj, string value)
{
obj.SetValue(VisualStateProperty, value);
}
// Using a DependencyProperty as the backing store for VisualState. This enables animation, styling, binding, etc...
public static readonly DependencyProperty VisualStateProperty =
DependencyProperty.RegisterAttached("VisualState", typeof(string), typeof(MyVisualStateManager), new PropertyMetadata(new PropertyChangedCallback(VisualStateChanged)));
public static void VisualStateChanged(DependencyObject Do, DependencyPropertyChangedEventArgs e)
{
if (e.NewValue != null)
{
string state = e.NewValue.ToString();
var control = Do as FrameworkElement;
VisualStateManager.GoToState(control, state, true);
}
}
}
Output
Different Item representing different devices and visual is changed on basis of their
Devicestateproperty which causes a
Triggerto get executed in
UserControl1.
Upvotes: 2
Reputation: 31686
I mean in the user interface of Blend, where to click to get the conditional working,
Objects and Timeline
panel. TextBox
.Edit Style
the either create a new style (most likely) or Edit a Copy
which works of any existing inherited styles.From there one can work on the properties tab to change specifics. Most likely you will be working directly in the xaml to do specific operations.
Even though these docs for Version 2, they still apply, if nothing else can give you an overview of Blend
Upvotes: 0