1.IValueConverter 是什么?解决什么问题?
1.1 定义
IValueConverter是WPF中用于数据绑定时进行值转换的接口。
C#
namespace System.Windows.Data
{
public interface IValueConverter{
object Convert(object value, Type targetType, object parameter, CultureInfo culture);
object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture);
}
}
当需要调用时,实现该接口并重写Convert和ConvertBack,以下分别叙述这两个方法的用途
1.2 核心作用
当ViewModle中的数据类型,不能直接用View展示,即ViewModel与View对应的数据类型不一致时,需要使用该接口进行数据类型转换,IValueConverter起到了"翻译官"的角色。
2.为什么要使用值转换器?
在 MVVM 模式中:
- ViewModel 只暴露 业务含义的数据
- View 需要 UI 能理解的类型
典型示例:
| ViewModel数据 | View |
|---|---|
| bool | Visibility |
| enum | Style |
| DataTime | string |
为了解决这样的类型不匹配,需要使用值转换器
3.IValueConverter 的生命周期与执行时机
3.1 执行时机
IValueConverter的实现类对象会在以下情况被调用
- 绑定源属性首次赋值
- 绑定源属性发生变化(INotifyPropertyChanged)
- 绑定目标需要重新计算显示值
3.2 执行方向
ViewModel -> View 调用Convert方法
View -> ViewModel 调用ConvertBack方法
4.Convert 与 ConvertBack 的职责划分
4.1 Convert
C#
object Convert(object value, Type targetType,object parameter, CultureInfo culture);
| 参数 | 含义 |
|---|---|
| value | 当前传递的值,在Concert中来自ViewModel |
| targetType | 目标属性类型 |
| parameter | XAML传入的附加参数 |
| culture | 区域信息 |
4.2CovertBack
C#
object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture);
| 参数 | 含义 |
|---|---|
| value | 当前传递的值,来自View |
| targetType | 目标属性类型 |
| parameter | XAML传入的附加参数 |
| culture | 区域信息 |
一般不具体实现
C#
object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture){
Binding.DoNothing;
}
在以下两种情况需要具体实现
- Mode=TwoWay
XAML
{Binding Path=... Mode=TwoWay}
- View需要回写到ViewModel中
5.具体实例
需要实现导航栏按钮被按下后,样式改变以提醒用户界面切换,为了完成该需求,可以在ViewModel中维护一个枚举属性来记录当前的访问界面
C#
//枚举
```
public enum MainWindowMenuItem
{
Menu1,
Menu2,
Menu3,
Menu4,
Menu5,
Menu6,
Menu7,
Menu8,
Menu9
}
```
public partial class MainWindowViewModel : ObservableObject
{
...Other...
[ObservableProperty] private MainWindowMenuItem _selectedMenuItem = MainWindowMenuItem.Menu1;
...Other...
}
XAML
<Button
Style="{Binding SelectedMenuItem,Converter={StaticResource MenuConverter},ConverterParameter={x:Static local:MainWindowMenuItem.Menu1}}"
Command="{Binding SelectMenuCommand}"
CommandParameter="{x:Static local:MainWindowMenuItem.Menu1}">
<Button.Content>
...
</Button.Content>
</Button>
可以看到这个按钮绑定了一个传入枚举的命令,当点击它的时候,他会修改ViewModel中的SelectedMenuItem属性,当该属性被修改时,会把对应的枚举值交给值转换器,然后对比按钮上的parameter,将被点击的按钮的样式修改为SelectedButtonStyle。
C#
public class MenuConverter:IValueConverter
{
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
{
var normal = (Style)Application.Current.Resources["NormalButtonStyle"];
var selected = (Style)Application.Current.Resources["SelectedButtonStyle"];
if (value == null || parameter == null)
return normal;
return value.Equals(parameter) ? selected : normal;
}
public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
{
return Binding.DoNothing;
}
}