Как изменить размер панели сетки WPF таким образом?

У меня есть это довольно простое окно с сеткой, содержащей два столбца, TextBlock и TextBox.

введите здесь описание изображения

Что мне нужно, чтобы установить для столбца 0 автоматический размер его содержимого и чтобы столбец 1 (содержимое) был в 4 раза больше размера столбца 0.

Как мне это сделать. Я создам потомка Grid, если это решение, потому что мне действительно нужна эта функция.

Изменить: дополнительные пояснения. Содержимое столбца 0 не изменится во время выполнения, поэтому размер столбца 0 или столбца 1 не должен изменяться во время выполнения. Сетка будет дочерним элементом окна, настроенного с помощью SizeToContent="WidthAndHeight", поэтому не должно быть дополнительного пространства.

Ответ Дмитрию: я попробовал то, что вы говорите, со следующим кодом, и он вообще не работает:

<Window x:Class="UnderstandSizing.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" 
SizeToContent="WidthAndHeight" >
<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width=".25*" />
        <ColumnDefinition Width=".75*" />
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto" />
    </Grid.RowDefinitions>
    <TextBlock Grid.Column="0" Text="THIS IS THE LABEL:" />
    <TextBox Grid.Column="1" Text="content" />
</Grid>
</Window>

Последнее редактирование: на кой черт мне (или кому-то еще) это нужно?

Одна из приятных особенностей WPF — это его способность работать без фиксированных размеров, верно? Если у вас есть нарушения и у вас есть больший размер шрифта, все будет выглядеть нормально. Если вы переведете свой пользовательский интерфейс на другой язык, который требует размера x2, все будет выглядеть нормально. Если у вас другие настройки PPI, все будет выглядеть нормально.

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


person Ignacio Soler Garcia    schedule 25.01.2012    source источник
comment
Вы хотите, чтобы внешний размер сетки увеличивался при увеличении размера содержимого столбца 1? Или у вас есть заданное пространство, внутри которого должна оставаться сетка? Или ширина столбца 1 постоянна и известна во время компиляции?   -  person Martin Hennings    schedule 25.01.2012
comment
Один вопрос: если вы хотите, чтобы столбец 1 в четыре раза превышал размер столбца 0, что произойдет с оставшимся пространством? Или что вы хотите, если ширина столбца 0 + 4-кратная ширина столбца 0 превышает доступное пространство?   -  person dowhilefor    schedule 25.01.2012
comment
Пробовали ли вы использовать проценты — tanguay.info/web/index.php? pg=codeExamples&id=36   -  person    schedule 25.01.2012
comment
@Dmitry 0.2* и 0.8* такие же, как * и 4*, а последний ближе к тому, что ищет SoMoS.   -  person Martin Hennings    schedule 25.01.2012
comment
@All: добавлены дополнительные пояснения, которые помогут вам понять проблему. Спасибо всем.   -  person Ignacio Soler Garcia    schedule 25.01.2012
comment
@SoMoS смотрите мой обновленный ответ. Это работает, вы должны учитывать поведение дочерних элементов управления.   -  person    schedule 25.01.2012


Ответы (4)


Вы можете использовать привязки к столбцам сетки:

<Grid.ColumnDefinitions>
   <ColmunDefinition Width="Auto" x:Name="firstCol"/>
   <ColumnDefinition Width="{Binding ActualWidth, ElementName=firstCol, Converter={StaticResource MultiplyConverter}, ConverterParameter=4}" />
</Grid.ColumnDefinitions>

Затем преобразователь:

public class MultiplyConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        double originalValue;
        double multiplier;
        if (value != null && parameter != null && 
            double.TryParse(value.ToString(), out originalValue) &&
            double.TryParse(parameter.ToString(), out multiplier)) //Can be lots of things: sentinel object, NaN (not a number)...
        {
            return originalValue * multiplier;
        }
        else return Binding.DoNothing;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

Вы также можете написать присоединенное свойство для столбцов сетки.

person Louis Kottmann    schedule 25.01.2012
comment
Выглядит как выполнимо. Можете ли вы немного объяснить, что такое прикрепленное свойство? Я не понимаю, что вы имеете в виду. - person Ignacio Soler Garcia; 25.01.2012
comment
Вы можете просто проверить if(value is double), тогда он не может быть нулевым и его не нужно анализировать. Кроме того, взгляните на Binding.DoNothing< /а>. +1 за использование ConverterParameter для гибкости... - person Martin Hennings; 25.01.2012
comment
@Martin хорошее замечание по Binding.DoNothing . Я не уверен насчет value is double, так как на самом деле это строки. - person Louis Kottmann; 25.01.2012
comment
@Baboon: может быть, для ColumnDefinitions. Ширина объекта двойная. Я отладил его и посмотрел на value.GetType().ToString(). Результат: System.Double. - person Martin Hennings; 25.01.2012
comment
Это не работает. Когда я использую ваш код, значение представляет собой объект типа GridLenght, для которого установлено значение Auto, а не двойное значение. Вы должны использовать ActualWidth правильно? - person Ignacio Soler Garcia; 25.01.2012
comment
Нет, ActualWidth возвращает 0 во время выполнения (даже когда он работает в редакторе Visualstudio... странно). Любые подсказки? - person Ignacio Soler Garcia; 25.01.2012

Изменить:

Если размеры известны во время компиляции, не будет ли проще установить ширину вручную?


Для этого вы можете использовать BindingConverter, я бы выбрал отдельные элементы в горизонтальной StackPanel (посмотрите, ширина StackPanel достаточно велика для вашего содержимого):

Вот очищенный код.

MainWindow.xaml:

<!-- define xmlns:local="clr-namespace:YourAppNamespace" -->
<StackPanel Orientation="Horizontal" HorizontalAlignment="Left">
    <StackPanel.Resources>
        <local:WidthConverter x:Key="wc" />
    </StackPanel.Resources>
    <Grid Background="Gray" x:Name="col1">
        <TextBlock Text="blub"/>
    </Grid>
    <Grid Background="Orange" Width="{Binding ElementName=col1, Path=ActualWidth, Converter={StaticResource ResourceKey=wc}}">
        <Label Content="bla"></Label>
    </Grid>
</StackPanel>

MainWindow.xaml.cs:

public class WidthConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        if (!(value is double))
        {
            return Binding.DoNothing;
        }
        return ((double)value) * 4.0;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}
person Martin Hennings    schedule 25.01.2012
comment
Это не будет работать для целых столбцов, это только между меткой и текстовым блоком. - person Louis Kottmann; 25.01.2012
comment
Я не знаю лучшего способа создания прерывистого неотзывчивого пользовательского интерфейса, чем тот, который вы опубликовали. вы используете его в своих проектах? - person ; 25.01.2012
comment
@Baboon: Хорошо, изменил, теперь сетки зависят друг от друга. - person Martin Hennings; 25.01.2012
comment
@Dmitry: StackPanel гарантирует, что две сетки выровнены по левому краю и занимают только то пространство, которое им нужно. - person Martin Hennings; 25.01.2012
comment
Размеры неизвестны во время компиляции, известны только в самом начале выполнения. Прочтите мою последнюю правку. Спасибо. - person Ignacio Soler Garcia; 25.01.2012

Взято с: http://www.tanguay.info/web/index.php?pg=codeExamples&id=36

идея состоит в том, чтобы использовать:

Обновление 2 - опубликован полный XAML (обратите внимание на поведение дочерних элементов вашей сетки):

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width=".25*" />
                <ColumnDefinition Width=".75*" />
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto" />
            </Grid.RowDefinitions>
            <Grid Background="Yellow" Grid.Column="0">
                <TextBlock  Text="THIS IS THE LABEL:" />
            </Grid>
            <Grid Background="Blue" Grid.Column="1">
                <TextBox Background="Transparent" Text="content" />
            </Grid>

        </Grid>

    </Grid>
</Window>

Я только что проверил это, и это сработало.

Обновление: Проще говоря, в WPF нет готового способа сделать это. В зависимости от ваших обстоятельств вам придется придумать какой-нибудь трюк, чтобы ваша сетка заработала.

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

person Community    schedule 25.01.2012
comment
Боюсь, это вообще не отвечает на вопрос. Как изменить ширину сетки при изменении размера содержимого столбца 0? - person Martin Hennings; 25.01.2012
comment
Вопрос в следующем: вы пробовали? Ваша сетка всегда будет расширяться по всей ширине, а столбец 0 обычно не будет иметь точную ширину своего содержимого. - person Martin Hennings; 25.01.2012
comment
Нет, Мартин. Поместите две кнопки в сетку и попробуйте. - person ; 25.01.2012
comment
Это потому, что кнопки автоматически подстраиваются под размер сетки. Установите ширину первой кнопки на «20» и посмотрите, будет ли ширина второго столбца автоматически равна «60». - person Martin Hennings; 25.01.2012

Насколько я понимаю, вы пытаетесь оформить метку (текстовый блок) и соответствующее поле ввода для нее. В качестве индикатора вы должны сначала просмотреть Beth Massi's Windows Client видео в простой форме ввода данных. который находится на разработке формы data entry, но макет также продемонстрирован очень хорошо.

В частности, обратите внимание, как она размещает элементы управления в окне WPF с помощью дизайнера, окна свойств и XAML, и тогда, я думаю, вам не нужно, чтобы первый столбец имел размер Auto, а второй столбец - 4* первого столбца.

EDIT: В соответствии с рассматриваемым обновлением я публикую возможное решение, как показано ниже:

  1. Код файла XAML (обратите внимание на использование SizeToContent в Window и на привязку к свойству ActualWidth для элемента управления Textbox):

    <Window x:Class="GridTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:local="clr-namespace:GridTest"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        Title="MainWindow"
        d:DesignHeight="350"
        d:DesignWidth="525"
        SizeToContent="WidthAndHeight"
        mc:Ignorable="d">
    <Grid>
        <Grid.Resources>
            <local:FourWidthConverter x:Key="FourWidthConv" />
        </Grid.Resources>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
        <TextBlock Name="tb"
                   Grid.Column="0"
                   Text="Auto Text, change at design time to see changes in Width" />
        <TextBox Name="tx"
                 Grid.Column="1"
                 Width="{Binding ElementName=tb,
                                 Path=ActualWidth,
                                 Converter={StaticResource FourWidthConv}}"
                 Text="4 * col 1 width displaying Text in SizetoContentWindow" />
    </Grid>
    </Window>
    
  2. .Xaml.cs код файла (обратите внимание на конвертер здесь):

    using System.Windows;
    using System.Windows.Data;
    
    namespace GridTest
    {
        /// <summary>
        /// Interaction logic for MainWindow.xaml
        /// </summary>
        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
            }
        }
    
        public class FourWidthConverter : IValueConverter
        {
            public object Convert(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
            {
                return 4 * (double)value;
            }
    
            public object ConvertBack(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
            {
                throw new System.NotImplementedException();
            }
        }
    }
    
person VSS    schedule 25.01.2012
comment
прочитайте мое редактирование, чтобы понять, почему мне или кому-либо может понадобиться эта функция. - person Ignacio Soler Garcia; 25.01.2012
comment
@SoMoS Я отредактировал свой ответ и опубликовал возможное решение, см. РЕДАКТИРОВАТЬ .. - person VSS; 25.01.2012
comment
@SoMoS Вероятно, вам нужно будет реализовать этот код внутри пользовательского элемента управления, а не в окне, для повторного использования такого рода функций. - person VSS; 25.01.2012