Mới sử dụng WPF & MVVM Tôi đang gặp khó khăn với một số chức năng cơ bản.MVVM - thực hiện chức năng 'IsDirty' đối với ModelView để lưu dữ liệu
Hãy đầu tiên để tôi giải thích những gì tôi sau đó, và sau đó đính kèm một số mã ví dụ ...
Tôi có một màn hình hiển thị danh sách người dùng, và tôi hiển thị chi tiết của người sử dụng lựa chọn trên cánh tay phải bên cạnh hộp văn bản có thể chỉnh sửa. Sau đó tôi có một nút Save là DataBound, nhưng tôi chỉ muốn nút này hiển thị khi dữ liệu đã thực sự thay đổi. tức là - tôi cần kiểm tra "dữ liệu bẩn".
Tôi có một ví dụ đầy đủ MVVM trong đó tôi có một mô hình gọi là User:
namespace Test.Model
{
class User
{
public string UserName { get; set; }
public string Surname { get; set; }
public string Firstname { get; set; }
}
}
Sau đó, ViewModel trông như thế này:
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Windows.Input;
using Test.Model;
namespace Test.ViewModel
{
class UserViewModel : ViewModelBase
{
//Private variables
private ObservableCollection<User> _users;
RelayCommand _userSave;
//Properties
public ObservableCollection<User> User
{
get
{
if (_users == null)
{
_users = new ObservableCollection<User>();
//I assume I need this Handler, but I am stuggling to implement it successfully
//_users.CollectionChanged += HandleChange;
//Populate with users
_users.Add(new User {UserName = "Bob", Firstname="Bob", Surname="Smith"});
_users.Add(new User {UserName = "Smob", Firstname="John", Surname="Davy"});
}
return _users;
}
}
//Not sure what to do with this?!?!
//private void HandleChange(object sender, NotifyCollectionChangedEventArgs e)
//{
// if (e.Action == NotifyCollectionChangedAction.Remove)
// {
// foreach (TestViewModel item in e.NewItems)
// {
// //Removed items
// }
// }
// else if (e.Action == NotifyCollectionChangedAction.Add)
// {
// foreach (TestViewModel item in e.NewItems)
// {
// //Added items
// }
// }
//}
//Commands
public ICommand UserSave
{
get
{
if (_userSave == null)
{
_userSave = new RelayCommand(param => this.UserSaveExecute(), param => this.UserSaveCanExecute);
}
return _userSave;
}
}
void UserSaveExecute()
{
//Here I will call my DataAccess to actually save the data
}
bool UserSaveCanExecute
{
get
{
//This is where I would like to know whether the currently selected item has been edited and is thus "dirty"
return false;
}
}
//constructor
public UserViewModel()
{
}
}
}
Các "RelayCommand" chỉ là một wrapper đơn giản lớp, như là "ViewModelBase". (Tôi sẽ đính kèm sau này mặc dù chỉ cho rõ ràng)
using System;
using System.ComponentModel;
namespace Test.ViewModel
{
public abstract class ViewModelBase : INotifyPropertyChanged, IDisposable
{
protected ViewModelBase()
{
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = this.PropertyChanged;
if (handler != null)
{
var e = new PropertyChangedEventArgs(propertyName);
handler(this, e);
}
}
public void Dispose()
{
this.OnDispose();
}
protected virtual void OnDispose()
{
}
}
}
Cuối cùng - XAML
<Window x:Class="Test.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="clr-namespace:Test.ViewModel"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<vm:UserViewModel/>
</Window.DataContext>
<Grid>
<ListBox Height="238" HorizontalAlignment="Left" Margin="12,12,0,0" Name="listBox1" VerticalAlignment="Top"
Width="197" ItemsSource="{Binding Path=User}" IsSynchronizedWithCurrentItem="True">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Path=Firstname}"/>
<TextBlock Text="{Binding Path=Surname}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Label Content="Username" Height="28" HorizontalAlignment="Left" Margin="232,16,0,0" Name="label1" VerticalAlignment="Top" />
<TextBox Height="23" HorizontalAlignment="Left" Margin="323,21,0,0" Name="textBox1" VerticalAlignment="Top" Width="120" Text="{Binding Path=User/UserName}" />
<Label Content="Surname" Height="28" HorizontalAlignment="Left" Margin="232,50,0,0" Name="label2" VerticalAlignment="Top" />
<TextBox Height="23" HorizontalAlignment="Left" Margin="323,52,0,0" Name="textBox2" VerticalAlignment="Top" Width="120" Text="{Binding Path=User/Surname}" />
<Label Content="Firstname" Height="28" HorizontalAlignment="Left" Margin="232,84,0,0" Name="label3" VerticalAlignment="Top" />
<TextBox Height="23" HorizontalAlignment="Left" Margin="323,86,0,0" Name="textBox3" VerticalAlignment="Top" Width="120" Text="{Binding Path=User/Firstname}" />
<Button Content="Button" Height="23" HorizontalAlignment="Left" Margin="368,159,0,0" Name="button1" VerticalAlignment="Top" Width="75" Command="{Binding Path=UserSave}" />
</Grid>
</Window>
Vì vậy, về cơ bản, khi tôi chỉnh sửa một họ, nút Save nên được kích hoạt; và nếu tôi hoàn tác chỉnh sửa của mình - thì sau đó nó sẽ bị vô hiệu hóa một lần nữa vì không có gì thay đổi.
Tôi đã thấy điều này trong nhiều ví dụ, nhưng chưa tìm ra cách thực hiện.
Mọi trợ giúp sẽ được đánh giá cao! Brendan
Tôi cũng sẽ sử dụng Bộ công cụ ánh sáng MVVM –
Cảm ơn, tôi đã cài đặt bộ công cụ MVVM-Light, nhưng tôi chưa thấy bất kỳ cách nào dễ dàng thực hiện chức năng "IsDirty". Tuy nhiên, tôi đã giải quyết được vấn đề của mình (có lẽ không phải là cách tốt nhất - nhưng nó hoạt động) - sẽ trả lời câu hỏi của riêng tôi một chút sau đó với các chi tiết – Brendan
MVVM không hỗ trợ chức năng đọc bẩn. Đó chỉ là một gợi ý để giảm thiểu nỗ lực thực hiện mô hình MVVM. Nó là tốt để biết rằng bạn đã làm việc ra đọc bẩn. Bây giờ tôi sẽ đề nghị để khám phá thêm tin nhắn và sự kiện để chỉ huy trong bộ công cụ ánh sáng mà sẽ cung cấp cho bạn kiểm soát nhiều hơn nữa. Có một thời gian tốt. – ShahidAzim