WPF绑定到网格列宽度

10

我正在尝试将我的一个用户控件中的DependancyProperty绑定到GridColumnWidth属性。

我的代码类似于这样:

<Grid x:Name="MyGridName">
    <Grid.ColumnDefinitions>
        <ColumnDefinition x:Name="TitleSection" Width="100" />
        <ColumnDefinition Width="*" />
    </Grid.ColumnDefinitions>

    <Grid.RowDefinitions>...</Grid.RowDefinitions>

    <GridSplitter x:Name="MyGridSplitter" Grid.Row="0" Grid.Column="0" ... />
</Grid>

在一个独立的Usercontrol中,我定义了以下的DependancyProperty
public static readonly DependencyProperty TitleWidthProperty = DependencyProperty.Register("TitleWidth", typeof(int), typeof(MyUserControl));

public int TitleWidth
{
    get { return (int)base.GetValue(TitleWidthProperty); }
    set { base.SetValue(TitleWidthProperty, value); }
}

我正在编写代码创建用户控件实例,因此我有一个类似于以下绑定语句:

MyUserControl Cntrl = new MyUserControl(/* Construction Params */);
BindingOperations.SetBinding(Cntrl , MyUserControl.AnotherProperty, new Binding { ElementName = "objZoomSlider", Path = new PropertyPath("Value"), Mode = BindingMode.OneWay });
BindingOperations.SetBinding(Cntrl , MyUserControl.TitleWidthProperty, new Binding { ElementName = "TitleSection", Path = new PropertyPath("ActualWidth"), Mode = BindingMode.OneWay });
/* Other operations on Cntrl */

第一个定义的绑定非常有效,虽然它是绑定到实际的UIElement(在这种情况下是Slider),但是对“TitleSection”进行的绑定(这是在Grid中定义的ColumnDefinition)失败了。在代码中设置断点并在“TitleSection”上进行监视会返回预期的对象。
我开始怀疑x:Name'd ColumnDefinition不能被绑定。有人能建议我如何能够绑定到网格中第一列的可变宽度吗?
编辑#1 - 回答评论
数据绑定“失败”的意思是,在TitleWidth属性的setter上设置断点,并使用GridSplitter控件调整第一列的大小时,断点永远不会命中。此外,当DependancyProperty TitleWidth更改时,我希望执行的代码也没有被执行。
用户控件在Window_Loaded函数中创建并添加到Grid中的Stackpanel中。我希望在构建Usercontrols时,Grid已经被渲染出来。当它们正在构建/绑定发生之前,肯定可以监视到x:Name'd元素TitleSection并且其值为100
编辑#2 - 可能与此有关?
我一直在 MSDN 页面上查找 Grid ColumnDefinition 文档,并发现了 GridLength(),但我不知道如何在绑定表达式中使用它。我无法在绑定代码中使用相关的 GridLengthConverter 作为转换器,因为它不是从 IValueConverter 派生的。
我正在考虑以某种方式绑定到 Grid 对象中一个单元格的 ActualWidth 属性。这似乎不如绑定到列定义干净,但目前我无法让其正常工作。

失败在哪里,你是在什么时候创建用户控件的?网格已经显示了吗? - Donnelle
你不能依赖于在依赖属性的set/get中设置断点,因为它们永远不会被绑定引擎使用。在内部,依赖属性是使用SetValue(DependencyProperty, value)进行设置的。 - Ian Oakes
3个回答

11

我的一个解决方案有点拙劣,但我会解释如何做:

基本上,我有一个两列、多行的网格,在第一列右侧对齐了一个分割器,以便用户可以调整大小,以适应其中包含的内容。为了使事情复杂化,我在某些行中通过编程方式加载了一个用户控件,该控件具有用于呈现目的的2个列跨度(内容从一个单元格流到下一个单元格)。

当第一列被调整大小时,我需要将此反映在用户控件中。首先我尝试绑定到ColumnDefinition,但它并没有起作用。

我是如何解决/拙劣处理的

在第一列的一个空单元格中,我添加了一个<Label>并为其添加了一个x:Name,以使其可访问。由于它在单元格中,因此具有“Stretch”的默认属性,并完全填充该单元格。使用Label的ActualWidth属性进行绑定意味着对列大小的更改正确地传达给了我跨越列的用户控件的DependancyProperty。

思考

显然,尽管ColumnDefinition具有ActualWidth属性,但当它更改时,似乎不会在内部触发PropertyChanged事件(这是我的最佳猜测)。这可能是一个bug,或者是有意设计的,但对我来说,这意味着我必须使用不太干净的解决方案。


1
这对我来说很有效。我有一个小小的变化:<!-- 将另一个元素的宽度属性绑定到此矩形的ActualWidth,以自动调整为最左侧列的实际宽度 --> <Rectangle x:Name="Column0WidthRect" Width="100" Grid.Row="0" Grid.Column="0"/> - Foredecker

5

ColumnDefinition.Width不是整数 - 它是一个GridLength。 您不能直接将GridLength绑定到整数,您需要使用转换器。

这也是为什么您不能将任何控件的宽度属性(double)直接绑定到ColumnDefinition的宽度属性(GridLength)而不使用转换器的原因。


3

您尝试过在xaml中设置绑定吗?以下内容应该对您有帮助。

<ColumnDefinition 
    x:Name="TitleSection" 
    Width="{Binding 
                Path=TitleWidth, 
                RelativeSource={RelativeSource AncestorType=MyUserControl}}" 
    />

否则,从你提供的绑定代码来看,我觉得绑定方向是错误的,绑定的目标应该是网格列,源应该是你的依赖属性。
上述XAML的等效代码是:
BindingOperations.SetBinding(TitleSection, ColumnDefinition.WidthProperty,
    new Binding()
    {
        RelativeSource= new RelativeSource(RelativeSourceMode.FindAncestor, typeof(MyUserControl),1),
        Path = new PropertyPath("TitleWidth"),
    });

相关的是,使用GridSplitter并绑定Width属性是互斥的。一旦你使用分隔器调整列宽度,你的绑定将被分隔器的值所替代。

这类似于更新任何绑定目标属性时会遇到的情况。当你在代码中直接设置目标值时,实际上是用你提供的值替换了绑定对象。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接