【问题标题】:Is it possible to create a template for a GridViewColumn, without fixed data binding?是否可以在没有固定数据绑定的情况下为 GridViewColumn 创建模板?
【发布时间】:2011-11-02 09:37:19
【问题描述】:

这可能吗?

我有一个 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>

编辑 - 我想我会分享 @H.B. 解决方案的 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 替换为应用程序的根命名空间(可以在应用程序的属性中找到)。

再次感谢@H.B.!

【问题讨论】:

    标签: wpf xaml data-binding datatemplate


    【解决方案1】:

    我现在能想到的唯一内联方法是使用markup-extensions,因为您尝试将多个值传递给一个属性。

    将变量数据放入模板似乎并不简单,以下使用静态属性的方法是相当的 hack,也许您可​​以想出更好的方法:

    <ListView ItemsSource="{Binding Data}">
        <ListView.Resources>
            <!-- x:Shared="False" because otherwise the Tag extension is only evaluated the first time the resource is accessed -->
            <DataTemplate x:Shared="false" x:Key="TemplateBuilder_BaseTemplate">
                <TextBox Text="{me:TemplateBuilderTag}" Width="100" LostFocus="TextBox_LostFocus" />
            </DataTemplate>
        </ListView.Resources>
        <ListView.View>
            <GridView>
                <GridViewColumn CellTemplate="{me:TemplateBuilder Name}"  />
                <GridViewColumn CellTemplate="{me:TemplateBuilder Occupation}" />
            </GridView>
        </ListView.View>
    </ListView>
    
    public class TemplateBuilderExtension : MarkupExtension
    {
        public string Path { get; set; }
    
        public TemplateBuilderExtension() { }
        public TemplateBuilderExtension(string path)
        {
            Path = path;
        }
    
        // Here be dirty hack.
        internal static string TagPath { get; private set; }
    
        public override object ProvideValue(IServiceProvider serviceProvider)
        {
            TagPath = Path;
            var resourceExt = new StaticResourceExtension("TemplateBuilder_BaseTemplate");
            // This line causes the evaluation of the Tag as the resource is loaded.
            var baseTemplate = resourceExt.ProvideValue(serviceProvider) as DataTemplate;
            return baseTemplate;
        }
    }
    
    public class TemplateBuilderTagExtension : MarkupExtension
    {
        public override object ProvideValue(IServiceProvider serviceProvider)
        {
            return new Binding(TemplateBuilderExtension.TagPath);
        }
    }
    

    我在获取资源时尝试使用自定义服务提供者,但不幸的是它没有到​​达标签的ProvideValue,这将是获取路径的更好方法。

    您当然可以在TemplateBuilderExtension 中从头开始动态创建模板,这样您就不会遇到此类问题。

    【讨论】:

    • +1 这看起来很有希望。我今晚会试试,因为我现在没有我的代码。我有点惊讶 XAML 提供了模板控件的方法,但没有像 GridViewColumn 这样的元素,它们不是可视元素,但似乎会经常使用。我错过了什么明显的东西吗?对于这些类型的列表,我是否应该使用 ListView 之外的其他东西(请记住,这个项目在 3.5 中)?
    • @transistor1:嗯,ListView 是一个视图,它可能不是用来编辑的,你可以使用 WPF 工具包中的 DataGrid。
    • 快速提问:public string Path { get; set; } 行是否意味着 Path 属性未在内部存储(即未实现 get 和 set)?还是它是默认属性实现?我比较习惯VB,虽然我做过一些基本的C#编码,所以我正在翻译它。
    • ...很确定这是一个默认的属性实现。
    • @transistor1:这称为auto-implemented property,只是私有支持字段和公开它的公共属性的简写。当然不能以这种方式直接访问该字段...
    猜你喜欢
    • 2021-04-07
    • 2011-05-08
    • 2018-01-23
    • 2013-08-21
    • 2014-06-16
    • 2018-05-22
    • 2011-04-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多