处理 mvvm 演示项目(不是家庭作业)
- 继承 ObservableCollection 的类 Friends
- Class Friends ToString 是 FirstName + " " + LastName 等
- 具有 Friends 和 SelectedFriend 属性的 ViewModel
- ComboBox ItemsSource 绑定到 ViewModel Friends 属性
- ComboBox SelectedItem 绑定到 ViewModel Friends 属性
- TextBoxes 文本绑定到 ViewModel SelectedFriend.FirstName 属性等
我进行以下更改
- 选择史蒂夫
- 更改为斯蒂芬 - 更改是因为如果数据被保存并重新加载是显示斯蒂芬
- ComboBox 仍然显示史蒂夫
- 删除 ComboBox 列表并选择 Sara
- Drop ComboBox 列表 - 显示 Steve
- 从 ComboBox 列表中选择 Steve
- ComboBox 现在显示 Stephen 和 FirstName TextBox
- 选择萨拉
- 删除 ComboBox 列表,它显示史蒂夫
- 在保存并重新加载数据之前,组合框列表不会更改
数据被持久化到一个 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>