0

处理 mvvm 演示项目(不是家庭作业)

  1. 继承 ObservableCollection 的类 Friends
  2. Class Friends ToString 是 FirstName + " " + LastName 等
  3. 具有 Friends 和 SelectedFriend 属性的 ViewModel
  4. ComboBox ItemsSource 绑定到 ViewModel Friends 属性
  5. ComboBox SelectedItem 绑定到 ViewModel Friends 属性
  6. TextBoxes 文本绑定到 ViewModel SelectedFriend.FirstName 属性等

我进行以下更改

  1. 选择史蒂夫
  2. 更改为斯蒂芬 - 更改是因为如果数据被保存并重新加载是显示斯蒂芬
  3. ComboBox 仍然显示史蒂夫
  4. 删除 ComboBox 列表并选择 Sara
  5. Drop ComboBox 列表 - 显示 Steve
  6. 从 ComboBox 列表中选择 Steve
  7. ComboBox 现在显示 Stephen 和 FirstName TextBox
  8. 选择萨拉
  9. 删除 ComboBox 列表,它显示史蒂夫
  10. 在保存并重新加载数据之前,组合框列表不会更改

数据被持久化到一个 xml 文件中。我遗漏了什么,以便 ComboBox 列表显示对 SelectedItem 的更新更改?

模型类

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;

namespace MVVM_Example.Models
{
    public enum Gender : int
    {
        None = 0,
        Male,
        Female
    }

    public class Friend : INotifyPropertyChanged
    {
        private string _firstName;

        public string FirstName 
        {
            get { return _firstName; }
            set
            {
                if (_firstName != value)
                {
                    _firstName = value;
                    OnPropertyChanged("FirstName");
                }
            }
        }

        public string LastName { get; set; }
        public DateTime HireDate { get; set; }
        public Gender Gender { get; set; }
        public bool IsContractor { get; set; }
        public string FullName { get { return string.Format("{0}, {1}", LastName, FirstName); } }

        public override string ToString()
        {
            return string.Format("{0} {1}: Hired {2}, Gender {3}, Status: {4}", FirstName, LastName, HireDate.ToString("MMM dd, yyyy"), Gender, IsContractor ? "Contractor" : "Employee");
        }

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        protected void OnPropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        #endregion
    }
}

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;

using MVVM_Example.Models;

namespace MVVM_Example.Models
{
    public class Friends : ObservableCollection<Friend>
    {
        public Friends()
            : this(loadFriends())
        {
        }

        public Friends(List<Friend> friends)
            : this(friends.ToArray())
        {
        }

        public Friends(IEnumerable<Friend> friends)
            : base(friends)
        {
        }

        public static implicit operator Friends(List<Friend> friends)
        {
            return new Friends(friends);
        }

        public Friends Sort()
        {
            return this.Cast<Friend>().OrderBy(f => f.LastName).ThenBy(f => f.FirstName).ThenByDescending(f => f.HireDate).ToList();
        }

        private static List<Friend> loadFriends()
        {
            return new List<Friend>
            {
                new Friend { FirstName = "Steve", LastName = "Wilson", Gender = Gender.Male, HireDate = new DateTime(2004, 3, 12), IsContractor = false },
                new Friend { FirstName = "Adam", LastName = "Flowers", Gender = Gender.Male, HireDate = new DateTime(2012, 12, 28), IsContractor = false },
                new Friend { FirstName = "Sara", LastName = "Fennema", Gender = Gender.Female, HireDate = new DateTime(2006, 8, 15), IsContractor = false },
                new Friend { FirstName = "Gary", LastName = "Winey", Gender = Gender.Male, HireDate = new DateTime(2012, 4, 6), IsContractor = true },
            }.OrderBy(f => f.LastName).ThenBy(f => f.FirstName).ToList();
        }
    }
}

视图模型

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Xml;
using System.Xml.Serialization;

using MVVM_Example.Models;

namespace MVVM_Example.ViewModels
{
    public class FriendsViewModel : INotifyPropertyChanged
    {
        #region Properties

        #region AreFriendsLoaded

        public bool AreFriendsLoaded
        {
            get { return _areFriendsLoaded; }
            private set
            {
                if (_areFriendsLoaded != value)
                {
                    _areFriendsLoaded = value;
                    OnPropertyChanged("AreFriendsLoaded");
                }
            }
        }
        private bool _areFriendsLoaded;

        #endregion

        #region Friends

        public Friends Friends
        {
            get { return _friends; }
            private set
            {
                if (_friends != value)
                {
                    _friends = value;
                    OnPropertyChanged("Friends");
                    HasFriends = value != null && value.Count > 0;
                }
            }
        }
        private Friends _friends;

        #endregion

        #region HasFriends

        public bool HasFriends 
        { 
            get { return _hasFriends; }
            private set
            {
                if (_hasFriends != value)
                {
                    _hasFriends = value;
                    OnPropertyChanged("HasFriends");
                }
            }
        }
        private bool _hasFriends;

        #endregion

        #region SelectedFriend

        public Friend SelectedFriend
        {
            get { return _selectedFriend; }
            set
            {
                if (_selectedFriend != value)
                {
                    _selectedFriend = value;
                    OnPropertyChanged("SelectedFriend");
                    transferData(true);
                }
            }
        }
        private Friend _selectedFriend;

        #endregion

        #region FirstName

        public string FirstName
        {
            get { return _firstName; }
            set
            {
                if (_firstName != value)
                {
                    _firstName = value;
                    OnPropertyChanged("FirstName");
                    transferData("FirstName");
                }
            }
        }
        private string _firstName;

        #endregion

        #endregion

        #region Constructors

        public FriendsViewModel()
            : base()
        {
            verifyFriends();
        }

        #endregion

        #region Methods

        protected virtual void DeleteSelectedFriend()
        {
            if (Friends.Contains(SelectedFriend))
            {
                Friends.Remove(SelectedFriend);
            }
        }

        private void transferData(bool fromSelectedFriend)
        {
            transferData(fromSelectedFriend, null);
        }

        private void transferData(string propertyName)
        {
            transferData(false, propertyName);
        }

        private void transferData(bool fromSelectedFriend, string propertyName)
        {
            if (fromSelectedFriend)
            {
                FirstName = SelectedFriend == null ? null : SelectedFriend.FirstName;
            }
            else if (SelectedFriend != null)
            {
                if (propertyName == null)
                {
                    throw new InvalidOperationException("Missing propertyName argument in transferData method.");
                }

                switch (propertyName.Trim().ToLowerInvariant())
                {
                    case "firstname":
                        SelectedFriend.FirstName = FirstName;
                        break;
                    default:
                        throw new InvalidOperationException(string.Format("Unexpected property name '{0} in transferData method.", propertyName));
                }
            }
        }

        private void verifyFriends()
        {
            if (Friends == null)
            {
                Friends = new Friends();
            }
        }

        #endregion

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        protected void OnPropertyChanged(string propertyName)
        {

            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        #endregion
    }
}

视图 - 用户控件

<UserControl x:Class="MVVM_Example.Views.FriendsView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:j2a="http://j2associates.com/MVVMBase"
             xmlns:sys="clr-namespace:System;assembly=mscorlib"
             xmlns:vms="clr-namespace:MVVM_Example.ViewModels"
             mc:Ignorable="d" 
             d:DesignHeight="320" d:DesignWidth="400" Name="userControl">

    <UserControl.DataContext>
        <vms:FriendsViewModel />
    </UserControl.DataContext>

    <Grid Margin="5">
        <StackPanel>
            <DockPanel LastChildFill="False">
                <Label DockPanel.Dock="Top" Content="Friends" />
                <ComboBox DockPanel.Dock="Bottom" Name="friendsComboBox" Margin="0,5,0,0" ToolTipService.ShowOnDisabled="True" VerticalContentAlignment="Center" 
                          ItemsSource="{Binding Friends}" SelectedItem="{Binding SelectedFriend}" IsEnabled="{Binding HasFriends}" />
            </DockPanel>

            <GroupBox Header="Selected Friend" Margin="0,5,0,0">
                <Grid>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="auto"/>
                        <RowDefinition Height="auto"/>
                        <RowDefinition Height="auto"/>
                        <RowDefinition Height="auto"/>
                        <RowDefinition Height="auto"/>
                    </Grid.RowDefinitions>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="auto"/>
                        <ColumnDefinition/>
                    </Grid.ColumnDefinitions>

                    <Label Grid.Row="0" Grid.Column="0" Content="First Name" Margin="10,5,0,0" />
                    <Label Grid.Row="1" Grid.Column="0" Content="Last Name" Margin="10,5,0,0" />
                    <Label Grid.Row="2" Grid.Column="0" Content="Hire Date" Margin="10,5,0,0" />
                    <Label Grid.Row="3" Grid.Column="0" Content="Gender" Margin="10,5,0,0" />
                    <Label Grid.Row="4" Grid.Column="0" Content="Contractor" Margin="10,5,0,0" />

                    <TextBox Grid.Row="0" Grid.Column="1" Margin="5,5,0,0" VerticalContentAlignment="Center" 
                             Text="{Binding FirstName, UpdateSourceTrigger=PropertyChanged, TargetNullValue=Undefined}" />
                    <TextBox Grid.Row="1" Grid.Column="1" Margin="5,5,0,0" VerticalContentAlignment="Center" 
                             Text="{Binding SelectedFriend.LastName, UpdateSourceTrigger=PropertyChanged, FallbackValue=Undefined}" />
                    <DatePicker Grid.Row="2" Grid.Column="1" Margin="5,5,0,0" VerticalContentAlignment="Center" 
                                SelectedDate="{Binding SelectedFriend.HireDate}" />
                    <TextBox Grid.Row="3" Grid.Column="1" Margin="5,5,0,0" VerticalContentAlignment="Center" 
                             Text="{Binding SelectedFriend.Gender, UpdateSourceTrigger=PropertyChanged, FallbackValue=Undefined}" />
                    <CheckBox Grid.Row="4" Grid.Column="1" VerticalAlignment="Center" Margin="5,5,0,0" VerticalContentAlignment="Center" 
                              IsChecked="{Binding SelectedFriend.IsContractor, FallbackValue={x:Null}}" />
                </Grid>
            </GroupBox>

            <DockPanel LastChildFill="False">
                <Button DockPanel.Dock="Left" Content="Save data" Margin="5,5,0,0" Width="70" Click="saveDataButton_Click" />
            </DockPanel>
        </StackPanel>
    </Grid>
</UserControl>

ViewModel Code Behind - 使用事件而不是命令来最小化显示的代码

    private void saveDataButton_Click(object sender, RoutedEventArgs e)
    {
        string path = Directory.GetCurrentDirectory();
        path = new DirectoryInfo(Path.Combine(path, "..\\..\\Data\\friends.xml")).FullName;

        // Create a new file stream to write the serialized object to a file.
        using (TextWriter fileStreamWriter = new StreamWriter(path))
        {
            // Create a new XmlSerializer instance with the type.
            XmlSerializer serializer = new XmlSerializer(typeof(Friends));
            serializer.Serialize(fileStreamWriter, ((MVVM_Example.ViewModels.FriendsViewModel)DataContext).Friends);

            // Cleanup.
            fileStreamWriter.Close();
        }

        MessageBox.Show(File.ReadAllText(path), "Data Saved", MessageBoxButton.OK, MessageBoxImage.Information);
    }

主窗口

<Window x:Class="MVVM_Example.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:views="clr-namespace:MVVM_Example.Views"
        Title="Main Window" Height="350" Width="425">
    <Grid>
        <views:FriendsView x:Name="friendsView1" />
    </Grid>
</Window>
4

0 回答 0