WPF
2023/03/06写一天wpf的一点心得
从设计上和vue还是很像的
和vue的一些对比, vue的响应式是通过proxy实现的, 但是C#没有proxy, 所以绑定model需要自己设置set/get, 从而发射事件,通知主线程重新渲染
ViewModelBase
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
| using System.ComponentModel;
using System.Diagnostics;
namespace Manager_v1.pages.models {
public abstract class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChangedEvent([System.Runtime.CompilerServices.CallerMemberName] string propertyName = "")
{
if (propertyName == "")
{
propertyName = GetCallerMemberName();
}
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
string GetCallerMemberName()
{
StackTrace trace = new StackTrace();
StackFrame frame = trace.GetFrame(2);//1代表上级,2代表上上级,以此类推
var propertyName = frame.GetMethod().Name;
if (propertyName.StartsWith("get_") || propertyName.StartsWith("set_") || propertyName.StartsWith("put_"))
{
propertyName = propertyName.Substring("get_".Length);
}
return propertyName;
}
}
}
|
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
| using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Data;
using System.Windows;
namespace Manager_v1.pages.models {
public class DashboardStore : ViewModelBase {
private string _age;
public string Age {
set {
_age = value;
RaisePropertyChangedEvent();
}
get => _age;
}
public ObservableCollection<User> List { get; set; } = new ObservableCollection<User>();
public DashboardStore() {
}
}
public class User {
public int Age { get; set; } = 123;
public string Name { get; set; } = "Name 13";
public string ClassName { get; set; } = "ClassName 13";
}
}
|
代码参考如上, 所有的响应式实体类都得通过继承ViewModelBase, 在set里面调用RaisePropertyChangedEvent
v-for 的对比
C#中没有v-for那么灵活的东西, 如果需要实现类似的功能, 首先需要一个支持变化的容器(List, ObservableCollection);
ListBox
自定义循环组件(style是为了删除点击特效)
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
| <ListBox ItemsSource="{Binding List}">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<!-- <Setter Property="IsSelected" Value="{Binding Content.IsSelected, Mode=TwoWay, RelativeSource={RelativeSource Self}}"/> -->
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<ContentPresenter />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Margin="10 10 " Text="{Binding Age}" Width="100" />
<TextBlock Margin="10 10 " Text="{Binding Name}" Width="100" />
<Button Margin="10 10 " Content="Delete" Background="Red" Width="100" />
<!-- <Button Content="{Binding Name}" Width="100" /> -->
<!-- <Button Content='{Binding ClassName}' Width="100" /> -->
</StackPanel>
</DataTemplate>
<!-- <DataTemplate> -->
<!-- <StackPanel Orientation="Horizontal"> -->
<!-- <Button Margin="10 0" Command="{Binding Click}" Content="{Binding Name}" /> -->
<!-- <Button Margin="10 0" Command="{Binding Click}" Content="{Binding Age}" /> -->
<!-- <Button Margin="10 0" Command="{Binding Click}" Content="{Binding ClassName}" /> -->
<!-- </StackPanel> -->
<!-- </DataTemplate> -->
</ListBox.ItemTemplate>
</ListBox>
|
DataGrid
自定义表格:
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
| <DataGrid ItemsSource="{Binding List}" IsReadOnly="True" AutoGenerateColumns="False" CanUserAddRows="False">
<DataGrid.Columns>
<DataGridTemplateColumn Header="operate" Width="*">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Margin="20 10 "
Text="{Binding Name}">
</TextBlock>
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="operate" Width="*">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Margin="20 10 "
Text="{Binding Age}">
</TextBlock>
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="operate" Width="*">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Button HorizontalAlignment="Center" VerticalAlignment="Center" Margin="20 10 "
Click="SayHello" Tag="{Binding }">
CLICK ME
</Button>
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
<!-- <DataGrid.ItemTemplate> -->
<!-- <DataTemplate> -->
<!-- <StackPanel Orientation="Horizontal"> -->
<!-- <TextBlock Margin="10 10 " Text="{Binding Name}"></TextBlock> -->
<!-- <TextBlock Margin="10 10 " Text="{Binding Age}"></TextBlock> -->
<!-- <Button>DELETE ME </Button> -->
<!-- </StackPanel> -->
<!-- </DataTemplate> -->
<!-- </DataGrid.ItemTemplate> -->
</DataGrid>
|
1
2
3
4
5
6
7
8
9
10
11
12
| 3. ```
## StackPanel
这是一个类似div的东西
## 关于循环点击事件的绑定
```C#
private void SayHello(object sender, RoutedEventArgs e) {
Button btn = (Button)sender;
User user = (User)btn.Tag; // tag就是参数
}
|
1
2
3
4
5
| <StackPanel Orientation="Horizontal">
<Button HorizontalAlignment="Center" VerticalAlignment="Center" Margin="20 10 " Click="SayHello" Tag="{Binding }">
CLICK ME
</Button>
</StackPanel>
|
Material 初始化
App.xaml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| <Application x:Class="Manager_v1.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Manager_v1"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
StartupUri="MainWindow.xaml">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<materialDesign:BundledTheme BaseTheme="Light" PrimaryColor="DeepPurple" SecondaryColor="Lime" />
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Defaults.xaml" />
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Light.xaml" />
<ResourceDictionary Source="pack://application:,,,/MaterialDesignColors;component/Themes/Recommended/Primary/MaterialDesignColor.DeepPurple.xaml" />
<ResourceDictionary Source="pack://application:,,,/MaterialDesignColors;component/Themes/Recommended/Accent/MaterialDesignColor.Lime.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
|
Frame
类似router-view, 但是他有个前后箭头, 需要手动去掉
1
| <Frame Source="./pages/Login.xaml" NavigationUIVisibility="Hidden"></Frame>
|
窗口切换
代码如下, new新窗口对象, 关闭自己即可
1
2
3
4
5
| private void OnExit(object sender, RoutedEventArgs e) {
Window dashboard = new MainWindow();
dashboard.Show();
Close();
}
|
路由式切换
1
2
3
4
5
6
|
private void OnClick(object sender, RoutedEventArgs e) {
Uri uri = new Uri("./pages/Login.xaml", UriKind.Relative);
if (NavigationService != null)
NavigationService.Source = (uri);
}
|