WPF: การตั้งค่าความกว้าง (และความสูง) เป็นค่าร้อยละ


149

สมมติว่าฉันต้องการTextBlockให้มันมีWidthค่าเท่ากับพาเรนต์คอนเทนเนอร์Width(เช่นยืดจากด้านข้าง) หรือเปอร์เซ็นต์ของพาเรนต์คอนเทนเนอร์Widthฉันจะทำสิ่งนี้ให้สำเร็จได้อย่างไรXAMLโดยไม่ระบุค่าสัมบูรณ์

ฉันต้องการทำสิ่งนี้เพื่อที่ว่าถ้าคอนเทนเนอร์พาเรนต์คอนเทนเนอร์ขยายตัวในภายหลัง ( Widthเพิ่มขึ้น'มัน)' องค์ประกอบย่อยจะถูกขยายโดยอัตโนมัติ (โดยทั่วไปเหมือนกับใน HTML และ CSS)


ลองดูคำตอบนี้
Jesper Fyhr Knudsen

ใช้คำตอบของ cwap และรวม tb ในการตั้งค่ากริดที่การจัดเรียงของมันยืด
Shimmy Weitzhandler

คำตอบ:


90

วิธียืดขนาดให้ใหญ่เท่ากับคอนเทนเนอร์พาเรนต์คือใช้แอททริบิวต์:

 <Textbox HorizontalAlignment="Stretch" ...

สิ่งนี้จะทำให้องค์ประกอบกล่องข้อความยืดออกในแนวนอนและเติมช่องว่างพาเรนต์ทั้งหมดในแนวนอน (อันที่จริงมันขึ้นอยู่กับพาเนลพาเนลที่คุณใช้ แต่ควรใช้งานได้ในกรณีส่วนใหญ่)

เปอร์เซ็นต์สามารถใช้ได้กับค่าของเซลล์กริดเท่านั้นตัวเลือกอื่นคือสร้างกริดและวางกล่องข้อความของคุณในหนึ่งในเซลล์ที่มีเปอร์เซ็นต์ที่เหมาะสม


221

คุณสามารถวางกล่องข้อความไว้ในตารางเพื่อทำค่าร้อยละในแถวหรือคอลัมน์ของตารางและปล่อยให้กล่องข้อความเติมลงในเซลล์แม่ของพวกเขาโดยอัตโนมัติ (ตามค่าเริ่มต้น) ตัวอย่าง:

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="2*" />
        <ColumnDefinition Width="3*" />
    </Grid.ColumnDefinitions>

    <TextBox Grid.Column="0" />
    <TextBox Grid.Column="1" />
</Grid>

สิ่งนี้จะทำให้ความกว้าง # 1 2/5 และ # 2 3/5


7
ฉันได้ลองแล้ว แต่ฉันได้รับข้อผิดพลาดนี้: '2 *' สตริงไม่สามารถแปลงเป็นความยาวได้ '
Andreas Grech

6
ที่จริงแล้ว * (เครื่องหมายดอกจัน) เป็นดาวตัวน้อย;) etymonline.com/index.php?term=asterisk
Pratik Deoghare

73
แม่ของฉันบอกว่าฉันเป็นดารา
Denys Wessels

7
สิ่งนี้ไม่ทำงานแม้ว่ากล่องข้อความจะอยู่ในกริด ความกว้างสามารถตั้งค่าเป็น Double, Qualified Double (ค่า double ตามด้วย px, in, cm หรือ pt) หรือ Auto ดูmsdn.microsoft.com/en-GB/library/…
Darren

2
ใช่ .. จริง ๆ แล้วนี่เป็นคำตอบที่ไม่ดีนัก แต่ตาม upvotes ทั้งหมดฉันคิดว่ามันช่วยใครบางคน (เมื่อนานมาแล้ว) ซึ่งเป็นสาเหตุที่ฉันไม่ได้ลบมัน
cwap

58

โดยปกติแล้วคุณจะใช้การควบคุมเลย์เอาต์ในตัวที่เหมาะสมกับสถานการณ์ของคุณ (เช่นใช้กริดเป็นพาเรนต์ถ้าคุณต้องการปรับสเกลสัมพันธ์กับพาเรนต์) ถ้าคุณต้องการที่จะทำมันด้วยองค์ประกอบหลักโดยพลการคุณสามารถสร้าง ValueConverter ทำมัน แต่มันอาจจะไม่สะอาดเท่าที่คุณต้องการ อย่างไรก็ตามหากคุณต้องการมันอย่างแน่นอนคุณสามารถทำสิ่งนี้:

public class PercentageConverter : IValueConverter
{
    public object Convert(object value, 
        Type targetType, 
        object parameter, 
        System.Globalization.CultureInfo culture)
    {
        return System.Convert.ToDouble(value) * 
               System.Convert.ToDouble(parameter);
    }

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

ซึ่งสามารถใช้แบบนี้เพื่อรับกล่องข้อความลูก 10% ของความกว้างของผืนผ้าใบหลัก:

<Window x:Class="WpfApplication1.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:WpfApplication1"
    Title="Window1" Height="300" Width="300">
    <Window.Resources>
        <local:PercentageConverter x:Key="PercentageConverter"/>
    </Window.Resources>
    <Canvas x:Name="canvas">
        <TextBlock Text="Hello"
                   Background="Red" 
                   Width="{Binding 
                       Converter={StaticResource PercentageConverter}, 
                       ElementName=canvas, 
                       Path=ActualWidth, 
                       ConverterParameter=0.1}"/>
    </Canvas>
</Window>

นี่มันเจ๋งจริงๆฉันจะทำมันในโค้ดได้อย่างไร (ตั้งค่าความกว้างของกล่องข้อความ)?
Jeremy

9
คุณควรพิจารณาเพิ่มCultureInfo.InvariantCultureไปที่การแปลงสองครั้งเพราะparameterถือว่าเป็นstringและในวัฒนธรรมที่แตกต่างกันdecimal separatorมันจะไม่ทำงานอย่างที่คาดไว้
Flat Eric

33

สำหรับทุกคนที่ได้รับข้อผิดพลาดเช่น: สตริง '2 *' ไม่สามารถแปลงเป็นความยาวได้

<Grid >
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="2*" /><!--This will make any control in this column of grid take 2/5 of total width-->
        <ColumnDefinition Width="3*" /><!--This will make any control in this column of grid take 3/5 of total width-->
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition MinHeight="30" />
    </Grid.RowDefinitions>

    <TextBlock Grid.Column="0" Grid.Row="0">Your text block a:</TextBlock>
    <TextBlock Grid.Column="1" Grid.Row="0">Your text block b:</TextBlock>
</Grid>

ทำไม<RowDefinition Height="auto" />ล่ะ
เบ็น

2
"อัตโนมัติ" ใช้พื้นที่มากที่สุดเท่าที่ความต้องการการควบคุม
ยา

ขอบคุณมากนี่น่าจะเป็นคำตอบที่ดีที่สุด
Mafii

นี่เป็นคำตอบที่ดีที่สุดอย่างแน่นอน
Knut Valen

7

สามารถใช้งาน IValueConverter ได้ คลาสตัวแปลงที่รับมรดกจาก IValueConverter ใช้พารามิเตอร์บางอย่างเช่นvalue(เปอร์เซ็นต์) และparameter(ความกว้างของพาเรนต์) และส่งกลับค่าความกว้างที่ต้องการ ในไฟล์ XAML ความกว้างของส่วนประกอบถูกกำหนดด้วยค่าที่ต้องการด้วย:

public class SizePercentageConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (parameter == null)
            return 0.7 * value.ToDouble();

        string[] split = parameter.ToString().Split('.');
        double parameterDouble = split[0].ToDouble() + split[1].ToDouble() / (Math.Pow(10, split[1].Length));
        return value.ToDouble() * parameterDouble;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        // Don't need to implement this
        return null;
    }
}

XAML:

<UserControl.Resources>
    <m:SizePercentageConverter x:Key="PercentageConverter" />
</UserControl.Resources>

<ScrollViewer VerticalScrollBarVisibility="Auto"
          HorizontalScrollBarVisibility="Disabled"
          Width="{Binding Converter={StaticResource PercentageConverter}, RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type Border}},Path=ActualWidth}"
          Height="{Binding Converter={StaticResource PercentageConverter}, ConverterParameter=0.6, RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type Border}},Path=ActualHeight}">
....
</ScrollViewer>

4

ฉันรู้ว่าไม่ใช่ Xaml แต่ฉันทำสิ่งเดียวกันกับเหตุการณ์ SizeChanged ของกล่องข้อความ:

private void TextBlock_SizeChanged(object sender, SizeChangedEventArgs e)
{
   TextBlock textBlock = sender as TextBlock;
   FrameworkElement element = textBlock.Parent as FrameworkElement;
   textBlock.Margin = new Thickness(0, 0, (element.ActualWidth / 100) * 20, 0);
}

ดูเหมือนว่ากล่องข้อความจะมีขนาด 80% ของเมนูหลัก (มีขอบด้านขวาเท่ากับ 20%) และขยายเมื่อต้องการ


4

ฉันใช้สองวิธีในการกำหนดขนาดที่สัมพันธ์กัน ฉันได้เรียนที่เรียกว่าRelativeมีคุณสมบัติที่แนบมาสามTo, WidthPercentและHeightPercentซึ่งจะเป็นประโยชน์ถ้าผมต้องการเป็นองค์ประกอบที่จะเป็นขนาดที่สัมพันธ์ของได้ทุกองค์ประกอบในภาพต้นไม้และรู้สึก hacky น้อยกว่าวิธีการแปลง - แม้ว่าการใช้สิ่งที่เหมาะกับคุณที่คุณ มีความสุขกับ

วิธีการอื่นค่อนข้างฉลาดแกมโกง เพิ่มViewBoxที่ที่คุณต้องการขนาดญาติข้างในจากนั้นเพิ่มGridที่ความกว้าง 100 จากนั้นถ้าคุณเพิ่ม a ที่TextBlockมีความกว้าง 10 ข้างในนั้นจะเห็นได้ชัด 10% จาก 100

ความViewBoxตั้งใจจะปรับขนาดGridตามพื้นที่ใดก็ตามที่ได้รับดังนั้นหากเป็นเพียงสิ่งเดียวในหน้าเว็บจากนั้นGridขนาดจะถูกปรับขนาดเต็มความกว้างและมีประสิทธิภาพคุณTextBlockจะถูกปรับขนาดเป็น 10% ของหน้า

หากคุณไม่ได้ตั้งความสูงไว้Gridมันจะย่อขนาดให้พอดีกับเนื้อหาดังนั้นขนาดทั้งหมดจะค่อนข้างใหญ่ คุณจะต้องตรวจสอบให้แน่ใจว่าเนื้อหาไม่สูงเกินไปเช่นเริ่มเปลี่ยนอัตราส่วนภาพของพื้นที่ที่กำหนดให้กับเนื้อหาViewBoxอื่นซึ่งจะเริ่มปรับขนาดความสูงเช่นกัน คุณอาจจะสามารถทำงานรอบนี้มีของStretchUniformToFill

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.