wpf - WPF - 重用具有不同绑定的模板
问题描述
为什么不关闭这个问题?
请不要关闭问题:建议的链接不包含答案,因为其中没有Binding
属性DataGridTemplateColumn
,我找不到将数据绑定到它的方法。
似乎可以Text={Binding}
在数据模板中使用,这是答案的“一半”
原始问题
我是WPF的新手。
我有一个DataGrid
我想为某些列提供特定模板的地方,但所有模板都是相同的。
例如
<DataGrid ItemsSource="{Binding Items}" AutoGenerateColumns="False" CanUserAddRows="False">
<DataGrid.Columns>
<!-- first column is a standard column, ok-->
<DataGridTextColumn Header="First Column" Binding="{Binding FirstColumn}"/>
<!-- a few of the other columns use a custom template-->
<DataGridTemplateColumn Header="Second Column">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBox Text="{Binding SecondColumn, UpdateSourceTrigger=PropertyChanged}"/
<OtherThings />
<OtherThings />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<More Columns Exactly like the above, with different bindings/>
<!-- Column3 Binding={Binding Column3}-->
<!-- Column4 Binding={Binding Column4}-->
</DataGrid.Columns>
</DataGrid>
如何以可以设置此模板绑定的方式将模板创建为静态资源?
我试图创建一个静态资源,如
<DataTemplate x:Key="ColumnTemplate">
<TextBox Text={I have no idea what to put here}/>
<OtherThings/>
<OtherThings/>
<DataTemplate>
并像使用它一样
<DataGrid>
<DataGrid.Columns>
<!-- Where does the Header go?, where does the binding go?-->
<!-- binds to column 2-->
<DataGridTemplateColumn CellTemplate="{StaticResource ColumnTemplate}">
<!-- binds to column 3-->
<DataGridTemplateColumn CellTemplate="{StaticResource ColumnTemplate}">
</DataGrid.Columns>
</DataGrid>
但我真的不知道如何正确地从项目绑定到模板内的文本框。
我怎样才能做到这一点?
解决方案
原则上,您可以这样做。不过,这是否是一个好计划还有待商榷。
您可以更改单元格模板以将列与其他标记绑定的任何内容包围起来。这似乎是你想要的。
如果您允许在数据网格中进行编辑,则数据网格会将单元格的内容从文本块切换到文本框,这有一些微妙之处。除了琐碎的要求之外,这对于任何事情都是不可取的 - 但这可能是一个不同的主题。
在数据网格或父资源中:
<Window.Resources>
<Style x:Key="StringStyle" TargetType="{x:Type DataGridCell}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridCell}">
<StackPanel>
<ContentControl>
<ContentPresenter/>
</ContentControl>
<TextBlock Text="A constant string"/>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
然后,您可以将其应用于列:
<DataGridTextColumn Header="Date" Binding="{Binding DT, StringFormat=\{0:dd:hh:mm:ss.FF\}}"
CellStyle="{StaticResource StringStyle}"
正如我上面提到的。当您单击单元格进行编辑时,可能会发生奇怪的事情。您可能还希望代码专注于 contentpresenter 中的文本框。
如果您想减少重复代码,则可以使用 xamlreader 使用模板动态构建列。
如果您可能只有 3 列相同,那么这可能是矫枉过正,但主要是复制粘贴。
我建立了一个示例来说明这一点:
https://gallery.technet.microsoft.com/WPF-Dynamic-XAML-Awkward-41b0689f
该示例构建了月份数据的移动选择。
相关代码在主窗口中
private void Button_Click(object sender, RoutedEventArgs e)
{
// Get the datagrid shell
XElement xdg = GetXElement(@"pack://application:,,,/dg.txt");
XElement cols = xdg.Descendants().First(); // Column list
// Get the column template
XElement col = GetXElement(@"pack://application:,,,/col.txt");
DateTime mnth = DateTime.Now.AddMonths(-6);
for (int i = 0; i < 6; i++)
{
DateTime dat = mnth.AddMonths(i);
XElement el = new XElement(col);
// Month in mmm format in header
var mnthEl = el.Descendants("TextBlock")
.Single(x => x.Attribute("Text").Value.ToString() == "xxMMMxx");
mnthEl.SetAttributeValue("Text", dat.ToString("MMM"));
string monthNo = dat.AddMonths(-1).Month.ToString();
// Month as index for the product
var prodEl = el.Descendants("TextBlock")
.Single(x => x.Attribute("Text").Value == "{Binding MonthTotals[xxNumxx].Products}");
prodEl.SetAttributeValue("Text",
"{Binding MonthTotals[" + monthNo + "].Products}");
// Month as index for the total
var prodTot = el.Descendants("TextBlock")
.Single(x => x.Attribute("Text").Value == "{Binding MonthTotals[xxNumxx].Total}");
prodTot.SetAttributeValue("Text",
"{Binding MonthTotals[" + monthNo + "].Total}");
cols.Add(el);
}
string dgString = xdg.ToString();
ParserContext context = new ParserContext();
context.XmlnsDictionary.Add("", "http://schemas.microsoft.com/winfx/2006/xaml/presentation");
context.XmlnsDictionary.Add("x", "http://schemas.microsoft.com/winfx/2006/xaml");
DataGrid dg = (DataGrid)XamlReader.Parse(dgString, context);
Root.Children.Add(dg);
}
private XElement GetXElement(string uri)
{
XDocument xmlDoc = new XDocument();
var xmltxt = Application.GetContentStream(new Uri(uri));
string elfull = new StreamReader(xmltxt.Stream).ReadToEnd();
xmlDoc = XDocument.Parse(elfull);
return xmlDoc.Root;
}
col.txt 文件包含列的所有“标准”标记。然后将其作为 xml 操作以替换值。
然后使用 xamlreader.parse 将结果转换为 wpf ui 对象
然后再次。
可能为一个需求而过度设计的只有几列。
推荐阅读
- python - 我如何判断 vmware 上的 pyvmomi 造成的压力是什么?
- r - Shiny App 的 RStudio DT DataTables 包出现 Ajax 错误
- c++ - 对重载函数 find_first_not_of 的模糊调用
- python - 如果块中的标签出现 Tkinter 问题
- batch-file - 如何在 Windows 10 上的批处理块中使用 ~dp0
- python - 陷入 Python Zybook 挑战问题
- java - [Ljava.lang.String; 不能转换为 java.lang.String
- kubernetes - 尽管创建了入口资源,但未创建 GCE LoadBalancer
- html - CSS - 为列表项添加填充无法正常工作
- python - Python pandas - 显示同一列值之间的关系