开发者

WPF Style Triggers in DataTemplate

i hope you can help me. I got following Code in the Resources:

<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>

To me that looks all correct.

Now, the problem is: When i do the following, an exceptions occurs:

Specified element is a开发者_开发百科lready the logical child of another element. Disconnect it first.

1. load the control, selected type is CIRC

2. change the dropdown to select RECT (template triggers and togglebuttons are shown correctly)

3. change the dropdown back to CIRC

--> now the Exception occurs.

4. if i ignore the exception, the template "EditCircleTemplate" does not get loaded, and the normal ToString of the model object gets displayed.

Additional info:

originally there are 4 different types in the WPF, two of them with ToggleButtons (that's why i use templates). I cut them out, they dont differ really. But what i found out using all 4 templates is that the error does not occur when switching to a new Template, but when unloading a template with the toggle buttons. Which is kinda strange. Also if i remove the DataTriggers for the ToggleButtons everything works like a charm.

The Exception comes from the XAML-Interpreter, so the Stacktrace is not useful at all.

Can anyone give me a hint what i am doing wrong?

Edit: oops, i guess i forgot the content code:

<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/Solution:

I just found a workaround - it just does not satisfy me:

Instead of putting the style in the UserControl.Resources, which for me would be the more clean and intuitive solution, i have to set the style with the triggers on each ToggleButton separately.

So removing the and adding following code to each ToggleButton did the trick:

<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>

The big question still persists: WHY?


The problem is that if you create an Image in a style there is only one instance, so as soon as multiple controls use the style there is going to be a fight over this one instance which can only be owned by one control.

The easiest solution to this is placing the Style in a resource and setting x:Shared to false, that way a copy of the style is used whereever referenced.


Why do you need to create BitmapImages and set them as Source to your Content Images in Triggers? Why arent you using the URI source to Images directly?

    <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> 

Let me know if this helps.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜