为什么项目之间共享 ItemsControl 中的 ContentControl 的 TargetNullValue?
Why is the TargetNullValue of a ContentControl in an ItemsControl shared between the items?
鉴于此 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
中定义的 "Activate-Device" 按钮仅针对列表中的最后一项显示。其他项目只是显示为空白,甚至没有没有数据模板的视图模型的默认 "Some.Namespace.SomeViewModel" 文本。不管我在 Devices
集合中放入什么,我总是只看到最右边(即最后一个)项目上的按钮。
我不知道为什么?
编辑:看起来 TargetNullValue
只创建了一次,然后为每个项目创建了 "reused",因此它是前一个项目的 "stolen"。如果是这样,我该如何防止呢?我想为每个项目创建一个新的按钮实例。
编辑:@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
首先共享?
x:Shared
属性告诉 WPF 在每次使用 XAML 元素时创建一个新实例,但这只能在 ResourceDictionary
中的项目上设置。尝试将 Button
放入带有 x:Shared='False'
的 ResourceDictionary
中,然后使用 StaticResource
.
引用它
鉴于此 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
中定义的 "Activate-Device" 按钮仅针对列表中的最后一项显示。其他项目只是显示为空白,甚至没有没有数据模板的视图模型的默认 "Some.Namespace.SomeViewModel" 文本。不管我在 Devices
集合中放入什么,我总是只看到最右边(即最后一个)项目上的按钮。
我不知道为什么?
编辑:看起来 TargetNullValue
只创建了一次,然后为每个项目创建了 "reused",因此它是前一个项目的 "stolen"。如果是这样,我该如何防止呢?我想为每个项目创建一个新的按钮实例。
编辑:@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
首先共享?
x:Shared
属性告诉 WPF 在每次使用 XAML 元素时创建一个新实例,但这只能在 ResourceDictionary
中的项目上设置。尝试将 Button
放入带有 x:Shared='False'
的 ResourceDictionary
中,然后使用 StaticResource
.