国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

C#學習(十)——WPF重構(gòu)與美化

這篇具有很好參考價值的文章主要介紹了C#學習(十)——WPF重構(gòu)與美化。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

一、Entity Framework Core

特點:【跨平臺】,【建?!浚静樵?、更改、保存】,【并發(fā)】,【事務(wù)】,【緩存】,【數(shù)據(jù)遷移】

EF的組件
C#學習(十)——WPF重構(gòu)與美化,c#,學習,wpf,重構(gòu),ui

二、重構(gòu):構(gòu)建數(shù)據(jù)模型

項目延續(xù)C#學習(九)的 項目代碼,以此基礎(chǔ)進行進一步重構(gòu)
所需的NuGet包如下:
C#學習(十)——WPF重構(gòu)與美化,c#,學習,wpf,重構(gòu),ui
C#學習(十)——WPF重構(gòu)與美化,c#,學習,wpf,重構(gòu),ui

逆向數(shù)據(jù)庫獲得數(shù)據(jù)模型(Model)
首先在根目錄下創(chuàng)建Models文件夾,然后使用Tools->NuGet包管理器->程序包管理器控制臺
輸入指令

Scaffold-DbContext "自己的數(shù)據(jù)庫連接字符串" Microsoft.EntityFrameworkCore.Sqlserver -OutputDir Models -Context AppDbContext

處理完成后,就可以在Models文件夾中看到通過逆向數(shù)據(jù)庫構(gòu)建的數(shù)據(jù)模型啦!

三、OMR數(shù)據(jù)管理

使用Entity Framework 取代SQL語句
使用ORM來自動生成SQL語句,通過數(shù)據(jù)庫的映射框架獲取數(shù)據(jù)模型,通過模型框架的鏈式結(jié)構(gòu)來處理數(shù)據(jù),可以使業(yè)務(wù)實現(xiàn)在代碼中,而不是實現(xiàn)在SQL語句中。因此對于程序員來說,使用對象的鏈式結(jié)構(gòu)更加符合面向?qū)ο蟮木幊汤砟睢?/p>

通過數(shù)據(jù)模型向UI傳遞和綁定數(shù)據(jù)
代碼改進后如下:
MainWindow.xaml.cs

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        ShowCustomers();
    }
    //訪問數(shù)據(jù)庫
    private void ShowCustomers()
    {
        try
        {
            using(var db = new AppDbContext())
            {
                var customers = db.Customers.ToList();
                customerList.DisplayMemberPath = "Name";
                customerList.SelectedValuePath = "Id";
                customerList.ItemsSource = customers;
            }
        }catch (Exception ex)
        {
            MessageBox.Show(ex.ToString());
        }
        
    }

    private void customerList_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        try
        {
            Customer selectedItem = customerList.SelectedItem as Customer;
            if (selectedItem == null)
            {
                appointmentList.ItemsSource = null;
                return;
            }
            NameTextBox.Text = selectedItem.Name;
            IdTextBox.Text = selectedItem.IdNumber;
            AddressTextBox.Text = selectedItem.Address;

            using(var db = new AppDbContext())
            {
                var customerId = customerList.SelectedValue;
                var appointment = db.Appointments
                	.Where(a => a.CustomerId == (int)customerId)
                	.ToList();

                appointmentList.DisplayMemberPath = "Time";
                appointmentList.SelectedValuePath = "Id";
                appointmentList.ItemsSource = appointment;
            }
            
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.ToString());
        }
    }

    private void CancelAppointment_Click(object sender, RoutedEventArgs e)
    {
        try
        {
            var appointmentId = appointmentList.SelectedValue;

            using (var db = new AppDbContext())
            {
                var appointmentToRemove = db.Appointments
                	.Where(a => a.Id == (int)appointmentId)
                	.FirstOrDefault();//因為Id主鍵是唯一選擇,因此這里過濾后不再是列表,而是獨立的對象,因此使用FirstOrDefault

                db.Appointments.Remove(appointmentToRemove);

                db.SaveChanges();
            }

            MessageBox.Show("取消預(yù)約成功!");
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.ToString());
        }
        finally
        {
            customerList_SelectionChanged(null, null);
        }
    }

    private void DeleteCustomer_Click(object sender, RoutedEventArgs e)
    {
        try
        {
            var customerId = customerList.SelectedValue;

            using(var db = new AppDbContext())
            {
                //使用Entity Framework后,不需要進行兩次數(shù)據(jù)庫操作,只需要使用Include方法
                var customerToRemove = db.Customers
                    //.Include(c => c.Appointments)
                    .Where(c => c.Id == (int)customerId)
                    .Include(c => c.Appointments)
                    .FirstOrDefault();
                
                db.Customers.Remove(customerToRemove);
                db.SaveChanges();
            }

            MessageBox.Show("刪除用戶成功!");
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.ToString());
        }
        finally
        {
            ShowCustomers();
            customerList_SelectionChanged(null, null);
        }
    }

    private void AddCustomer_Click(object sender, RoutedEventArgs e)
    {
        try
        {
            using (var db = new AppDbContext())
            {
                var customer = new Customer()
                {
                    Name = NameTextBox.Text,
                    IdNumber = IdTextBox.Text,
                    Address = AddressTextBox.Text
                };
                db.Customers.Add(customer);
                db.SaveChanges();
            }
            MessageBox.Show("添加用戶信息成功!");
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.ToString());
        }
        finally
        {
            ShowCustomers();

        }
    }

    private void AddAppointment_Click(object sender, RoutedEventArgs e)
    {
        try
        {
            using(var db = new AppDbContext())
            {
                var appointment = new Appointment()
                {
                    Time = DateTime.Parse(AppointmentDatePicker.Text),
                    CustomerId = (int)customerList.SelectedValue
                };

                db.Appointments.Add(appointment);
                db.SaveChanges();
            }
            MessageBox.Show("預(yù)約成功!");
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.ToString());
        }
        finally
        {
            customerList_SelectionChanged(null, null);
        }
    }

    private void UpdateCustomer_Click(object sender, RoutedEventArgs e)
    {
        try
        {
            using (var db = new AppDbContext())
            {
                var customer = db.Customers.Where(c => c.Id == (int)customerList.SelectedValue).FirstOrDefault();

                customer.Name = NameTextBox.Text.Trim();
                customer.IdNumber = IdTextBox.Text.Trim();
                customer.Address = AddressTextBox.Text.Trim();

                db.SaveChanges();
            }
            MessageBox.Show("預(yù)約成功!");
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.ToString());
        }
        finally
        {
            ShowCustomers();
        }
    }
}

易報錯點提示
1.聯(lián)級刪除時,會出現(xiàn)appointment表的customerId為空情況,因此需要再customerList_SelectionChanged方法里進行一個判空處理;
2.使用聯(lián)級刪除,使用Entity Framework后,不需要進行兩次數(shù)據(jù)庫操作,只需要使用Include方法,但需要引入using Microsoft.EntityFrameworkCore;
3.注意生成的AppDbContext.cs文件中,OnModelCreating方法中的OnDelete的DeleteBehavior,使用Cascade方法,Automatically deletes dependent entities when the principal is deleted or the
relationship to the principal is severed, but creates a non-cascading foreign key constraint in the database..OnDelete(DeleteBehavior.Cascade)

四、布局重構(gòu)

首先對于原來丑陋的展示頁面進行重新布局,構(gòu)建我們的基礎(chǔ)布局框架

 <Grid>
     <Grid.RowDefinitions>
         <RowDefinition Height="Auto"/>
         <RowDefinition/>
     </Grid.RowDefinitions>
     <Grid.ColumnDefinitions>
         <ColumnDefinition Width="240"/>
         <ColumnDefinition Width="280"/>
         <ColumnDefinition/>
     </Grid.ColumnDefinitions>
     
     <!--header-->
     <Border Grid.ColumnSpan="3" Background="#9a0070">
         <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
         	 <!--隨意添加一個圖片,圖片放置在根目錄文件夾下的Images文件中-->
             <Image Height="90" Margin="5" Source="/Images/logo.jpg"/>
             <TextBlock Text="WPF客戶管理系統(tǒng)" FontSize="40" VerticalAlignment="Center" Foreground="#ffffff"/>
         </StackPanel>
     </Border>
     <StackPanel Grid.Row="1" Grid.Column="0">
         <Button Content="添加客戶"/>
         <ListView/>
     </StackPanel>
     <StackPanel Grid.Row="1" Grid.Column="1">
         <TextBlock Text="姓名" Margin="10 10 10 0"/>
         <TextBox Margin="10"/>
         <TextBlock Text="身份證號" Margin="10 10 10 0"/>
         <TextBox Margin="10"/>
         <TextBlock Text="地址" Margin="10 10 10 0"/>
         <TextBox Margin="10"/>
         <Button Content="保存" Margin="10 10 10 30" VerticalAlignment="Bottom" HorizontalAlignment="Left"/>
     </StackPanel>
     <StackPanel Grid.Row="1" Grid.Column="2">
         <ListView/>
         <TextBlock Text="添加新預(yù)約"/>
         <DatePicker Margin="10"/>
         <Button Content="預(yù)約"/>
     </StackPanel> 
 </Grid>

完成布局的組件化控制
首先在根目錄下創(chuàng)建文件夾“Control”,在文件夾中新建項“用戶控件(WPF)”命名HeaderControl.xaml,將MainWindow.xaml中的header代碼轉(zhuǎn)移至此

HeaderControl.xaml

<Border Grid.ColumnSpan="3" Background="#9a0070">
    <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
        <Image Height="90" Margin="5" Source="/Images/logo.jpg"/>
        <TextBlock Text="WPF客戶管理系統(tǒng)" FontSize="40" VerticalAlignment="Center" Foreground="#ffffff"/>
    </StackPanel>
</Border>

MainWindow.xaml中對應(yīng)部分刪除,替換為

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

五、MVVM架構(gòu)

MVVM指?Model(模型) View(視圖) ViewModel(視圖模型)

直接使用View也可以進行項目的開發(fā),正如上一篇文章所示例的,但是直接使用View訪問數(shù)據(jù)庫,無法完成數(shù)據(jù)的隔離,無法進行復(fù)雜的業(yè)務(wù)開發(fā),甚至無法可持續(xù)的維護系統(tǒng),因此必須進行業(yè)務(wù)與數(shù)據(jù)的隔離,以及業(yè)務(wù)與界面的隔離。因此對于業(yè)務(wù)進行分離后,就得到了視圖模型,視圖模型可以全部或者部分使用模型的字段,模型的字段通過映射的方式向視圖模型提供業(yè)務(wù)的支持,而視圖模型與視圖則雙向綁定,不僅可以讓用戶看到數(shù)據(jù),還可以通過UI交互操作數(shù)據(jù),而視圖模型作為業(yè)務(wù)的載體,也會承擔與數(shù)據(jù)庫的溝通工作,視圖模型會處理一切與UI的交互行為。
C#學習(十)——WPF重構(gòu)與美化,c#,學習,wpf,重構(gòu),ui
MVVM的優(yōu)點

  • [ 兼容MVC架構(gòu) ]
  • [ 業(yè)務(wù)與UI邏輯徹底分開,方便測試 ]
  • [ 方便維護 ]

MVVM的缺點

  • [ 代碼量增加 ]
  • [ 對象調(diào)用復(fù)雜度增加 ]

MVVM項目代碼重構(gòu)
首先,在根目錄下創(chuàng)建文件夾ViewModels,新建項目MainViewModel,CustomerViewModel,AppointmentViewModel
代碼如下:
MainWindow.xaml

<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"/>
        <ListView ItemsSource="{Binding Customers, Mode=OneWay}" DisplayMemberPath="Name" SelectedItem="{Binding SelectedCustomer, Mode=TwoWay}"/>
    </StackPanel>
    <StackPanel Grid.Row="1" Grid.Column="1">
        <TextBlock Text="姓名" Margin="10 10 10 0"/>
        <TextBox x:Name="NameTextBox" Margin="10" Text="{Binding SelectedCustomer.Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
        <TextBlock Text="身份證號" Margin="10 10 10 0"/>
        <TextBox Name="IdTextBox"  Margin="10" Text="{Binding SelectedCustomer.IdNumber, Mode=TwoWay}"/>
        <TextBlock Text="地址" Margin="10 10 10 0"/>
        <TextBox x:Name="AddressTextBox" Margin="10" Text="{Binding SelectedCustomer.Address, Mode=TwoWay}"/>
        <Button Content="保存" Margin="10 10 10 30" VerticalAlignment="Bottom" HorizontalAlignment="Left" Click="SaveCustomer_Click"/>
    </StackPanel>
    <StackPanel Grid.Row="1" Grid.Column="2">
        <ListView ItemsSource="{Binding Appointments, Mode=TwoWay}" DisplayMemberPath="Time"/>
        <TextBlock Text="添加新預(yù)約"/>
        <DatePicker Name="AppointmentDatePicker" Margin="10"/>
        <Button Content="預(yù)約" Click="AddAppointment_Click"/>
    </StackPanel> 
</Grid>

MainWindow.xaml.cs

public partial class MainWindow : Window
{
    private MainViewModel _viewModel;
    public MainWindow()
    {
        InitializeComponent();
        _viewModel = new MainViewModel();

        _viewModel.LoadCustomers();

        DataContext = _viewModel;
    }

    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 ex)
        {
            MessageBox.Show(ex.ToString());
        }
    }

    private void AddAppointment_Click(object sender, RoutedEventArgs e)
    {
        try
        {
            DateTime time = DateTime.Parse(AppointmentDatePicker.Text);
            _viewModel.AddAppointment(time);
        }catch (Exception ex)
        {
            MessageBox.Show(ex.ToString());
        }
    }
}

AppointmentViewModel.cs

public class AppointmentViewModel
{
    private Appointment _appointment;

    public AppointmentViewModel(Appointment appointment)
    {
        _appointment = appointment;
    }
	//因為Id為只讀屬性,因此不需要set
    public int Id { get => _appointment.Id; }

    public DateTime Time { get => _appointment.Time; set
        {
        	//有且僅當數(shù)據(jù)發(fā)生變化,才向數(shù)據(jù)庫寫入數(shù)據(jù)
            if(value != _appointment.Time)
            {
                _appointment.Time = value;
            }
        }      
    }
}

CustomerViewModel.cs

public class CustomerViewModel
{
    private Customer _customer;

    public CustomerViewModel(Customer customer)
    {
        _customer = customer;
    }

    public int Id { get => _customer.Id; }

    public string Name { get => _customer.Name; set 
        {
            if(_customer.Name != value)
            {
                _customer.Name = value;
            }
        } 
    }public string IdNumber { get => _customer.IdNumber; set 
        {
            if(_customer.IdNumber != value)
            {
                _customer.IdNumber = value;
            }
        } 
    }public string Address { get => _customer.Address; set 
        {
            if(_customer.Address != value)
            {
                _customer.Address = value;
            }
        } 
    }
}

MainViewModel.cs

//INotifyPropertyChanged刷新更新的屬性
public class MainViewModel : INotifyPropertyChanged
{
    //初始化空列表避免程序運行過程中出現(xiàn)為止的內(nèi)存問題
    //使用觀察者模式ObservableCollection實時更新添加后的客戶數(shù)據(jù)
    public ObservableCollection<CustomerViewModel> Customers { get; set; } = new();
    public ObservableCollection<AppointmentViewModel> Appointments { get; set; } = new();

    private CustomerViewModel _selectedCustomer;

    public event PropertyChangedEventHandler? PropertyChanged;

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

    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())
        {
            var customers = db.Customers.ToList();

            foreach (var customer in customers)
            {
                Customers.Add(new CustomerViewModel(customer));
            }

        }
    }

    public void ClearSelectedCustomer()
    {
        _selectedCustomer = null;
        RaisePropertyChanged(nameof(SelectedCustomer));
    }

    public void SaveCustomer(string name, string idNumber, string address)
    {
        if(SelectedCustomer != null)
        {
            //更新客戶數(shù)據(jù)
            using (var db = new AppDbContext())
            {
                var customer = db.Customers.Where(c => c.Id == SelectedCustomer.Id).FirstOrDefault();
                customer.Name = name;
                customer.IdNumber = idNumber;
                customer.Address = address;
                db.SaveChanges();
            }
        }
        else
        {
            //添加新客戶
            using (var db = new AppDbContext())
            {
                var newCustomer = new Customer()
                {
                    Name = name,
                    IdNumber = 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(new AppointmentViewModel(a));
            }
        }
    }

    public void AddAppointment(DateTime selectedDate)
    {
        if(SelectedCustomer == null) { return; }

        using (var db = new AppDbContext())
        {
            var newAppointment = new Appointment()
            {
                Time = selectedDate,
                CustomerId = SelectedCustomer.Id
            };
            db.Appointments.Add(newAppointment);
            db.SaveChanges();
        }
        LoadAppointments(SelectedCustomer.Id);
    }
}

六、Material UI框架

安裝Material UI框架
C#學習(十)——WPF重構(gòu)與美化,c#,學習,wpf,重構(gòu),ui
接著訪問Material Design Themes的項目URL,可以看到對于此框架的使用講解,將示例中的想使用顏色模式的代碼部分,復(fù)制粘貼到App.xaml文件中,即可應(yīng)用
示例代碼:

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

在進一步優(yōu)化中,我們想要實現(xiàn)在日歷上顯示預(yù)約,對于已經(jīng)有預(yù)約的日期,不可在預(yù)約這樣的效果。想到可以使用BlackoutDates,然而BlackoutDates不支持數(shù)據(jù)的綁定,也就是無法傳入數(shù)據(jù),因此需要使用其他方法進行。
這里借用作大神的方法進行操作,完美解決我們的需求!
根目錄創(chuàng)建文件夾AttachedProperties,創(chuàng)建文件CalendarAttachedProperties
在大神基礎(chǔ)上對于我們的項目略加調(diào)整------原答案地址
CalendarAttachedProperties.cs

// 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
}

在我們的MainWindow.xaml里面引入命名空間xmlns:crackpot="clr-namespace:WPF_CMS.AttachedProperties"
關(guān)于整個窗口的設(shè)計 Title="客戶管理系統(tǒng)" Height="600" Width="1000" Background="Transparent" AllowsTransparency="True" WindowStyle="None" WindowStartupLocation="CenterScreen" FontFamily="Cambria">
MainWindow.xaml

<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" Cursor=""/>
        <StackPanel Grid.Row="1" Grid.Column="0">
            <Button Content="添加客戶" Click="ClearSelectedCustomer_Click" Width="195" Height="33" 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 x: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.IdNumber, Mode=TwoWay}"/>
                <TextBox x: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="270" Margin="35 30 35 30">
            <StackPanel Grid.Row="1" Grid.Column="2">
                <!--<ListView ItemsSource="{Binding Appointments, Mode=TwoWay}" DisplayMemberPath="Time"/>-->
                <Calendar Name="AppointmentCalendar" Height="320" Width="300" 
                          crackpot:CalendarAttachedProperties.RegisterBlackoutDates="{Binding Appointments, Mode=OneWay}"
                          SelectedDate="{Binding SelectedDate, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Cursor="Hand">
                </Calendar>
                <Button Content="預(yù)約" Click="AddAppointment_Click" Width="226" Cursor="Hand"/>
            </StackPanel>
        </MaterialDesign:Card>
    </Grid>
</Border>

由于更改為日歷點擊預(yù)約,因此相關(guān)邏輯代碼也需要更改調(diào)整
MainWindow.xaml.cs

public partial class MainWindow : Window
{
    private MainViewModel _viewModel;
    public MainWindow()
    {
        InitializeComponent();
        _viewModel = new MainViewModel();

        _viewModel.LoadCustomers();

        DataContext = _viewModel;

    }

    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 ex)
        {
            MessageBox.Show(ex.ToString());
        }
    }

    private void AddAppointment_Click(object sender, RoutedEventArgs e)
    {
        try
        {
            _viewModel.AddAppointment();
        }catch (Exception ex)
        {
            MessageBox.Show(ex.ToString());
        }
    }
}

MainViewModel.cs

//INotifyPropertyChanged刷新更新的屬性
public class MainViewModel : INotifyPropertyChanged
{
    //初始化空列表避免程序運行過程中出現(xiàn)為止的內(nèi)存問題
    //public List<Customer> Customers { get; set; } = new();
    //使用觀察者模式ObservableCollection實時更新添加后的客戶數(shù)據(jù)
    public ObservableCollection<CustomerViewModel> Customers { get; set; } = new();
    public ObservableCollection<DateTime> Appointments { get; set; } = new();
	//selectedDate可能為空
    private DateTime? _selectedDate;
    public DateTime? SelectedDate
    {
        get => _selectedDate;
        set
        {
            if(_selectedDate != value)
            {
                _selectedDate = value;
                RaisePropertyChanged(nameof(SelectedDate));
            }
        }
    }

    private CustomerViewModel _selectedCustomer;

    public event PropertyChangedEventHandler? PropertyChanged;

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

    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())
        {
            var customers = db.Customers.ToList();

            foreach (var customer in customers)
            {
                Customers.Add(new CustomerViewModel(customer));
            }

        }
    }

    public void ClearSelectedCustomer()
    {
        _selectedCustomer = null;
        RaisePropertyChanged(nameof(SelectedCustomer));
    }

    public void SaveCustomer(string name, string idNumber, string address)
    {
        if(SelectedCustomer != null)
        {
            //更新客戶數(shù)據(jù)
            using (var db = new AppDbContext())
            {
                var customer = db.Customers.Where(c => c.Id == SelectedCustomer.Id).FirstOrDefault();
                customer.Name = name;
                customer.IdNumber = idNumber;
                customer.Address = address;
                db.SaveChanges();
            }
        }
        else
        {
            //添加新客戶
            using (var db = new AppDbContext())
            {
                var newCustomer = new Customer()
                {
                    Name = name,
                    IdNumber = 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);
    }
}

到此,本項目結(jié)束文章來源地址http://www.zghlxwxcb.cn/news/detail-823775.html

到了這里,關(guān)于C#學習(十)——WPF重構(gòu)與美化的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔相關(guān)法律責任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包