DataTemplate中的WPF样式触发器

时间:2011-08-22 09:51:37

标签: wpf xaml data-binding triggers binding

我希望你能帮助我。我在资源中获得了以下代码:

<UserControl.Resources>
  <BitmapImage x:Key="img_src_lock" UriSource="/EEBase;component/Images/Lock_24x32.png" />
  <BitmapImage x:Key="img_src_unlock" UriSource="/EEBase;component/Images/Unlock_24x32.png" />
  <Style TargetType="{x:Type ToggleButton}">
    <Style.Triggers>
      <DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsChecked}" Value="True">
        <Setter Property="Content">
          <Setter.Value>
            <Image Source="{StaticResource img_src_lock}" />
          </Setter.Value>
        </Setter>
      </DataTrigger>
      <DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsChecked}" Value="False">
        <Setter Property="Content">
          <Setter.Value>
            <Image Source="{StaticResource img_src_unlock}" />
          </Setter.Value>
        </Setter>
      </DataTrigger>
    </Style.Triggers>
  </Style>
  <!-- TypeComboTemplateCollapsed -->
  <DataTemplate x:Key="TypeComboTemplateCollapsed">
    <TextBlock 
      Text="{Binding Path=Text, Mode=OneWay}" 
      VerticalAlignment="Center"
      HorizontalAlignment="Left"
      Margin="5,0,0,5"
      />
  </DataTemplate>
  <!-- TypeComboTemplateExpanded -->
  <DataTemplate x:Key="TypeComboTemplateExpanded">
    <TextBlock 
      Text="{Binding Path=Text, Mode=OneWay}" 
      VerticalAlignment="Center"
      Margin="5,0,0,5"
      />
  </DataTemplate>
  <!-- EditCircleTemplate -->
  <DataTemplate x:Key="EditCircleTemplate">
    <!-- some content here, no ToggleButton -->
  </DataTemplate>
  <!-- EditRectangleTemplate -->
  <DataTemplate x:Key="EditRectangleTemplate">
    <!-- some other content here, including the ToggleButtons -->
    <ToggleButton
      IsChecked="{Binding Path=BaseLocked, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}"
      Margin="5"
      />
    <ToggleButton
      IsChecked="{Binding Path=HeightLocked, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}"
      Margin="5"
      />
  </DataTemplate>
</UserControl.Resources>

对我而言看起来都很正确。

现在,问题是: 当我执行以下操作时,会发生异常:
指定的元素已经是另一个元素的逻辑子元素。首先断开它。
1.加载控制,选择的类型是CIRC
2.更改下拉列表以选择RECT(模板触发器和togglebuttons正确显示)
3.将下拉菜单更改回CIRC
- &GT;现在发生例外。
4.如果我忽略该异常,则不会加载模板“EditCircleTemplate”,并显示模型对象的正常ToString。

其他信息:
最初WPF中有4种不同的类型,其中两种带有ToggleButtons(这就是我使用模板的原因)。我把它们剪掉了,它们真的没有区别。但我发现使用所有4个模板时,切换到新模板时不会发生错误,但使用切换按钮卸载模板时。这有点奇怪。 此外,如果我删除ToggleButtons的DataTriggers,一切都像魅力一样 Exception来自XAML-Interpreter,因此Stacktrace根本没用。

任何人都可以暗示我的错误吗?

编辑: 哎呀,我想我忘记了内容代码:

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="160"/>
        <ColumnDefinition />
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition />
    </Grid.RowDefinitions>
    <ComboBox 
        Margin="5"
        Grid.Row="0"
        Grid.Column="0"
        ItemsSource="{Binding Path=PossibleTypes, Mode=OneTime}"
        SelectedItem="{Binding Path=SelectedType, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
        <ComboBox.ItemTemplate>
            <DataTemplate>
                <StackPanel>
                    <ContentControl x:Name="content" Content="{Binding}" ContentTemplate="{StaticResource TypeComboTemplateExpanded}"/>
                </StackPanel>
                <DataTemplate.Triggers>
                    <DataTrigger Binding="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=ComboBoxItem}}" Value="{x:Null}">
                        <Setter TargetName="content" Property="ContentTemplate" Value="{StaticResource TypeComboTemplateCollapsed}"/>
                    </DataTrigger>
                </DataTemplate.Triggers>
            </DataTemplate>
        </ComboBox.ItemTemplate>
    </ComboBox>
    <ContentControl
        Grid.Column="0"
        Grid.Row="1"
        Grid.ColumnSpan="2"
        Content="{Binding Mode=OneWay}">
        <ContentControl.ContentTemplate>
            <DataTemplate >
                <ContentControl
                    Name="inputContent"
                    Content="{Binding Mode=OneWay}"
                    ContentTemplate="{x:Null}" 
                    />
                <DataTemplate.Triggers>
                    <DataTrigger 
                        Binding="{Binding Path=SelectedType.Type, Mode=OneWay}" 
                        Value="CIRC">
                        <Setter 
                            TargetName="inputContent" 
                            Property="ContentTemplate" 
                            Value="{StaticResource EditCircleTemplate}"
                            />
                    </DataTrigger>
                    <DataTrigger 
                        Binding="{Binding Path=SelectedType.Type, Mode=OneWay}" 
                        Value="RECT">
                        <Setter 
                            TargetName="inputContent" 
                            Property="ContentTemplate" 
                            Value="{StaticResource EditRectangleTemplate}"/>
                    </DataTrigger>
                </DataTemplate.Triggers>
            </DataTemplate>
        </ContentControl.ContentTemplate>
    </ContentControl>
</Grid>

EDIT2 /解决方案:
我找到了一个解决方法 - 它只是不满足我:
而不是将样式放在UserControl.Resources中,对我来说这将是更清晰直观的解决方案,我必须在每个ToggleButton单独上设置触发器的样式。
因此删除并向每个ToggleButton添加以下代码可以解决问题:

<ToggleButton.Style>
  <Style TargetType="{x:Type ToggleButton}">
    <Style.Triggers>
      <DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsChecked}" Value="True" >
        <Setter Property="Content">
          <Setter.Value>
            <Image Source="{StaticResource img_src_lock}" />
          </Setter.Value>
        </Setter>
      </DataTrigger>
      <DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsChecked}" Value="False">
        <Setter Property="Content">
          <Setter.Value>
            <Image Source="{StaticResource img_src_unlock}" />
          </Setter.Value>
        </Setter>
      </DataTrigger>
    </Style.Triggers>
  </Style>
</ToggleButton.Style>

最大的问题仍然存在:为什么?

2 个答案:

答案 0 :(得分:1)

问题在于,如果你在一个样式中创建一个Image,那么只有一个实例,所以一旦多个控件使用该样式,就会对这个只能拥有的实例进行争夺由一个控制。

最简单的解决方案是将Style放在资源中并将x:Shared设置为false,这样就可以使用该样式的副本。

答案 1 :(得分:0)

为什么需要创建BitmapImages并将它们设置为触发器中的内容图像的源?为什么你不直接使用URI源到图像?

    <Style TargetType="{x:Type ToggleButton}"> 
      <Style.Triggers> 
        <DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsChecked}" Value="True"> 
          <Setter Property="Content"> 
            <Setter.Value> 
              <Image Source="/EEBase;component/Images/Lock_24x32.png" /> 
            </Setter.Value> 
          </Setter> 
        </DataTrigger> 
        <DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsChecked}" Value="False"> 
          <Setter Property="Content"> 
            <Setter.Value> 
              <Image Source="/EEBase;component/Images/Unlock_24x32.png" /> 
            </Setter.Value> 
          </Setter> 
        </DataTrigger> 
      </Style.Triggers> 
    </Style> 

如果有帮助,请告诉我。