Триггеры стиля WPF в шаблоне данных - PullRequest
0 голосов
/ 22 августа 2011

Я надеюсь, что вы можете мне помочь.Я получил следующий код в ресурсах:

<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 (триггеры шаблона и кнопки переключения отображаются правильно)
3. измените раскрывающийся список обратно наCIRC
-> теперь возникает исключение.
4. если я игнорирую исключение, шаблон "EditCircleTemplate" не загружается, и отображается обычная ToString объекта модели.

Дополнительная информация:
изначально в WPF есть 4 различных типа, два из которых с ToggleButtons (поэтому я использую шаблоны).Я вырезал их, они действительно не отличаются.Но я обнаружил, что, используя все 4 шаблона, ошибка возникает не при переключении на новый шаблон, а при выгрузке шаблона с помощью переключателей .Что странно.Также, если я удаляю DataTriggers для ToggleButtons, все работает как шарм.
Исключение исходит от XAML-интерпретатора, поэтому 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 / Solution:
Я только что нашел обходной путь -это просто не удовлетворяет меня:
Вместо того, чтобы помещать стиль в 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 ]

1 голос
/ 22 августа 2011

Проблема в том, что если вы создаете Image в стиле, то есть только один экземпляр, поэтому, как только несколько элементов управления будут использовать стиль, будет борьба за этот один экземпляр, который может принадлежать только одномуcontrol.

Самым простым решением этого является размещение стиля в ресурсе и установка x:Shared в значение false, чтобы копия стиля использовалась там, где на нее ссылаются.

0 голосов
/ 22 августа 2011

Зачем вам нужно создавать 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> 

Дайте мне знать, если это поможет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...