绑定到ColumnDefinition的宽度
本文关键字:ColumnDefinition 绑定 | 更新日期: 2023-09-27 18:07:38
我需要某种表格用于用户输入。所以我创建了一个定义了列和行的网格。这个表不是用来显示数据的,它的目的只是构造输入。
构造所有元素,如文本框等。我用宽度定义了所有列。在stackpanel中会有几个网格对齐。
XAML中的列定义如下:<Grid.ColumnDefinitions>
<ColumnDefinition x:Name="widthLoopID" Width="55" />
</Grid.ColumnDefinition>
我参考了其他网格,如:
<Grid.ColumnDefinitions>
<ColumnDefinition Width="{Binding ElementName=widthLoopID, Path=Width}" />
</GridColumnDefinition>
效果很好。
现在是困难的部分。我如何在代码隐藏中做到这一点?
我试了如下:
// define columns
ColumnDefinition loopIdColumn = new ColumnDefinition();
// setup databinding for columns
Binding loopIdBinding = new Binding();
// set binding for width
loopIdBinding.ElementName = "widthLoopID";
loopIdBinding.Path = new PropertyPath("Width");
loopIdColumn.SetBinding(Grid.WidthProperty, loopIdBinding);
// add definition of column
loopGrid.ColumnDefinitions.Add(loopIdColumn);
但是当执行时,我得到以下错误
System.Windows.Data Error: 1 : Cannot create default converter to perform 'one-way' conversions between types 'System.Windows.GridLength' and 'System.Double'. Consider using Converter property of Binding. BindingExpression:Path=Width; DataItem='ColumnDefinition' (HashCode=37457626); target element is 'ColumnDefinition' (HashCode=7871588); target property is 'Width' (type 'Double')
System.Windows.Data Error: 5 : Value produced by BindingExpression is not valid for target property.; Value='55' BindingExpression:Path=Width; DataItem='ColumnDefinition' (HashCode=37457626); target element is 'ColumnDefinition' (HashCode=7871588); target property is 'Width' (type 'Double')
所以我需要转换"宽度",但我如何做到这一点,为什么不能由默认的转换器执行,因为它在XAML?
我对WPF很陌生,可能不是每个概念都理解,所以请给我一个提示。
提前感谢本尼
编辑:我尝试了第一个答案的暗示。它不起作用,因为GridLengthConverter不是来自类型IValueConverter。所以我写了一个DoubleToGridLengthConverter,它将GridLength转换为Double,反之亦然。
现在值被转换了,但结果与代码在XAML中所做的结果不同。我有一种感觉,从代码后面看,它根本不起作用。真的奇怪。
下面是转换器的代码:
using System;
using System.Windows;
using System.Windows.Data;
using System.Windows.Media;
using System.Globalization;
using System.Diagnostics;
namespace editor
{
[ValueConversion(typeof(Double), typeof(GridLength))]
class DoubleToGridLengthConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
// check whether a value is given
if (value != null)
{
Debug.WriteLine("value is: " + value + " type: " + value.GetType());
return (Double)((GridLength)(value)).Value;
}
else
{
throw new ValueUnavailableException();
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
// check whether a value is given
if (value != null)
{
return new GridLength((Double)value);
}
else
{
throw new ValueUnavailableException();
}
}
}
}
有进一步的提示吗?我可以想象别人已经遇到过这个问题了。
再次感谢本尼
你很接近了,这个错误是一个很大的提示。您需要使用GridLengthConverter将原始类型(System.Double
)转换为GridLength
类型(这就是定义的列宽度)。
Try this(未经测试):
loopIdBinding.Converter = new System.Windows.GridLengthConverter();
事实上,这应该是你所要做的。这应该告诉绑定通过转换器运行该值以获得所需的类型。
编辑
所以是的,GridLengthConverter
不是IValueConverter
所以你不能这样做。相反,您需要创建一个实现IValueConverter
的新类,如下所示:
public class GridLengthValueConverter : IValueConverter
{
GridLengthConverter _converter = new GridLengthConverter();
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return _converter.ConvertFrom(value);
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return _converter.ConvertTo(value, targetType);
}
}
…然后将它的一个新实例指定为您的转换器:
loopIdBinding.Converter = new System.Windows.GridLengthConverter();
这也是未经测试的。
我想我误解了这个问题,我没有意识到你在2个网格之间绑定。然而,我留下了我之前的答案,因为它可能是相关的。如果您经常需要在代码中添加列,那么这是值得考虑的。每个情况都是不同的:-)
无论如何,你的问题的答案是,你的不需要一个转换器。在 这行中,您刚刚绑定了错误的属性loopIdColumn.SetBinding(Grid.WidthProperty, loopIdBinding);
改成
loopIdColumn.SetBinding(ColumnDefinition.WidthProperty, loopIdBinding);
一切正常
如果你需要做的只是同步(共享)跨不同网格的列大小,你检查了ColumnDefinition上的SharedSizeGroup属性吗?听起来可能会让事情变得简单一些。
sharesizegroup属性MSDN
MSDN代码示例链接:
<StackPanel>
<Grid ShowGridLines="True" Margin="0,0,10,0">
<Grid.ColumnDefinitions>
<ColumnDefinition SharedSizeGroup="FirstColumn"/>
<ColumnDefinition SharedSizeGroup="SecondColumn"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" SharedSizeGroup="FirstRow"/>
</Grid.RowDefinitions>
<Rectangle Fill="Silver" Grid.Column="0" Grid.Row="0" Width="200" Height="100"/>
<Rectangle Fill="Blue" Grid.Column="1" Grid.Row="0" Width="150" Height="100"/>
<TextBlock Grid.Column="0" Grid.Row="0" FontWeight="Bold">First Column</TextBlock>
<TextBlock Grid.Column="1" Grid.Row="0" FontWeight="Bold">Second Column</TextBlock>
</Grid>
<Grid ShowGridLines="True">
<Grid.ColumnDefinitions>
<ColumnDefinition SharedSizeGroup="FirstColumn"/>
<ColumnDefinition SharedSizeGroup="SecondColumn"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" SharedSizeGroup="FirstRow"/>
</Grid.RowDefinitions>
<Rectangle Fill="Silver" Grid.Column="0" Grid.Row="0"/>
<Rectangle Fill="Blue" Grid.Column="1" Grid.Row="0"/>
<TextBlock Grid.Column="0" Grid.Row="0" FontWeight="Bold">First Column</TextBlock>
<TextBlock Grid.Column="1" Grid.Row="0" FontWeight="Bold">Second Column</TextBlock>
</Grid>
</StackPanel>
为什么需要在后面的代码中这样做?我怀疑,如果你需要一个变量没有列,那么你应该使用某种类型的项目控制。你可以这样做:
<ItemsControl>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"></StackPanel>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
你可以使用画布作为你的itemspaneltemplate,我假设你可以使用网格(我自己没有尝试过网格)。然后使用数据模板调整项的大小。如果这是有用的,请告诉我,我可以提供更多的细节。