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
程序运行效果:

解决方案:

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

UpdateSourceTrigger=PropertyChanged:
实现输入时实时更新绑定源(就是InputText),而不用等到这个控件失去焦点时才更新InputText
在上面的例子里准备了一个TextBlock,并绑定了InputText,于是你会见到输入的字符会即时回显出来的效果
<TextBlock Text="{Binding InputText}"

(2)双向绑定 (TwoWay Binding)
核心概念 :实现了UI控件与数据源之间的双向数据流动
例子:

<!-- 字体大小调整区域 -->
<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,默认就是双向绑定。
所有方向属性的说明:

(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允许控件之间进行直接交互。
下图中两个位置用到了这个知识点:
当前窗口标题
滑条值(ElementName)

这里以滑条值(ElementName)这个例子说明一下:
1、 首先要给滑动条命名

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"/>
为什么这里必须用 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 属性。