0%

WPF MVVM示例一

深入浅出WPF示例, 理解Binding实现

示例

功能: 实现按钮计算更新TextBox数据

Cal

数据属性NotificationObject

当属性被赋值时调用RaisePropertyChanged触发PropertyChanged

1
2
3
4
5
6
7
8
9
public class NotificationObject : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;

public void RaisePropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}

命令属性DelegateCommand

View中按钮按下等触发命令后执行Execute

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class DelegateCommand : ICommand
{
public event EventHandler CanExecuteChanged;

public bool CanExecute(object parameter)
{
if(CanExcuteFunc == null)
return true;
return CanExcuteFunc(parameter);
}

public void Execute(object parameter)
{
if (ExecuteAction == null)
return;
ExecuteAction(parameter);
}

public Action<object> ExecuteAction { get; set; }

public Func<object, bool> CanExcuteFunc { get; set; }
}

MainWindowViewModel

示例中Cal``Button按下后触发执行CanExecute若返回true则执行Execute, 在构造中添加ExecuteAction执行方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
public class MainWindowViewModel : NotificationObject
{
private double num1;

public double Num1
{
get { return num1; }
set
{
num1 = value;
RaisePropertyChanged(nameof(Num1));
}
}

private double num2;

public double Num2
{
get { return num2++; }
set
{
num2 = value;
RaisePropertyChanged(nameof(Num2));
}
}

private double num3;

public double Num3
{
get { return num3; }
set
{
num3 = value;
RaisePropertyChanged(nameof(Num3));
}
}

public DelegateCommand AddCommand { get; set; }

void Add(object param)
{
Num3 = Num1 + Num2;
}
public MainWindowViewModel()
{
AddCommand = new DelegateCommand
{
ExecuteAction = Add
};
}
}

数据层DataContext

DataContext = new MainWindowViewModel();

指定Banding上下文即业务逻辑

如上述示例 Banding绑定的是MainWindowViewModel类里的属性名

DataContext设置方法

1. 初始化时添加
1
2
3
4
5
public MainWindow()
{
InitializeComponent();
this.DataContext = new MainWindowViewModel();
}
2. xamld:DataContext指定
1
2
xmlns:viewmodel="clr-namespace:LearnWpf.ViewModel" 
d:DataContext="{d:DesignInstance Type=viewmodel:MainWindowViewModel}"
3. xaml中添加
1
2
3
<Window.DataContext>
<viewmodel:MainWindowViewModel/>
</Window.DataContext>

Banding DataContext说明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!-- 注意此时我已经在初始化代码中设置DataContext 为 ClassA,DataContext = new ClassA -->
<Window x:Name="MyWindow">
<!-- DataContext 没有被指定,所以继承自父类 的 DataContext,也就是 ClassA -->
<StackPanel>
<!-- DataContext 继承自父类,也就是 ClassA, 所以这里会显示 ClassA.Name -->
<Label Content="{Binding Name}"/>
<!-- DataContext 仍然是ClassA, 但是我们通过binding设置为ClassA.ClassB-->
<StackPanel DataContext="{Binding ClassB}">
<!-- DataContext 继承自父类,也就是ClassB,所以这里会显示 ClassB.Name -->
<Label Content="{Binding Name}"/>
<!-- DataContext i仍然是 ClassB, 但是我们binding 到了Window's DataContext.Name, 也就是 ClassA.Name -->
<Label Content="{Binding ElementName=MyWindow, Path=DataContext.Name}"/>
</StackPanel>
<!-- We've left the StackPanel with its DataContext bound to ClassB, so this Label's DataContext is ClassA (inherited from parent StackPanel), and we are binding to ClassA.ClassB.Name -->
<Label Content="{Binding ClassB.Name}"/>
</StackPanel>
</Window>