【问题标题】:Why is the TargetNullValue of a ContentControl in an ItemsControl shared between the items?为什么 ItemsControl 中 ContentControl 的 TargetNullValue 会在项目之间共享?
【发布时间】:2019-12-22 15:27:44
【问题描述】:

鉴于此 xaml:

    <ItemsControl Grid.Row="1" ItemsSource="{Binding Devices}">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <UniformGrid Rows="1" />
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <ItemsControl.ItemTemplate>
            <DataTemplate DataType="{x:Type viewModels:IDeviceViewModel}">
                <Grid>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="Auto" />
                        <RowDefinition />
                    </Grid.RowDefinitions>
                    <TextBlock Text="{Binding Name}"
                               Grid.Row="0"
                               Margin="5"
                               HorizontalAlignment="Center" />
                    <ContentControl Grid.Row="1">
                        <ContentControl.Content>
                            <Binding Path="CurrentState">
                                <Binding.TargetNullValue>
                                    <Button Command="{Binding DataContext.ActivateCommand, RelativeSource={RelativeSource AncestorType={x:Type mah:MetroWindow}}}"
                                            CommandParameter="{Binding}">
                                        <Button.Template>
                                            <ControlTemplate>
                                                <Image MaxWidth="100"
                                                       Margin="10"
                                                       HorizontalAlignment="Center"
                                                       VerticalAlignment="Center"
                                                       Source="/Resources/ActivateDevice.png" />
                                            </ControlTemplate>
                                        </Button.Template>
                                    </Button>
                                </Binding.TargetNullValue>
                            </Binding>
                        </ContentControl.Content>
                    </ContentControl>
                </Grid>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>

TargetNullValue 中定义的“激活设备”按钮仅针对列表中的最后一项显示。其他项目只是显示为空白,甚至没有数据模板的视图模型的默认“Some.Namespace.SomeViewModel”文本。我在Devices 集合中放入了什么并不重要,我总是只看到最右边(即最后一个)项目上的按钮。

我不知道为什么?

编辑:看起来TargetNullValue 只创建一次,然后为每个项目“重复使用”,因此它是从前一个项目“偷走”的。如果是这种情况,我该如何防止呢?我想为每个项目创建一个新的按钮实例。

编辑:@KeithStein 解决方案有效:

    <ItemsControl Grid.Row="1" ItemsSource="{Binding Devices}">
        <ItemsControl.Resources>
            <Button x:Key="ActivateDeviceButton"
                    x:Shared="False"
                    Command="{Binding DataContext.ActivateCommand, RelativeSource={RelativeSource AncestorType={x:Type mah:MetroWindow}}}"
                    CommandParameter="{Binding Path=DataContext, ElementName=deviceRoot}">
                <Button.Template>
                    <ControlTemplate>
                        <Image MaxWidth="100"
                               Margin="10"
                               HorizontalAlignment="Center"
                               VerticalAlignment="Center"
                               Source="/Resources/ActivateDevice.png" />
                    </ControlTemplate>
                </Button.Template>
            </Button>
        </ItemsControl.Resources>
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <UniformGrid Rows="1" />
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <ItemsControl.ItemTemplate>
            <DataTemplate DataType="{x:Type viewModels:IDeviceViewModel}">
                <Grid x:Name="deviceRoot">
                    <Grid.RowDefinitions>
                        <RowDefinition Height="Auto" />
                        <RowDefinition />
                    </Grid.RowDefinitions>
                    <TextBlock Text="{Binding Name}"
                               Grid.Row="0"
                               Margin="5"
                               HorizontalAlignment="Center" />
                    <ContentControl Grid.Row="1" Content="{Binding CurrentState, TargetNullValue={StaticResource ActivateDeviceButton}}" />
                </Grid>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>

所以现在的问题是:为什么TargetNullValue 首先是共享的?

【问题讨论】:

  • 一个想法:将Button 放入ResourceDictionaryx:Shared='False'。然后使用“StaticResource”引用资源。
  • @KeithStein 这确实有效!它还提供了简洁的语法,因为绑定可以保留为属性。然而,我真的很想了解为什么 wpf 首先要这样做。我的意思是,我希望项目控件中各个项目的数据模板能够独立实例化,它们如何共享每个项目实例内的内容控件内绑定的目标空值?
  • 太棒了。我已将其发布为您可以接受的答案。至于为什么会这样:我确实希望每个项目都有自己的 DataTemplate 实例,但也许这些属性设置的值有可能被重用?因此,每个单独的 TargetNullValue 都被分配了相同的 Button 已被解析。这适用于Strings 或其他值类型(最常用)并节省时间和内存,但会导致大多数其他类出现问题。

标签: wpf xaml data-binding itemscontrol mahapps.metro


【解决方案1】:

x:Shared 属性告诉 WPF 在每次使用 XAML 元素时创建一个新实例,但这只能在 ResourceDictionary 中的项目上设置。尝试将Buttonx:Shared='False' 一起放入ResourceDictionary,然后使用StaticResource 引用它。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-03-07
    • 1970-01-01
    • 1970-01-01
    • 2013-09-08
    • 1970-01-01
    • 2018-05-27
    • 1970-01-01
    • 2012-08-02
    相关资源
    最近更新 更多