Привязка к ширине ColumnDefinition - PullRequest
       9

Привязка к ширине ColumnDefinition

5 голосов
/ 05 сентября 2011

Мне нужна какая-то таблица для пользовательского ввода. Поэтому я создал сетку с определенными столбцами и строками. Таблица не для отображения данных, ее цель - просто структурировать входные данные.

Чтобы структурировать все элементы, такие как текстовые поля и т. Д., Я определил все столбцы с шириной. В стековой панели будет несколько совмещенных сеток.

Определения столбцов в 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 и, возможно, не понял всех понятий, поэтому, пожалуйста, дайте мне подсказку.

Спасибо заранее Бенни

EDIT:

Я попробовал намек на первый ответ. Это не работает, потому что 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();
           }
        }
    }
}

Есть еще какие-нибудь намеки? Я могу представить, что кто-то еще уже имел эту проблему.

Еще раз спасибо Benny

Ответы [ 4 ]

2 голосов
/ 05 сентября 2011

Вы очень близки, и ошибка является большой подсказкой. Вам необходимо использовать GridLengthConverter для преобразования исходного типа (System.Double) в тип GridLength (именно так определяется ширина столбца).

Попробуйте это (не проверено):

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();

Опять же, это не проверено. Дайте мне знать, как это происходит.

1 голос
/ 04 января 2012

Если все, что вам нужно сделать, это синхронизировать (разделить) размер столбца между отдельными сетками, проверяли ли вы свойство SharedSizeGroup в ColumnDefinition? Похоже, это может сделать это немного легче.

SharedSizeGroup Свойство 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>
1 голос
/ 06 сентября 2011

Я думаю, что неправильно понял вопрос, я не осознавал, что вы связываете между двумя сетками. Однако я оставил свой предыдущий ответ, так как он может быть актуальным. Стоит подумать, если вам нужно добавлять столбцы в код довольно часто, вы делаете что-то не так. Каждая ситуация отличается, хотя: -)

В любом случае, ответ на ваш вопрос заключается в том, что вам не нужен конвертер. Вы только что связали неправильное свойство в этой строке

loopIdColumn.SetBinding(Grid.WidthProperty, loopIdBinding);

просто измените это на

loopIdColumn.SetBinding(ColumnDefinition.WidthProperty, loopIdBinding);

и все это прекрасно работает.

0 голосов
/ 06 сентября 2011

Зачем вам нужно сделать это в коде позади? Я подозреваю, что если вам нужна переменная no столбцов, вы должны использовать какой-то элемент управления элементами. Вы можете сделать это примерно так:

    <ItemsControl>
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <StackPanel Orientation="Horizontal"></StackPanel>
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
    </ItemsControl>

Вы можете использовать холст в качестве шаблонной панели элементов, и я предполагаю, что вы можете использовать сетку (я сам не пробовал сетку). Затем вы определяете размер элементов, используя шаблон данных. Если это полезно, дайте мне знать, и я могу предоставить более подробную информацию.

...