Проблема привязки ActualWidth на динамически заполненной сетке - PullRequest
2 голосов
/ 13 сентября 2011

Рассмотрим следующий простой код:


XAML:

<Grid Height="60" Name="grid">
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="162*" />
        <ColumnDefinition x:Name="coltest" Width="316*" />
        <ColumnDefinition Width="239*" />
    </Grid.ColumnDefinitions>
</Grid>
<Label MouseDoubleClick="TextBox_MouseDoubleClick" 
    Content="{Binding ElementName=coltest, Path=ActualWidth}" Grid.Row="1"/>

Событие MouseDoubleClick:

private void TextBox_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
    grid.RowDefinitions.Add(new RowDefinition());
    for (int i = 0; i < grid.ColumnDefinitions.Count; i++)
    {
        Random r = new Random();
        Label l = new Label { Content = r.Next(10, 1000000000).ToString() };
        grid.Children.Add(l);
        Grid.SetRow(l, grid.RowDefinitions.Count - 1);
        Grid.SetColumn(l, i);
    }
}

Моя метка содержит свойство ActualWidth второго столбца через привязку.В Visual Studio я вижу свою метку, содержащую значение 316. Таким образом, привязка работает.

Двойной щелчок по метке вызывает его событие и добавляет в сетку дополнительную строку со случайной длиной.

Я ожидаю увидеть новое значение на моем ярлыке, но (вычисленное во время выполнения) 0 не изменится!

Чего мне здесь не хватает?

1 Ответ

4 голосов
/ 13 сентября 2011

Основная проблема в том, что ActualWidth из ColumnDefinition не является свойством зависимости и не реализует INotifyPropertyChanged, поэтому Binding не может знать, что ActualWidth coltest изменилось.

Вам нужно будет явно обновить Binding

Edit2: В этом случае вы можете обновить Binding в событии SizeChanged для Grid, поскольку Columns имеют * ширину. Это не будет работать на 100% с шириной Auto, хотя ширина будет меняться в зависимости от элементов в ColumnDefinition

<Grid Name="grid"
      SizeChanged="grid_SizeChanged">
    <!--...-->
</Grid>

Обработчик событий

void grid_SizeChanged(object sender, SizeChangedEventArgs e)
{
    BindingExpression be = label.GetBindingExpression(Label.ContentProperty);
    be.UpdateTarget();
}

Редактировать: Внесены небольшие изменения в Xaml. Это будет обновлять Binding каждый раз, когда вы дважды нажимаете первый Label

<Grid Name="grid">
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="162*" />
        <ColumnDefinition x:Name="coltest" Width="316*" />
        <ColumnDefinition Width="239*" />
        <ColumnDefinition Width="239*" />
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
    </Grid.RowDefinitions>
    <Label MouseDoubleClick="TextBox_MouseDoubleClick"
           Name="label"
           Content="{Binding ElementName=coltest, Path=ActualWidth}" Grid.Row="0"/>
</Grid>

Обработчик событий

private void TextBox_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
    grid.RowDefinitions.Add(new RowDefinition());
    for (int i = 0; i < grid.ColumnDefinitions.Count; i++)
    {
        Random r = new Random();
        Label l = new Label { Content = r.Next(10, 1000000000).ToString() };
        grid.Children.Add(l);
        Grid.SetRow(l, grid.RowDefinitions.Count - 1);
        Grid.SetColumn(l, i);
    }
    BindingExpression be = label.GetBindingExpression(Label.ContentProperty);
    be.UpdateTarget();
}
...