wpf - ¿Es posible crear una plantilla para un GridViewColumn, sin enlace de datos fijo?
xaml data-binding (1)
El único método en el que puedo pensar ahora para incorporar esto es usar markup-extensions mientras intentas pasar más de un valor a una propiedad.
Sin embargo, la obtención de datos variables en la plantilla parece no ser trivial, y el siguiente enfoque con una propiedad estática es bastante complicado, tal vez se te ocurra algo mejor:
<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);
}
}
Traté de usar un proveedor de servicios personalizado al obtener el recurso, pero desafortunadamente no llegó en ProvideValue
de la etiqueta, esa habría sido una mejor manera de cruzar la ruta.
Por supuesto, puede crear la plantilla dinámicamente desde cero en TemplateBuilderExtension
, de esa manera no se encontrará con tales problemas.
es posible?
Tengo un ListView y quiero crear una plantilla para las columnas, de modo que cada columna que marque como ''cellTextBox'' se muestre con un cuadro de texto (y también llame a TextBox_LostFocus () en el evento LostFocus). Realmente me gustaría utilizar una única plantilla en lugar de definir un DockPanel y un TextBox para cada columna. Sin embargo, cada columna se vinculará a una columna diferente en la fuente de datos.
En otras palabras, me gustaría un "cortador de galletas" para GridViewColumns que me permita especificar una ruta de enlace diferente para cada uno.
Intenté algo como esto (entre otras cosas), pero no funciona.
¿Algunas 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>
EDITAR - Pensé que compartiría la traducción de Visual Basic de la solución de @ HB, que funcionó para mí. Quizás esto ayudará a alguien más.
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
Obviamente, el XAML es el mismo, independientemente.
No olvide agregar la siguiente referencia de espacio de nombres a su etiqueta de nivel raíz:
xmlns:me="clr-namespace:WpfApplication1"
, reemplazando WpfApplication
con el espacio de nombres raíz de la aplicación (esto se puede encontrar en las propiedades de la aplicación).
Gracias de nuevo @HB!