少有人走的路

勇哥的工业自动化技术网站

wpf的基础知识点演示

wpf的基础知识点演示:


知识点包括下面这些:

(1)常见的知识点

cs中的:

INotifyPropertyChanged

ICommand

CommandManager


xaml中:

Binding Value,UpdateSourceTrigger=PropertyChanged}

Command="{Binding MyCommand}


(2) Binding的核心扩展属性

除了UpdateSourceTrigger,还有下面这些:

Mode //控制绑定方向

CommandParameter //给命令传参数

ElementName //绑定到当前 XAML 中的其他控件

FallbackValue //绑定失败时的默认值

RelativeSource //绑定到控件自身 / 父控件


(3) INotifyCollectionChanged & ObservableCollection<T>


(4) DataContext(绑定的数据源)


(5) 其它知识点

x:Name,  Name



程序运行效果:


act115.gif


解决方案:

image.png



MainWindow.xaml

<Window x:Class="WpfApp1.MainWindow"
        x:Name="window"
        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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApp1"
        mc:Ignorable="d"
        Title="WPF知识点示例" Height="600" Width="800">
    <Window.Resources>
        <DataTemplate x:Key="ListItemTemplate">
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="40"/>
                    <ColumnDefinition Width="*"/>
                </Grid.ColumnDefinitions>
                <Border Grid.Column="0" Background="#E0E0E0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
                    <TextBlock 
                        Text="{Binding Index}" 
                        HorizontalAlignment="Center" 
                        VerticalAlignment="Center" 
                        FontSize="12" 
                        FontWeight="Bold" 
                        Foreground="#666666"/>
                </Border>
                <TextBlock 
                    Grid.Column="1" 
                    Text="{Binding Text}" 
                    Padding="10,5" 
                    FontSize="14" 
                    Foreground="#333333"/>
                <Grid.Style>
                    <Style TargetType="Grid">
                        <Style.Triggers>
                            <DataTrigger Binding="{Binding IsOdd}" Value="True">
                                <Setter Property="Background" Value="Gray"/>
                            </DataTrigger>
                            <DataTrigger Binding="{Binding IsEven}" Value="True">
                                <Setter Property="Background" Value="#fec700ff"/>
                            </DataTrigger>
                        </Style.Triggers>
                    </Style>
                </Grid.Style>
            </Grid>
        </DataTemplate>

        <DataTemplate x:Key="SimpleListItemTemplate">
            <TextBlock Text="{Binding Text}" Padding="5"/>
        </DataTemplate>

        <Style x:Key="ListBoxItemStyle" TargetType="ListBoxItem">
            <Setter Property="Margin" Value="0,2,0,0"/>
            <Setter Property="Padding" Value="0"/>
        </Style>
    </Window.Resources>
    <Window.DataContext>
        <local:MainViewModel />
    </Window.DataContext>
    <Grid Margin="20">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>

        <!-- 输入区域 -->
        <StackPanel Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" Margin="0,0,0,20">
            <TextBlock Text="输入文本:" FontSize="14" FontWeight="Bold"/>
            <TextBox 
                Text="{Binding InputText, UpdateSourceTrigger=PropertyChanged}" 
                Margin="0,5,0,0" 
                Height="30" 
                Width="400"
                HorizontalAlignment="Left"
                ToolTip="输入要添加的项目"/>
            <TextBlock Text="{Binding InputText}" Margin="0,5,0,0" Foreground="Blue"/>
        </StackPanel>

        <!-- 命令按钮区域 -->
        <StackPanel Grid.Row="1" Grid.Column="0" Orientation="Horizontal" Margin="0,0,0,20">
            <Button 
                Content="添加项目" 
                Command="{Binding AddItemCommand}" 
                Margin="0,0,10,0" 
                Height="30" 
                Width="100"/>
            <Button 
                Content="清空项目" 
                Command="{Binding ClearItemsCommand}" 
                Height="30" 
                Width="100"/>
            <Button 
                Content="更新显示" 
                Command="{Binding UpdateDisplayCommand}" 
                CommandParameter="自定义参数" 
                Margin="10,0,0,0" 
                Height="30" 
                Width="100"/>
        </StackPanel>

        <!-- 项目列表区域 -->
        <StackPanel Grid.Row="2" Grid.Column="0" Margin="0,0,20,0">
            <TextBlock Text="项目列表:" FontSize="14" FontWeight="Bold" Margin="0,0,0,5"/>
            <ListBox 
                ItemsSource="{Binding Items}" 
                SelectedIndex="{Binding SelectedIndex, Mode=TwoWay}" 
                Height="300" 
                Width="350"
                BorderBrush="Gray" 
                BorderThickness="1"
                ItemTemplate="{StaticResource ListItemTemplate}"
                ItemContainerStyle="{StaticResource ListBoxItemStyle}">
            </ListBox>
        </StackPanel>

        <!-- 显示区域 -->
        <StackPanel Grid.Row="2" Grid.Column="1">
            <TextBlock Text="显示内容:" FontSize="14" FontWeight="Bold" Margin="0,0,0,5"/>
            <Border 
                    Height="300" 
                    Width="350"
                    Padding="10"
                    Background="#F0F0F0"
                    BorderBrush="Gray" 
                    BorderThickness="1">
                <TextBlock 
                        Text="{Binding DisplayText, FallbackValue='绑定失败时的默认值'}"
                        TextWrapping="Wrap"/>
            </Border>
                <!-- 迷你列表(模板重用示例) -->
                <StackPanel Margin="0,10,0,0">
                    <TextBlock Text="迷你列表(模板重用):" FontSize="12" FontWeight="Bold" Margin="0,0,0,5"/>
                    <ListBox 
                        ItemsSource="{Binding Items}" 
                        Height="100" 
                        Width="350"
                        BorderBrush="LightGray" 
                        BorderThickness="1"
                        ItemTemplate="{StaticResource SimpleListItemTemplate}"/>
                </StackPanel>
            </StackPanel>

        <!-- 字体大小调整区域 -->
        <StackPanel Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="2" Margin="0,20,0,20">
            <TextBlock Text="字体大小调整:" FontSize="14" FontWeight="Bold" Margin="0,0,0,10"/>
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="120"/>
                    <ColumnDefinition Width="*"/>
                    <ColumnDefinition Width="100"/>
                </Grid.ColumnDefinitions>
                <TextBlock Text="字体大小:" Grid.Column="0" VerticalAlignment="Center"/>
                <Slider 
                    x:Name="fontSizeSlider"
                    Grid.Column="1" 
                    Minimum="8" 
                    Maximum="36" 
                    Value="{Binding FontSize, Mode=TwoWay}" 
                    VerticalAlignment="Center" Margin="0,0,10,0"/>
                <TextBox 
                    Grid.Column="2" 
                    Text="{Binding FontSize, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" 
                    Width="80" 
                    Height="25" 
                    VerticalAlignment="Center" 
                    HorizontalAlignment="Left"
                    ToolTip="直接输入字体大小"/>
            </Grid>
            <TextBlock 
                Text="示例文本:调整字体大小查看效果" 
                Margin="0,10,0,0" 
                FontSize="{Binding FontSize}" 
                FontWeight="Bold"
                Background="#F0F0F0" 
                Padding="10" 
                Width="400"/>
        </StackPanel>

        <!-- 绑定示例区域 -->
        <StackPanel Grid.Row="4" Grid.Column="0" Grid.ColumnSpan="2" Margin="0,0,0,0">
            <TextBlock Text="绑定示例:" FontSize="14" FontWeight="Bold" Margin="0,0,0,5"/>
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="150"/>
                    <ColumnDefinition Width="*"/>
                </Grid.ColumnDefinitions>
                <TextBlock Text="当前窗口标题:" Grid.Column="0" VerticalAlignment="Center"/>
                <TextBlock 
                    Grid.Column="1" 
                    Text="{Binding Title, ElementName=window}" 
                    VerticalAlignment="Center" 
                    Foreground="Blue"/>
            </Grid>
            <Grid Margin="0,5,0,0">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="150"/>
                    <ColumnDefinition Width="*"/>
                </Grid.ColumnDefinitions>
                <TextBlock Text="当前选中项:" Grid.Column="0" VerticalAlignment="Center"/>
                <TextBlock 
                    Grid.Column="1" 
                    Text="{Binding SelectedIndex, StringFormat='选中索引:{0}'}" 
                    VerticalAlignment="Center" 
                    Foreground="Green"/>
            </Grid>
            <Grid Margin="0,5,0,0">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="150"/>
                    <ColumnDefinition Width="*"/>
                </Grid.ColumnDefinitions>
                <TextBlock Text="列表项数量:" Grid.Column="0" VerticalAlignment="Center"/>
                <TextBlock 
                    Grid.Column="1" 
                    Text="{Binding Items.Count, StringFormat='共 {0} 项'}" 
                    VerticalAlignment="Center" 
                    Foreground="Orange"/>
            </Grid>
            <Grid Margin="0,5,0,0">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="150"/>
                    <ColumnDefinition Width="*"/>
                </Grid.ColumnDefinitions>
                <TextBlock Text="相对源绑定:" Grid.Column="0" VerticalAlignment="Center"/>
                <TextBlock 
                    Grid.Column="1" 
                    Text="{Binding RelativeSource={RelativeSource Self}, Path=Name, FallbackValue='未找到名称'}" 
                    Name="SampleTextBlock"
                    VerticalAlignment="Center" 
                    Foreground="Purple"/>
            </Grid>
            <Grid Margin="0,5,0,0">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="150"/>
                    <ColumnDefinition Width="*"/>
                </Grid.ColumnDefinitions>
                <TextBlock Text="滑动条值(ElementName):" Grid.Column="0" VerticalAlignment="Center"/>
                <TextBlock 
                    Grid.Column="1" 
                    Text="{Binding Value, ElementName=fontSizeSlider, StringFormat={}{0:F1}}" 
                    VerticalAlignment="Center" 
                    Foreground="Red"/>
            </Grid>
        </StackPanel>
    </Grid>
</Window>


MainViewModel.cs

using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows.Input;

namespace WpfApp1
{
    public class ListItem : INotifyPropertyChanged
    {
        private string _text;
        public string Text
        {
            get { return _text; }
            set
            {
                if (_text != value)
                {
                    _text = value;
                    OnPropertyChanged(nameof(Text));
                }
            }
        }

        private int _index;
        public int Index
        {
            get { return _index; }
            set
            {
                if (_index != value)
                {
                    _index = value;
                    OnPropertyChanged(nameof(Index));
                    OnPropertyChanged(nameof(IsEven));
                    OnPropertyChanged(nameof(IsOdd));
                }
            }
        }

        public bool IsEven => Index % 2 == 0;
        public bool IsOdd => Index % 2 != 0;

        public event PropertyChangedEventHandler PropertyChanged;
        protected virtual void OnPropertyChanged(string propertyName)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    public class MainViewModel : INotifyPropertyChanged
    {
        private string _inputText;
        public string InputText
        {
            get { return _inputText; }
            set
            {
                if (_inputText != value)
                {
                    _inputText = value;
                    OnPropertyChanged(nameof(InputText));
                }
            }
        }

        private string _displayText;
        public string DisplayText
        {
            get { return _displayText; }
            set
            {
                if (_displayText != value)
                {
                    _displayText = value;
                    OnPropertyChanged(nameof(DisplayText));
                }
            }
        }

        private int _selectedIndex;
        public int SelectedIndex
        {
            get { return _selectedIndex; }
            set
            {
                if (_selectedIndex != value)
                {
                    _selectedIndex = value;
                    OnPropertyChanged(nameof(SelectedIndex));
                }
            }
        }

        private double _fontSize;
        public double FontSize
        {
            get { return _fontSize; }
            set
            {
                if (_fontSize != value)
                {
                    _fontSize = value;
                    OnPropertyChanged(nameof(FontSize));
                }
            }
        }

        public ObservableCollection<ListItem> Items { get; set; }

        public ICommand AddItemCommand { get; set; }
        public ICommand ClearItemsCommand { get; set; }
        public ICommand UpdateDisplayCommand { get; set; }

        public MainViewModel()
        {
            Items = new ObservableCollection<ListItem>
            {
                new ListItem { Text = "项目1", Index = 1 },
                new ListItem { Text = "项目2", Index = 2 },
                new ListItem { Text = "项目3", Index = 3 }
            };

            AddItemCommand = new RelayCommand(AddItem);
            ClearItemsCommand = new RelayCommand(ClearItems);
            UpdateDisplayCommand = new RelayCommand<string>(UpdateDisplay);

            DisplayText = "欢迎使用WPF示例程序";
            FontSize = 14;
        }

        private void AddItem(object parameter)
        {
            if (!string.IsNullOrEmpty(InputText))
            {
                var newItem = new ListItem { Text = InputText, Index = Items.Count + 1 };
                Items.Add(newItem);
                InputText = string.Empty;
            }
        }

        private void ClearItems(object parameter)
        {
            Items.Clear();
        }

        private void UpdateDisplay(string parameter)
        {
            DisplayText = $"更新时间:{DateTime.Now.ToString()},参数:{parameter}";
        }

        public event PropertyChangedEventHandler PropertyChanged;
        protected virtual void OnPropertyChanged(string propertyName)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    public class RelayCommand : ICommand
    {
        private readonly Action<object> _execute;
        private readonly Func<object, bool> _canExecute;

        public RelayCommand(Action<object> execute, Func<object, bool> canExecute = null)
        {
            _execute = execute;
            _canExecute = canExecute;
        }

        public event EventHandler CanExecuteChanged
        {
            add { System.Windows.Input.CommandManager.RequerySuggested += value; }
            remove { System.Windows.Input.CommandManager.RequerySuggested -= value; }
        }

        public bool CanExecute(object parameter)
        {
            return _canExecute == null || _canExecute(parameter);
        }

        public void Execute(object parameter)
        {
            _execute(parameter);
        }
    }

    public class RelayCommand<T> : ICommand
    {
        private readonly Action<T> _execute;
        private readonly Func<T, bool> _canExecute;

        public RelayCommand(Action<T> execute, Func<T, bool> canExecute = null)
        {
            _execute = execute;
            _canExecute = canExecute;
        }

        public event EventHandler CanExecuteChanged
        {
            add { System.Windows.Input.CommandManager.RequerySuggested += value; }
            remove { System.Windows.Input.CommandManager.RequerySuggested -= value; }
        }

        public bool CanExecute(object parameter)
        {
            return _canExecute == null || _canExecute((T)parameter);
        }

        public void Execute(object parameter)
        {
            _execute((T)parameter);
        }
    }

    public class BoolToColorConverter : System.Windows.Data.IValueConverter
    {
        public object Convert(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            if (value is bool boolValue && boolValue)
            {
                return System.Windows.Media.Brushes.Blue;
            }
            return System.Windows.Media.Brushes.Orange;
        }

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


按知识点分析上面代码



 (1)  {Binding Value,UpdateSourceTrigger=PropertyChanged}

INotifyPropertyChanged


例子:

 <StackPanel Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" Margin="0,0,0,20">
            <TextBlock Text="输入文本:" FontSize="14" FontWeight="Bold"/>
            <TextBox 
                Text="{Binding InputText, UpdateSourceTrigger=PropertyChanged}" 
                Margin="0,5,0,0" 
                Height="30" 
                Width="400"
                HorizontalAlignment="Left"
                ToolTip="输入要添加的项目"/>
            <TextBlock Text="{Binding InputText}" Margin="0,5,0,0" Foreground="Blue"/>
        </StackPanel>


Binding Value:

    ViewModel中实现了INotifyPropertyChanged接口,当InputText属性变化时通知UI

image.png


UpdateSourceTrigger=PropertyChanged:

 实现输入时实时更新绑定源(就是InputText),而不用等到这个控件失去焦点时才更新InputText

 在上面的例子里准备了一个TextBlock,并绑定了InputText,于是你会见到输入的字符会即时回显出来的效果
<TextBlock Text="{Binding InputText}"

 

act109.gif




(2)双向绑定 (TwoWay Binding)

核心概念 :实现了UI控件与数据源之间的双向数据流动

例子:

act110.gif

<!-- 字体大小调整区域 -->
<StackPanel Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="2" Margin="0,20,0,20">
    <TextBlock Text="字体大小调整:" FontSize="14" FontWeight="Bold" Margin="0,0,0,10"/>
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="120"/>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="100"/>
        </Grid.ColumnDefinitions>
        <TextBlock Text="字体大小:" Grid.Column="0" VerticalAlignment="Center"/>
        <Slider 
            Grid.Column="1" 
            Minimum="8" 
            Maximum="36" 
            Value="{Binding FontSize, Mode=TwoWay}" 
            VerticalAlignment="Center" Margin="0,0,10,0"/>
        <TextBox 
            Grid.Column="2" 
            Text="{Binding FontSize, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" 
            Width="80" 
            Height="25" 
            VerticalAlignment="Center" 
            HorizontalAlignment="Left"
            ToolTip="直接输入字体大小"/>
    </Grid>
    <TextBlock 
        Text="示例文本:调整字体大小查看效果" 
        Margin="0,10,0,0" 
        FontSize="{Binding FontSize}" 
        FontWeight="Bold"
        Background="#F0F0F0" 
        Padding="10" 
        Width="400"/>
</StackPanel>

  

  - Slider.Value="{Binding FontSize, Mode=TwoWay}" 

- 滑动条与FontSize属性双向绑定

  - TextBox.Text="{Binding FontSize, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" 

- 文本框与FontSize属性双向绑定


有些控件,默认Mode=TwoWay。所以在这个例里不需要写Mode=TwoWay,默认就是双向绑定。

所有方向属性的说明:

image.png


(3)ICommand, ObservableCollection<T> 

- ICommand - 使用了RelayCommand实现

- Command="{Binding AddItemCommand}" - 按钮与命令的绑定

- ObservableCollection<T> - 项目列表使用了此集合类型,添加项目时会自动通知UI更新


例子:

添加项目按钮,清空项目按钮

<!-- 命令按钮区域 -->
<StackPanel Grid.Row="1" Grid.Column="0" Orientation="Horizontal" Margin="0,0,0,20">
    <Button 
        Content="添加项目" 
        Command="{Binding AddItemCommand}" 
        Margin="0,0,10,0" 
        Height="30" 
        Width="100"/>
    <Button 
        Content="清空项目" 
        Command="{Binding ClearItemsCommand}" 
        Height="30" 
        Width="100"/>
    <Button 
        Content="更新显示" 
        Command="{Binding UpdateDisplayCommand}" 
        CommandParameter="自定义参数" 
        Margin="10,0,0,0" 
        Height="30" 
        Width="100"/>
</StackPanel>


<!-- 项目列表区域 -->
        <StackPanel Grid.Row="2" Grid.Column="0" Margin="0,0,20,0">
            <TextBlock Text="项目列表:" FontSize="14" FontWeight="Bold" Margin="0,0,0,5"/>
            <ListBox 
                ItemsSource="{Binding Items}" 
                SelectedIndex="{Binding SelectedIndex, Mode=TwoWay}" 
                Height="300" 
                Width="350"
                BorderBrush="Gray" 
                BorderThickness="1">
                <ListBox.ItemTemplate>
                    <DataTemplate>
                        <TextBlock Text="{Binding}" Padding="5"/>
                    </DataTemplate>
                </ListBox.ItemTemplate>
            </ListBox>
        </StackPanel>


  用户点击“添加项目”按钮后,由于这个按钮绑定了AddItemCommand命令:

Command="{Binding AddItemCommand}"

所以会执行viewModel中的AddItemCommand方法,这个方法是ICommand接口的实现。

至于为啥项目列表控件会实时回显,这是因为它的数据源就是Items

ItemsSource="{Binding Items}"

而Items就是一个ObservableCollection<string>。(观察者集合,集合变化后它会通知项目列表控件更新)

   public ObservableCollection<string> Items { get; set; }



(4)自定义参数

“更新显示”按钮

  <!-- 命令按钮区域 -->
  <StackPanel Grid.Row="1" Grid.Column="0" Orientation="Horizontal" Margin="0,0,0,20">
      <Button 
          Content="添加项目" 
          Command="{Binding AddItemCommand}" 
          Margin="0,0,10,0" 
          Height="30" 
          Width="100"/>
      <Button 
          Content="清空项目" 
          Command="{Binding ClearItemsCommand}" 
          Height="30" 
          Width="100"/>
      <Button 
          Content="更新显示" 
          Command="{Binding UpdateDisplayCommand}" 
          CommandParameter="自定义参数" 
          Margin="10,0,0,0" 
          Height="30" 
          Width="100"/>
  </StackPanel>


上面的CommandParameter="自定义参数"

这个字符串会传到viewModel中的UpdateDisplay方法的parameter中去

 private void UpdateDisplay(string parameter)
 {
     DisplayText = $"更新时间:{DateTime.Now.ToString()},参数:{parameter}";
 }


(5) 控件之间进行数据交互

ElementName允许控件之间进行直接交互。

下图中两个位置用到了这个知识点:

  1.   当前窗口标题

  2. 滑条值(ElementName)


act113.gif


这里以滑条值(ElementName)这个例子说明一下:

1、 首先要给滑动条命名

image.png

2、指定ElementName

{Binding Value, ElementName=fontSizeSlider, StringFormat={}{0:F1}}

中,Value就是滑动条的Value,它是个double,因此后面的StringFormat就负责做数据显示格式化。

ElementName则是控件的x:Name(注意x:Name可不是控件的Name)


<Grid Margin="0,5,0,0">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="150"/>
                    <ColumnDefinition Width="*"/>
                </Grid.ColumnDefinitions>
                <TextBlock Text="滑动条值(ElementName):" Grid.Column="0" VerticalAlignment="Center"/>
                <TextBlock 
                    Grid.Column="1" 
                    Text="{Binding Value, ElementName=fontSizeSlider, StringFormat={}{0:F1}}" 
                    VerticalAlignment="Center" 
                    Foreground="Red"/>
            </Grid>


(6) 数据模板

作用:定义数据如何在UI上显示

例子:项目列表的数据模板

<ListBox.ItemTemplate>
    <DataTemplate>
        <TextBlock Text="{Binding}" Padding="5"/>
    </DataTemplate>
</ListBox.ItemTemplate>

- {Binding} :这是一个 空路径绑定 ,表示绑定到 整个数据项本身

- ItemsSource="{Binding Items}" :ListBox 的数据源是 ViewModel 中的 Items 集合(类型为 ObservableCollection<string> )

- 每个数据项 :由于 Items 是字符串集合,每个数据项都是一个 string 值


模板还可以更灵活:

1、 包含多个控件;绑定类的属性

<ListBox ItemsSource="{Binding People}">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <StackPanel Orientation="Horizontal" Margin="5">
                <TextBlock Text="{Binding Name}" Width="100"/>
                <TextBlock Text="{Binding Age}" Width="50"/>
                <TextBlock Text="{Binding Gender}" Width="50"/>
            </StackPanel>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>


2、触发器(触发样式改变)

<DataTemplate>
    <TextBlock Text="{Binding Name}">
        <TextBlock.Style>
            <Style TargetType="TextBlock">
                <Setter Property="Foreground" Value="Black"/>
                <Style.Triggers>
                    <DataTrigger Binding="{Binding Gender}" Value="男">
                        <Setter Property="Foreground" Value="Blue"/>
                    </DataTrigger>
                    <DataTrigger Binding="{Binding Gender}" Value="女">
                        <Setter Property="Foreground" Value="Pink"/>
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </TextBlock.Style>
    </TextBlock>
</DataTemplate>

3、模板重用

<Window.Resources>
    <DataTemplate x:Key="PersonTemplate">
        <!-- 模板内容 -->
    </DataTemplate>
</Window.Resources>

<!-- 多个地方使用同一模板 -->
<ListBox ItemsSource="{Binding People}" ItemTemplate="{StaticResource PersonTemplate}"/>
<ComboBox ItemsSource="{Binding People}" ItemTemplate="{StaticResource PersonTemplate}"/>




(6)  x:Name, Name的区别

问题来源是滑动条控件,它为啥要写成x:Name

<Slider 
    x:Name="fontSizeSlider"
    Grid.Column="1" 
    Minimum="8" 
    Maximum="36" 
    Value="{Binding FontSize, Mode=TwoWay}" 
    VerticalAlignment="Center" Margin="0,0,10,0"/>


image.png


为什么这里必须用 x:Name

在当前示例中,我们需要使用 x:Name="fontSizeSlider" 而不是 Name="fontSizeSlider" ,原因如下:


1. ElementName 绑定的要求

ElementName 绑定依赖于 XAML 解析器在编译时创建的命名作用域(Name Scope)。只有使用 x:Name 时,元素才会被正确注册到命名作用域中, ElementName 绑定才能找到目标元素。


2. 代码生成机制

当使用 x:Name 时,XAML 编译器会在生成的 MainWindow.g.cs 文件中创建一个对应的字段:


// 生成的代码示例

internal System.Windows.Controls.Slider fontSizeSlider;


这样,在运行时,WPF 框架就能通过这个字段找到对应的控件实例。


3. 适用范围更广

x:Name 可以用于所有 XAML 元素,包括非控件元素(如 Storyboard 、 ResourceDictionary 等)。

而 Name 属性只适用于实现了 INameScope 接口的控件。


总结

x:Name 是 XAML 语言层面的属性,它不仅设置控件的名称,还会在编译时创建对应的字段并注册到命名作用域中,

这对于 ElementName 绑定是必需的。而 Name 只是控件的一个普通属性,虽然在很多情况下也能工作,

但在需要通过名称查找元素的场景中, x:Name 更为可靠和通用。


因此,在 WPF XAML 中,当需要为元素命名以便通过 ElementName 绑定或代码访问时,推荐使用 x:Name 属性。




发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

«    2026年2月    »
1
2345678
9101112131415
16171819202122
232425262728
控制面板
您好,欢迎到访网站!
  查看权限
网站分类
搜索
最新留言
文章归档
网站收藏
友情链接

Powered By Z-BlogPHP 1.7.3

Copyright www.skcircle.com Rights Reserved.

鄂ICP备18008319号


站长QQ:496103864 微信:abc496103864