WPF入门 #1 WPF布局基础、WPF样式基础、WPF数据模板、WPF绑定

发布于:2025-06-19 ⋅ 阅读:(114) ⋅ 点赞:(0)

WPF当中有许多的布局容器控件,例如<Grid>、<StackPanel>、<WrapPanel>、<DockPanel>、<UniformGrid>。接下来分别介绍一下各个布局容器控件。

布局基础

Grid

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="2*"/>
        <RowDefinition/>
    </Grid.RowDefinitions>

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

    <Border Grid.Row="0" Grid.Column="0" Background="Red"/>
    <Border Grid.Row="0" Grid.Column="1" Background="Yellow"/>
    <Border Grid.Row="1" Grid.Column="0" Background="Blue"/>
    <Border Grid.Row="1" Grid.Column="1" Background="Green"/>
</Grid>

Grid中的元素还可以跨行和跨列:

StackPanel

StackPanel默认水平排列,具有 Orientation=""属性可以改变排列方向。

WrapPanel

WrapPanel默认水平排列,也具有 Orientation=""属性可以改变排列方向。

DockPanel

DockPanel具有停靠的功能,位于DockPanel中的元素,可以设置它的方向。

UniformGrid

这个容器最大的作用就是在有限的空间里面均分剩余空间。

下面对一个页面进行布局模拟练习:

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="80"/>
        <RowDefinition/>
    </Grid.RowDefinitions>

    <Border Background="#FFECF1"/>

    <Grid Grid.Row="1">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="200"/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>

        <Border Background="#FF7F24"/>

        <Grid Grid.Column="1" Margin="5">
            <Grid.RowDefinitions>
                <RowDefinition Height="100"/>
                <RowDefinition/>
                <RowDefinition/>
            </Grid.RowDefinitions>

            <Grid Grid.Row="0">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition/>
                    <ColumnDefinition/>
                    <ColumnDefinition/>
                    <ColumnDefinition/>
                    <ColumnDefinition/>
                </Grid.ColumnDefinitions>

                <Border Margin="5" Grid.Column="0" Background="#1b1c1d"/>
                <Border Margin="5" Grid.Column="1" Background="#2AC864"/>
                <Border Margin="5" Grid.Column="2" Background="#1b1c1d"/>
                <Border Margin="5" Grid.Column="3" Background="#F85A54"/>
                <Border Margin="5" Grid.Column="4" Background="#1b1c1d"/>
            </Grid>
            
            <Grid Grid.Row="1">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="1.5*"/>
                    <ColumnDefinition/>
                </Grid.ColumnDefinitions>

                <Border Margin="5" Grid.Column="0" Background="#1b1c1d"/>
                <Border Margin="5" Grid.Column="1" Background="#2AC864"/>
            </Grid>
            
            <Grid Grid.Row="2">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="1.5*"/>
                    <ColumnDefinition/>
                </Grid.ColumnDefinitions>

                <Border Margin="5" Grid.Column="0" Background="#1b1c1d"/>
                <Border Margin="5" Grid.Column="1" Background="#F85A54"/>
            </Grid>
        </Grid>
    </Grid>
</Grid>

样式基础

样式负责修饰元素的外观以及行为,可以在样式中定义不同类型元素的属性值集合。

<Window.Resources>
    <Style x:Key="BaseStyle" TargetType="Button">
        <Setter Property="FontSize" Value="18"/>
        <Setter Property="Foreground" Value="White"/>
        <Setter Property="Background" Value="Red"/>
    </Style>

    <Style x:Key="BottonStyle" TargetType="Button" BasedOn="{StaticResource BaseStyle}">
        <Setter Property="Content" Value="Botton1"/>
    </Style>
</Window.Resources>
<Grid>
    <StackPanel>
        <Button Background="Blue" Style="{StaticResource BottonStyle}"/>
        <Button Style="{StaticResource BottonStyle}"/>
        <Button Style="{StaticResource BottonStyle}"/>
    </StackPanel>
</Grid>

数据模板

<Grid>
    <ListBox x:Name="list">
        <ListBoxItem>
            <StackPanel Orientation="Horizontal">
                <Border Width="10" Height="10" Background="Red"/>
                <TextBlock Margin="10,0"  Text="Red"/>
            </StackPanel>
        </ListBoxItem>

        <ListBoxItem>
            <StackPanel Orientation="Horizontal">
                <Border Width="10" Height="10" Background="Blue"/>
                <TextBlock Margin="10,0"  Text="Red"/>
            </StackPanel>
        </ListBoxItem>

        <ListBoxItem>
            <StackPanel Orientation="Horizontal">
                <Border Width="10" Height="10" Background="Green"/>
                <TextBlock Margin="10,0"  Text="Red"/>
            </StackPanel>
        </ListBoxItem>
    </ListBox>
</Grid>

可以看到,这里每一项的构造都是完全相同的,唯一不同的就是它们的数据,因此可以将它抽离出来作为一个模板。

<Grid>
    <ListBox x:Name="list">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <StackPanel Orientation="Horizontal">
                    <Border Width="10" Height="10" Background="{Binding Code}"/>
                    <TextBlock Margin="10,0"  Text="{Binding Name}"/>
                </StackPanel>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
</Grid>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.NetworkInformation;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace WpfApp4 {
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window {
        public MainWindow() {
            InitializeComponent();

            List<Color> test = new List<Color>();

            test.Add(new Color() { Code = "#FFB6C1", Name = "浅粉红" });
            test.Add(new Color() { Code = "#FFC0CB", Name = "粉红" });
            test.Add(new Color() { Code = "#DC143C", Name = "猩红" });
            test.Add(new Color() { Code = "#FFF0F5", Name = "脸红的淡紫色" });

            //LightPink 浅粉红	#FFB6C1	255,182,193
            //Pink 粉红	#FFC0CB	255,192,203
            //Crimson 猩红	#DC143C	220,20,60
            //LavenderBlush 脸红的淡紫色	#FFF0F5	255,240,245
            list.ItemsSource = test;
        }

        public class Color {
            public string Code { get; set; }
            public string Name { get; set; }
        }
    }
}

由此就可以看到DataTemplate的作用。继续编写例子:

<Grid>
    <DataGrid x:Name = "grid" AutoGenerateColumns="False" CanUserAddRows="False">
        <DataGrid.Columns>
            <DataGridTextColumn Header="Code" Binding="{Binding Code}"/>
            <DataGridTextColumn Header="Name" Binding="{Binding Name}"/>

            <DataGridTemplateColumn Header="操作">
                <DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <StackPanel Orientation="Horizontal">
                            <Button Content="删除" />
                            <Button Content="复制" />
                            <Button Content="保存" />
                        </StackPanel>
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
                
            </DataGridTemplateColumn>
        </DataGrid.Columns>
    </DataGrid>
</Grid>

灵活地使用DataTemplate数据模块,对后续开发有很重要的帮助,当然DataTemplate的应用不止于此,后续还会介绍到。

绑定

使用绑定可以使得控件与控件之间建立一种绑定关系,可以不再为此编写大量的代码来维持。

<Grid>
    <StackPanel>
        <Slider x:Name="slider" Margin="5" ValueChanged="Slider_ValueChanged"/>
        <TextBox x:Name="textbox1" Margin="5" Height="30" TextChanged="textbox1_TextChanged"/>
        <TextBox x:Name="textbox2" Margin="5" Height="30"/>
        <TextBox x:Name="textbox3" Margin="5" Height="30"/>
    </StackPanel>
</Grid>
namespace WpfApp5 {
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window {
        public MainWindow() {
            InitializeComponent();
        }

        private void Slider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e) {
            textbox1.Text = slider.Value.ToString();
            textbox2.Text = slider.Value.ToString();
            textbox3.Text = slider.Value.ToString();
        }

        private void textbox1_TextChanged(object sender, TextChangedEventArgs e) {
            if (double.TryParse(textbox1.Text, out double result))
            slider.Value = result;
        }
    }       
}

此时代码实现了拖动滑块,下方三个框里的数据会同步变化。对下方任意一个框里的数据进行修改,上方滑块的位置也会同步变化。为了实现这个功能,代码变得特别的冗余,可以使用绑定来简化。

<Grid>
    <StackPanel>
        <Slider x:Name="slider" Margin="5"/>
        <TextBox Text="{Binding ElementName=slider,Path=Value}" x:Name="textbox1" Margin="5" Height="30"/>
        <TextBox Text="{Binding ElementName=slider,Path=Value}" x:Name="textbox2" Margin="5" Height="30"/>
        <TextBox Text="{Binding ElementName=slider,Path=Value}" x:Name="textbox3" Margin="5" Height="30"/>
    </StackPanel>
</Grid>

此时就不需要具体的实现代码了,使用绑定就可以完成两个控件的双向绑定。 


网站公告

今日签到

点亮在社区的每一天
去签到