是否可以在没有固定数据绑定的情况下为 GridViewColumn 创建模板?
这可能吗?
我有一个 ListView,我想为列创建一个模板,以便我标记为“cellTextBox”的每一列都显示一个文本框(并且还在 LostFocus 事件上调用 TextBox_LostFocus())。我真的很想使用单个模板,而不是为每个列定义 DockPanel 和 TextBox。但是,每一列都将绑定到数据源中的不同列。
换句话说,我想要 GridViewColumns 的“千篇一律”,它允许我为每个列指定不同的绑定路径。
我尝试过类似的事情(除其他外),但它不起作用。
有什么想法吗?
<Page.Resources>
<DataTemplate x:Key="cellTextBox">
<DockPanel>
<TextBox
LostFocus="TextBox_LostFocus"
Width="100"
Text="{Binding RelativeSource={RelativeSource Mode=TemplatedParent},Path=DisplayMemberBinding}"
/>
</DockPanel>
</DataTemplate>
</Page.Resources>
<StackPanel>
<ListView ScrollViewer.HorizontalScrollBarVisibility="Disabled"
HorizontalAlignment="Stretch"
ItemsSource="{Binding Tables[0]}"
Width="Auto"
x:Name="Service_Tasks">
<ListView.View>
<GridView>
<GridViewColumn Width="120" CellTemplate="{StaticResource cellTextBox}" DisplayMemberBinding={Binding Path=Field1} Header="Field1" />
<GridViewColumn Width="120" CellTemplate="{StaticResource cellTextBox}" DisplayMemberBinding={Binding Path=Field2} Header="Field2" />
<GridViewColumn Width="120" CellTemplate="{StaticResource cellTextBox}" DisplayMemberBinding={Binding Path=Field3} Header="Field3" />
<GridViewColumn Width="120" CellTemplate="{StaticResource cellTextBox}" DisplayMemberBinding={Binding Path=FieldN} Header="FieldN" />
<!-- ... other columns ... -->
</GridView>
</ListView.View>
</ListView>
</StackPanel>
编辑 - 我想我应该分享 @HB 解决方案的 Visual Basic 翻译,它对我有用。也许这会对其他人有所帮助。
Imports System.Windows.Markup
Public Class TemplateBuilderExtension : Inherits StaticExtension
Dim _path As String
Shared _tagpath As String
'Private TagPath As String
Shared Property TagPath As String
Get
TagPath = _tagpath
End Get
Private Set(ByVal value As String)
_tagpath = value
End Set
End Property
Property Path As String
Get
Path = _path
End Get
Set(ByVal value As String)
_path = value
End Set
End Property
Public Overrides Function ProvideValue(ByVal serviceProvider As System.IServiceProvider) As Object
TagPath = Path
Dim resourceExt = New StaticResourceExtension("TemplateBuilder_BaseTemplate")
'Dim baseTemplate As DataTemplate = DirectCast(resourceExt.ProvideValue(serviceProvider), DataTemplate)
ProvideValue = DirectCast(resourceExt.ProvideValue(serviceProvider), DataTemplate)
End Function
Public Sub New()
MyBase.new()
End Sub
Public Sub New(ByVal Path As String)
Me.Path = Path
End Sub
End Class
Public Class TemplateBuilderTagExtension : Inherits MarkupExtension
Public Sub New()
MyBase.New()
End Sub
Public Overrides Function ProvideValue(ByVal serviceProvider As System.IServiceProvider) As Object
ProvideValue = New Binding(TemplateBuilderExtension.TagPath)
End Function
End Class
显然,无论如何,XAML 都是相同的。
不要忘记将以下命名空间引用添加到根级标记:
xmlns:me="clr-namespace:WpfApplication1"
,将 WpfApplication
替换为应用程序的根命名空间是(这可以在您的应用程序的属性中找到)。
再次感谢@HB!
Is this possible?
I have a ListView and I want to create a template for the columns, so that each column that I mark as a 'cellTextBox' displays with a textbox in it (and also calls the TextBox_LostFocus() on the LostFocus event). I'd really like to use a single template rather than defining a DockPanel and TextBox for every single column. However, each column is going to be bound to a different column in the data source.
In other words, I'd like a "cookie cutter" for GridViewColumns that allows me to specify a different binding path for each one.
I tried something like this (among other things), but it doesn't work.
Any ideas?
<Page.Resources>
<DataTemplate x:Key="cellTextBox">
<DockPanel>
<TextBox
LostFocus="TextBox_LostFocus"
Width="100"
Text="{Binding RelativeSource={RelativeSource Mode=TemplatedParent},Path=DisplayMemberBinding}"
/>
</DockPanel>
</DataTemplate>
</Page.Resources>
<StackPanel>
<ListView ScrollViewer.HorizontalScrollBarVisibility="Disabled"
HorizontalAlignment="Stretch"
ItemsSource="{Binding Tables[0]}"
Width="Auto"
x:Name="Service_Tasks">
<ListView.View>
<GridView>
<GridViewColumn Width="120" CellTemplate="{StaticResource cellTextBox}" DisplayMemberBinding={Binding Path=Field1} Header="Field1" />
<GridViewColumn Width="120" CellTemplate="{StaticResource cellTextBox}" DisplayMemberBinding={Binding Path=Field2} Header="Field2" />
<GridViewColumn Width="120" CellTemplate="{StaticResource cellTextBox}" DisplayMemberBinding={Binding Path=Field3} Header="Field3" />
<GridViewColumn Width="120" CellTemplate="{StaticResource cellTextBox}" DisplayMemberBinding={Binding Path=FieldN} Header="FieldN" />
<!-- ... other columns ... -->
</GridView>
</ListView.View>
</ListView>
</StackPanel>
EDIT - I thought I would share the Visual Basic translation of @H.B.'s solution, which worked for me. Perhaps this will help out someone else.
Imports System.Windows.Markup
Public Class TemplateBuilderExtension : Inherits StaticExtension
Dim _path As String
Shared _tagpath As String
'Private TagPath As String
Shared Property TagPath As String
Get
TagPath = _tagpath
End Get
Private Set(ByVal value As String)
_tagpath = value
End Set
End Property
Property Path As String
Get
Path = _path
End Get
Set(ByVal value As String)
_path = value
End Set
End Property
Public Overrides Function ProvideValue(ByVal serviceProvider As System.IServiceProvider) As Object
TagPath = Path
Dim resourceExt = New StaticResourceExtension("TemplateBuilder_BaseTemplate")
'Dim baseTemplate As DataTemplate = DirectCast(resourceExt.ProvideValue(serviceProvider), DataTemplate)
ProvideValue = DirectCast(resourceExt.ProvideValue(serviceProvider), DataTemplate)
End Function
Public Sub New()
MyBase.new()
End Sub
Public Sub New(ByVal Path As String)
Me.Path = Path
End Sub
End Class
Public Class TemplateBuilderTagExtension : Inherits MarkupExtension
Public Sub New()
MyBase.New()
End Sub
Public Overrides Function ProvideValue(ByVal serviceProvider As System.IServiceProvider) As Object
ProvideValue = New Binding(TemplateBuilderExtension.TagPath)
End Function
End Class
Obviously, the XAML is the same, regardless.
Do not forget to add the following namespace reference to your root-level tag:
xmlns:me="clr-namespace:WpfApplication1"
, replacing WpfApplication
with whatever your application's root namespace is (this can be found in your application's properties).
Thanks again @H.B.!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我现在能想到的内联的唯一方法是使用 markup-extensions 当您尝试将多个值传递给一个属性时。
不过,将变量数据放入模板似乎并不简单,并且以下使用静态属性的方法相当麻烦,也许您可以想到更好的方法:
我尝试在获取资源时使用自定义服务提供程序,但不幸的是它确实如此没有到达标签的
ProvideValue
,这将是获取路径的更好方法。当然,您可以在
TemplateBuilderExtension
中从头开始动态创建模板,这样您就不会遇到此类问题。The only method i can think of right now to inline this is using markup-extensions as you try to pass more than one value to one property.
Getting variable data into the template seems to be non-trivial though and the following approach using a static property is quite the hack, maybe you can think of something better:
I tried to use a custom service provider when getting the resource but unfortunately it did not arrive in
ProvideValue
of the tag, that would have been a better way to get the path accross.You could of course create the template dynamically from scratch in the
TemplateBuilderExtension
, that way you will not run into such issues.