WPF【11_11】WPF实战-重构与美化(配置Material UI框架)-示例

--\App.xaml

<Application x:Class="WPF_CMS.App"

xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

xmlns:local="clr-namespace:WPF_CMS"

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.MergedDictionaries>

</ResourceDictionary>

</Application.Resources>

</Application>

--\MainWindow.xaml

<Window x:Class="WPF_CMS.MainWindow"

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:WPF_CMS"

xmlns:controls="clr-namespace:WPF_CMS.Controls"

xmlns:MaterialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"

xmlns:alex="clr-namespace:WPF_CMS.ArrachedProperties"

mc:Ignorable="d"

Title="CMS客户管理系统" Height="600" Width="900" Background="Transparent" AllowsTransparency="True" WindowStyle="None" WindowStartupLocation="CenterScreen" FontFamily="Cambria">

<Border Background="White" CornerRadius="30">

<Grid>

<Grid.RowDefinitions>

<RowDefinition Height="Auto"/>

<RowDefinition />

</Grid.RowDefinitions>

<Grid.ColumnDefinitions>

<ColumnDefinition Width="240"/>

<ColumnDefinition Width="280"/>

<ColumnDefinition />

</Grid.ColumnDefinitions>

<!--header-->

<controls:HeaderControl Grid.ColumnSpan="3"/>

<StackPanel Grid.Row="1" Grid.Column="0">

<Button Content="添加客户" Click="ClearSelectedCustomer_Click" Width="192" Margin="10"/>

<ListView ItemsSource="{Binding Customers, Mode=OneWay}" DisplayMemberPath="Name" SelectedItem="{Binding SelectedCustomer, Mode=TwoWay}" />

</StackPanel>

<MaterialDesign:Card Grid.Row="1" Grid.Column="1" Width="250" Height="440" Margin="10">

<StackPanel >

<Border Margin="10" CornerRadius="20" Background="#FFFFEEFA">

<Image Source="/Images/cartoon.png" Stretch="Uniform" Height="150" />

</Border>

<TextBox

Name="NameTextBox"

Margin="10"

Style="{StaticResource MaterialDesignOutlinedTextBox}"

MaterialDesign:HintAssist.Hint="姓名"

Text="{Binding SelectedCustomer.Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>

<TextBox

Name="IdTextBox"

Margin="10"

Style="{StaticResource MaterialDesignOutlinedTextBox}"

MaterialDesign:HintAssist.Hint="身份证"

Text="{Binding SelectedCustomer.IdNnumber, Mode=TwoWay}" />

<TextBox

Name="AddressTextBox"

Margin="10"

Style="{StaticResource MaterialDesignOutlinedTextBox}"

MaterialDesign:HintAssist.Hint="地址"

Text="{Binding SelectedCustomer.Address, Mode=TwoWay}" />

<Button Content="保存" Margin="10 10 10 30" VerticalAlignment="Bottom" HorizontalAlignment="Left" Click="SaveCustomer_Click" />

</StackPanel>

</MaterialDesign:Card>

<MaterialDesign:Card Grid.Row="1" Grid.Column="2" Width="310" Margin="35, 30 35, 30">

<StackPanel Grid.Row="1" Grid.Column="2">

<!--<ListView ItemsSource="{Binding Appointments, Mode=TwoWay}" DisplayMemberPath="Time"/>-->

<Calendar Name="AppointmentCalender" Height="320" Width="300" alex:CalendarAttachedProperties.RegisterBlackoutDates="{Binding Appointments, Mode=OneWay}" SelectedDate="{Binding SelectedDate, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">

</Calendar>

<Button Content="预约" Click="AddAppointment_Click" Width="190" Margin="10" />

</StackPanel>

</MaterialDesign:Card>

</Grid>

</Border>

</Window>

--\MainWindow.xaml.cs

public partial class MainWindow : Window

{

private MainViewModel _viewModel;

public MainWindow()

{

InitializeComponent();

_viewModel = new MainViewModel();

_viewModel.LoadCustomers();

DataContext = _viewModel;

//ShowCustomers();

}

private void ClearSelectedCustomer_Click(object sender, RoutedEventArgs e)

{

_viewModel.ClearSelectedCustomer();

}

private void SaveCustomer_Click(object sender, RoutedEventArgs e)

{

try

{

string name = NameTextBox.Text.Trim();

string idNumber = IdTextBox.Text.Trim();

string address = AddressTextBox.Text.Trim();

_viewModel.SaveCustomer(name, idNumber, address);

}

catch (Exception error)

{

MessageBox.Show(error.ToString());

}

}

private void AddAppointment_Click(object sender, RoutedEventArgs e)

{

try

{

_viewModel.AddAppointment();

}

catch (Exception error)

{

MessageBox.Show(error.ToString());

}

}

}

--\ArrachedProperties\CalendarAttachedProperties.cs

namespace WPF_CMS.ArrachedProperties

{

// Adds a collection of command bindings to a date picker's existing BlackoutDates collection, since the collections are immutable and can't be bound to otherwise.

// Usage: <DatePicker hacks:AttachedProperties.RegisterBlackoutDates="{Binding BlackoutDates}" >

public class CalendarAttachedProperties : DependencyObject

{

#region Attributes

private static readonly List<Calendar> _calendars = new List<Calendar>();

private static readonly List<DatePicker> _datePickers = new List<DatePicker>();

#endregion

#region Dependency Properties

public static DependencyProperty RegisterBlackoutDatesProperty = DependencyProperty.RegisterAttached("RegisterBlackoutDates", typeof(ObservableCollection<DateTime>), typeof(CalendarAttachedProperties), new PropertyMetadata(null, OnRegisterCommandBindingChanged));

public static void SetRegisterBlackoutDates(DependencyObject d, ObservableCollection<DateTime> value)

{

d.SetValue(RegisterBlackoutDatesProperty, value);

}

public static ObservableCollection<DateTime> GetRegisterBlackoutDates(DependencyObject d)

{

return (ObservableCollection<DateTime>)d.GetValue(RegisterBlackoutDatesProperty);

}

#endregion

#region Event Handlers

private static void CalendarBindings_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)

{

ObservableCollection<DateTime> blackoutDates = sender as ObservableCollection<DateTime>;

Calendar calendar = _calendars.First(c => c.Tag == blackoutDates);

if (e.Action == NotifyCollectionChangedAction.Reset)

{

calendar.BlackoutDates.Clear();

}

if (e.Action == NotifyCollectionChangedAction.Add)

{

foreach (DateTime date in e.NewItems)

{

calendar.BlackoutDates.Add(new CalendarDateRange(date));

}

}

}

private static void DatePickerBindings_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)

{

ObservableCollection<DateTime> blackoutDates = sender as ObservableCollection<DateTime>;

DatePicker datePicker = _datePickers.First(c => c.Tag == blackoutDates);

if (e.Action == NotifyCollectionChangedAction.Add)

{

foreach (DateTime date in e.NewItems)

{

datePicker.BlackoutDates.Add(new CalendarDateRange(date));

}

}

}

#endregion

#region Private Methods

private static void OnRegisterCommandBindingChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)

{

Calendar calendar = sender as Calendar;

if (calendar != null)

{

ObservableCollection<DateTime> bindings = e.NewValue as ObservableCollection<DateTime>;

if (bindings != null)

{

if (!_calendars.Contains(calendar))

{

calendar.Tag = bindings;

_calendars.Add(calendar);

}

calendar.BlackoutDates.Clear();

foreach (DateTime date in bindings)

{

calendar.BlackoutDates.Add(new CalendarDateRange(date));

}

bindings.CollectionChanged += CalendarBindings_CollectionChanged;

}

}

else

{

DatePicker datePicker = sender as DatePicker;

if (datePicker != null)

{

ObservableCollection<DateTime> bindings = e.NewValue as ObservableCollection<DateTime>;

if (bindings != null)

{

if (!_datePickers.Contains(datePicker))

{

datePicker.Tag = bindings;

_datePickers.Add(datePicker);

}

datePicker.BlackoutDates.Clear();

foreach (DateTime date in bindings)

{

datePicker.BlackoutDates.Add(new CalendarDateRange(date));

}

bindings.CollectionChanged += DatePickerBindings_CollectionChanged;

}

}

}

}

#endregion

}

}

--\ViewModels\MainViewModel.cs

public class MainViewModel : INotifyPropertyChanged

{

public event PropertyChangedEventHandler PropertyChanged;

private void RaisePropertyChanged(string propertyName)

{

PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));

}

//public List<Customer> Customers { get; set; } = new();

public ObservableCollection<CustomerViewModel> Customers { get; set; } = new();

public ObservableCollection<DateTime> Appointments { get; set; } = new();

private DateTime? _selectedDate;

public DateTime? SelectedDate { get => _selectedDate;

set

{

if(_selectedDate != value)

{

_selectedDate = value;

RaisePropertyChanged(nameof(SelectedDate));

}

} }

private CustomerViewModel _selectedCustomer;

public CustomerViewModel SelectedCustomer

{

get => _selectedCustomer;

set

{

if (value != _selectedCustomer)

{

_selectedCustomer = value;

RaisePropertyChanged(nameof(SelectedCustomer));

LoadAppointments(SelectedCustomer.Id);

}

}

}

public void LoadCustomers()

{

Customers.Clear();

using (var db = new AppDbContext())

{

// Select * from Customers as c join Appointments as a on c.Id = a. CustomerId

var customers = db.Customers

//.Include(c => c.Appointments)

.ToList();

foreach (var c in customers)

{

Customers.Add(new CustomerViewModel(c));

}

}

}

public void ClearSelectedCustomer()

{

_selectedCustomer = null;

RaisePropertyChanged(nameof(SelectedCustomer));

}

public void SaveCustomer(string name, string idNumber, string address)

{

if(SelectedCustomer != null)

{

// 更新客户数据

using (var db = new AppDbContext())

{

var customer = db.Customers.Where(c => c.Id == SelectedCustomer.Id).FirstOrDefault();

customer.Name = name;

customer.IdNnumber = idNumber;

customer.Address = address;

db.SaveChanges();

}

}

else

{

// 添加新客户

using (var db = new AppDbContext())

{

var newCustomer = new Customer()

{

Name = name,

IdNnumber = idNumber,

Address = address

};

db.Customers.Add(newCustomer);

db.SaveChanges();

}

LoadCustomers();

}

}

public void LoadAppointments(int customerId)

{

Appointments.Clear();

using (var db = new AppDbContext())

{

var appointments = db.Appointments.Where(a => a.CustomerId == customerId).ToList();

foreach(var a in appointments)

{

Appointments.Add(a.Time);

}

}

}

public void AddAppointment()

{

if (SelectedCustomer == null)

{

return;

}

using (var db = new AppDbContext())

{

var newAppointment = new Appointment()

{

Time = SelectedDate.Value,

CustomerId = SelectedCustomer.Id

};

db.Appointments.Add(newAppointment);

db.SaveChanges();

}

SelectedDate = null;

LoadAppointments(SelectedCustomer.Id);

}

}

最终效果示例图

相关推荐
LHX sir1 小时前
低代码革命遇瓶颈?这个“套娃神技“才是破局关键!
前端·ui·前端框架·交互·团队开发·软件需求·极限编程
LHX sir3 小时前
巨头撤退,玩家内卷!2025,IoT平台的生死劫与重生路
开发语言·前端·物联网·低代码·ui·前端框架·交互
我要打打代码3 小时前
wpf触发器
java·linux·wpf
Trust yourself2435 小时前
如何获取easy-ui的表格的分页大小
前端·javascript·ui·oracle
The Sheep 20236 小时前
WPF里的几何图形Path绘制
wpf
安卓开发者6 小时前
鸿蒙Next图形绘制指南:从基础几何图形到复杂UI设计
ui·华为·harmonyos
somethingGoWay7 小时前
wpf 自定义密码文本框,并且可以双向绑定
wpf
xiaopengbc8 小时前
Adobe Illustrator 2025最新破解教程下载安装教程,Illustrator2025最新版下载
ui·adobe·illustrator
程序边界11 小时前
Unity开发保姆级教程:C#脚本+物理系统+UI交互,3大模块带你通关游戏开发
ui·unity·c#
魏波.18 小时前
UI自动化测试之Selenium元素定位8大方式
selenium·测试工具·ui