我想创建一个仅显示适合该控件范围的项目的控件。为此,我创建了自己的面板,该面板继承自StackPanel
,并覆盖了ArrangeOverride
过程。在那里,我让默认的StackPanel
进行排列,然后我检测到不适合面板边界的项目并将其隐藏。就像魅力一样。
现在,我想知道某个项目是否由于不适合面板的边界而被隐藏。为此,我创建了一个附加属性,在隐藏项目的情况下将其设置为True
。然后将视图模型中的属性绑定到此附加属性。但无论物品是否已隐藏,我都无法获得信息。
为简单起见,我创建了一个小示例项目来显示我的问题,但没有所有开销。
我希望你们中的一个能弄清楚为什么我没有得到我想要的信息。
这是我的StackPanel
。在第二个项目中,类型为String
的附加属性“测试”被设置为“已填充”,否则默认值为“空”。
Public Class StackPanelEx
Inherits StackPanel
Public Shared TestProperty As DependencyProperty = DependencyProperty.RegisterAttached("Test", GetType(String), GetType(StackPanelEx), New FrameworkPropertyMetadata("Empty"))
Public Shared Function GetTest(ByVal d As DependencyObject) As String
Return d.GetValue(StackPanelEx.TestProperty)
End Function
Public Shared Sub SetTest(ByVal d As DependencyObject, ByVal value As String)
d.SetValue(StackPanelEx.TestProperty, value)
End Sub
Protected Overrides Function ArrangeOverride(finalSize As Size) As Size
Dim result As Size
Dim index As Integer
result = MyBase.ArrangeOverride(finalSize)
For Each child As UIElement In MyBase.InternalChildren
index += 1
If (index Mod 2) = 0 Then
StackPanelEx.SetTest(child, "Filled")
End If
Next child
Return result
End Function
End Class
这是我的ItemViewModel,简单明了:
Imports System.ComponentModel
Public Class ItemViewModel
Implements INotifyPropertyChanged
Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
Protected Sub OnPropertyChanged(propertyName As String)
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
End Sub
Private _caption As String
Public Property Caption As String
Get
Return _caption
End Get
Set(value As String)
_caption = value
Me.OnPropertyChanged(NameOf(Me.Caption))
End Set
End Property
End Class
这是我的MainViewModel,其中包含ItemViewModels的集合:
Imports System.Collections.ObjectModel
Imports System.ComponentModel
Public Class MainViewModel
Implements INotifyPropertyChanged
Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
Protected Sub OnPropertyChanged(propertyName As String)
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
End Sub
Private ReadOnly _items As ObservableCollection(Of ItemViewModel)
Public Sub New()
_items = New ObservableCollection(Of ItemViewModel)
_items.Add(New ItemViewModel With {.Caption = "Item 1"})
_items.Add(New ItemViewModel With {.Caption = "Item 2"})
_items.Add(New ItemViewModel With {.Caption = "Item 3"})
_items.Add(New ItemViewModel With {.Caption = "Item 4"})
_items.Add(New ItemViewModel With {.Caption = "Item 5"})
End Sub
Public ReadOnly Property Items As ObservableCollection(Of ItemViewModel)
Get
Return _items
End Get
End Property
End Class
最后是我的MainWindow,您可能必须调整“本地”名称空间:
<Window x:Class="MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApp4"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.DataContext>
<local:MainViewModel />
</Window.DataContext>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<ItemsControl Grid.Column="0"
ItemsSource="{Binding Items}"
MinWidth="50">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Caption}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<ItemsControl Grid.Column="1"
ItemsSource="{Binding Items}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<local:StackPanelEx Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Content="{Binding Caption}" Margin="2" local:StackPanelEx.Test="{Binding Caption, Mode=OneWayToSource}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</Window>
所有项目的标题都显示为“空”,因此我附加属性的默认值有效。但是我希望第二个项目都显示标题“ Filled”(因为在我的面板的ArrangeOverride
中设置了附加属性的值)。
Snoop告诉我,我附加的属性的值确实在第二个项目中都是“已填充”,因此绑定似乎有问题。
我不知道哪里出了问题。
答案 0 :(得分:1)
ItemTemplate中的Button不是StackPanelEx的直接子项,而该子项用作ItemsPanel,因此从不在Button上设置附加属性。
ItemsControl创建一个ContentPresenter
作为 item容器元素,该元素的ContentTemplate
属性设置为ItemTemplate
。
将绑定移动到ItemContainerStyle
:
<ItemsControl ...>
...
<ItemsControl.ItemContainerStyle>
<Style TargetType="ContentPresenter">
<Setter Property="local:StackPanelEx.Test"
Value="{Binding Caption, Mode=OneWayToSource}"/>
</Style>
</ItemsControl.ItemContainerStyle>
</ItemsControl>