2016-04-25 130 views
1

我正在处理VS2015的表达式混合,我有一个绑定到ObservableCollection自定义对象的ListBox。这些对象公开Properties出现NotifyPropertyChanged,并且一切正常。WPF将VisualState附加到对象属性

我可以绑定部分,如果ItemTemplate那些Properties和我的名单的工作不错,但我想要做的就是按照一定的bool(已配置与否)设置VisualState。我还创建了一些事件(配置,confLost),并试图在触发器面板中定位这些事件,但是......没有任何工作。

如何将VisualStates绑定到绑定对象的成员?

+0

Javirs嗨,你可以发布你的对象类的代码?或者它的一个片段。我可以帮助你,然后 – Master

+0

@Master如我的答案所示,对象的代码根本不需要。 – javirs

回答

1

虽然Kylo的解决方案将可行,微软的员工已经开展了无代码的3键点击操作,为这样一个简单的行动做解决方案。

解决方案是在行为上,有一种行为称为GoToStateAction,您必须将其中一个添加到您的控件中,并在那里设置触发器(可以设置为DataTrigger)。在我的情况下,我绑定到类型枚举的属性。 然后你可以设置比较值(等于“随时可用”)

然后,你可以触发特定对象的状态变化比较的结果,你设置你的对象,并选择从状态一个不错的组合框。甚至还有一个用于转换的checbox。

VS screenshot

+0

很好...你应该也发布后改变的代码......这是实际的关键。 –

2

ItemTemplate房产像其他任何DependencyProperty一样,可随时设置/重置,其视觉影响将反映在UI上。见下面的例子,其中我已绑定一个boolToggleButton状态和ItemControl'sItemTemplate相应地改变呈现不同visual

更新:我设计了一个Device类,它具有设备名称,并且它的状态可以做出类似的情况。另一个类MyVisualStateManager创建一个可绑定的属性。原因VisualStateManager类不公开直接绑定的任何属性。代码是如下:

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 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)); 
     } 
    } 
} 

助手类:此类公开附加属性VisualState可能在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); 
     } 
    } 
} 

输出

Different Item representing different devices and visual is changed on basis of their Devicestate property which causes a触发to get executed in的UserControl1 .

list Item

+0

关于如何从表情混合界面做到这一点的任何线索?顺便说一句,我想要做的是根据其特定对象上的布尔单独地更改每个项目的VisualState,但是我想很容易从您的示例中推断如何到达那里。你可以提供一些关于如何从表达式Blend接口做到这一点的细节? – javirs

+0

@javirs在表达式混合中......你的意思是通过从某些配置中读取该bool值? –

+0

我的意思是在Blend的用户界面中,在哪里点击以获得有条件工作,取决于Data变量,VisualState(具有定义的动画)之间的切换。到目前为止,我没有编辑xaml,只是使用Blend面板。事情很好。我想继续这样做。 – javirs

0

我的意思是在Blend,应该点击哪里获得有条件工作的用户界面,

  1. 在混合认准Objects and Timeline面板。
  2. 在您定义的ItemTemplate中选择控件(您已经设置了一个正确的?),您希望状态发生变化。 在Kylo的例子中,我们将选择TextBox
  3. 右键点击并选择Edit Style或者创建一个新的样式(最有可能)或Edit a Copy,它可以处理任何现有的继承样式。

enter image description here

从那里可以在属性选项卡上努力改变细节。您很可能会直接在xaml中执行特定的操作。

enter image description here


即使这些文档的第2版,它们仍然适用,如果没有别的可以给你混合的概述

Create a style resource

Style and template overview