2011-09-29 37 views
9

Làm quen với WPF và khả năng tuyệt vời của nó để thay đổi, ràng buộc, bật và thao tác khác. Tôi đang cố gắng để có được một cái nhìn tổng quan về tinh thần của những gì đang xảy ra và hy vọng một số có thể xác nhận hoặc sửa các bài đọc của tôi.Cố gắng hiểu về DependencyProperty

Trước WPF, bạn có đại biểu và sự kiện. Bạn có thể có một tá kiểm soát tất cả nghe (thông qua được đăng ký cho sự kiện), vì vậy khi sự kiện cháy, tất cả các điều khiển khác sẽ được thông báo tự động và có thể hành động tuy nhiên chúng được mã hóa. Chẳng hạn như ...

Từ Mã Đằng sau, bạn sẽ làm cái gì đó như

GotFocus += MyMethodToDoSomething; 

Sau đó, phương pháp chữ ký

private void MyMethodToDoSomething(object sender, RoutedEventArgs e) 
{ 
    .. do whatever 
} 

Thêm vào đó, bằng cách sử dụng tiêu chuẩn getter/setter, setter có thể gọi phương pháp riêng của mình trong lớp học riêng của mình để làm điều gì đó mỗi lần ai đó cố gắng lấy hoặc đặt giá trị

private int someValue; 
public int SomeValue 
{ 
    get { this.DoSomeOtherThing(); 
     return someValue; 
     } 

    set { this.DoAnotherThing(); 
     someValue = value; 
} 

Bây giờ, có các thuộc tính phụ thuộc và ràng buộc một/hai chiều. Tôi hiểu (tôi nghĩ) về một chiều để mô phỏng thêm về một hoạt động chỉ đọc. Tuy nhiên, với hai chiều ràng buộc, các phụ thuộc tự động thông báo cho bất cứ ai "tùy thuộc" về một thay đổi trong nguồn hoặc đích tương ứng, mà không kiểm tra rõ ràng nếu một cái gì đó đã đăng ký một sự kiện, khung sẽ tự động xử lý việc công bố thay đổi để điều khiển tương ứng (mục tiêu hoặc nguồn).

Vì vậy, hãy để tôi qua tình huống này với biểu mẫu Thêm/Chỉnh sửa Lưu/Hủy bảo trì cũ. Trong khung cũ hơn, nếu ai đó nhấp vào nút thêm hoặc chỉnh sửa, tất cả các trường nhập dữ liệu sẽ trở thành "được bật" với dữ liệu trống cho bản ghi mới hoặc chỉnh sửa dữ liệu hiện có. Đồng thời, các nút thêm/chỉnh sửa sẽ bị vô hiệu hóa, nhưng các nút Lưu/Hủy bây giờ sẽ được bật.

Tương tự như vậy khi hoàn tất qua Lưu/Hủy, nó sẽ vô hiệu hóa tất cả các trường nhập, lưu/hủy và bật lại các nút Thêm/Chỉnh sửa.

Tôi không hiểu rõ loại kịch bản như vậy sẽ được xử lý như thế nào trong kịch bản thuộc tính phụ thuộc này (chưa), nhưng tôi có đóng không? Tôi cũng hiểu rằng bạn có thể liên kết với hầu hết mọi thứ, bao gồm các phối màu, hiển thị/ẩn, phông chữ, v.v ... Nhưng tôi đang thực hiện các bước nhỏ để cố gắng nắm bắt nội dung này.

Cảm ơn.

+1

Vì WPF là một chủ đề lớn và câu hỏi của bạn khá rộng, khó trả lời. Tôi rất sẵn lòng cung cấp cho bạn các liên kết đến các tài nguyên WPF yêu thích của tôi.Ví dụ bạn đã đọc trên mẫu Model-View-ViewModel chưa? Đây là một bản trình bày tuyệt vời: http://blog.lab49.com/archives/2650 –

+0

Câu hỏi của bạn có vẻ giống như một bài viết về thuộc tính phụ thuộc. Tôi thậm chí không đọc nó. –

+0

@Corey Kosak, nếu bạn đăng nhận xét của mình dưới dạng câu trả lời, tôi sẽ kiểm tra xem giải pháp có mang lại sự hiểu biết từng bước tốt nhất mà không phải mua sách hay không. – DRapp

Trả lời

2

Áp phích đã yêu cầu tôi đăng lại nhận xét của tôi dưới dạng câu trả lời. Hạnh phúc để bắt buộc :-)

Ngoài ra tôi đã tìm thấy cuốn sách này rất hữu ích: http://www.amazon.com/WPF-4-Unleashed-Adam-Nathan/dp/0672331195

exp của riêng tôi erience với WPF liên quan đến việc trở lại giữa một loạt các nguồn lực khác nhau như tôi cố gắng để có được chương trình của tôi để làm việc.Có rất nhiều thứ trong WPF nó thực sự khó khăn để giữ nó tất cả trong đầu của bạn khi bạn đang học nó.

6

Công cụ getter/setter là tính năng của các thuộc tính C# thông thường. Nó không phải là duy nhất cho WPF.

Công cụ một chiều/hai chiều này nói về ràng buộc dữ liệu WPF, không yêu cầu bạn tạo Thuộc tính phụ thuộc - chỉ để sử dụng chúng.

Thuộc tính phụ thuộc được tích hợp vào chính các điều khiển. Chúng cho phép bạn trực tiếp tham khảo các thuộc tính đó khi thêm các trường hợp kiểm soát của bạn vào biểu mẫu. Chúng cho phép kiểm soát tùy chỉnh của bạn cảm thấy hơi "bản địa" hơn.

Thông thường chúng được sử dụng để triển khai thuộc tính có thể sử dụng ràng buộc dữ liệu. Trong ứng dụng của bạn, bạn chủ yếu chỉ cần sử dụng ràng buộc dữ liệu, thay vì triển khai móc mới cho ứng dụng đó.

... nếu ai đó nhấp vào nút thêm hoặc chỉnh sửa, tất cả các trường nhập dữ liệu sẽ được "bật" với dữ liệu trống cho bản ghi mới hoặc chỉnh sửa dữ liệu hiện có. Đồng thời, các nút thêm/chỉnh sửa sẽ bị vô hiệu hóa, nhưng các nút Lưu/Hủy bây giờ sẽ được bật.

Tương tự như vậy khi hoàn tất qua Lưu/Hủy, nó sẽ vô hiệu hóa tất cả các trường nhập, lưu/hủy và bật lại các nút Thêm/Chỉnh sửa.

tôi sẽ thực hiện những gì bạn muốn đạt được với:

  • Một quan điểm mô hình
  • Dữ liệu bắt buộc đối với quan điểm cho rằng quan điểm mô hình
  • Vạch trần ICommand trên mô hình điểm (đối với nút)
  • INotifyPropertyThay đổi trên kiểu xem (đối với tất cả các thuộc tính)

Không có thuộc tính phụ thuộc mới cần được tạo cho kịch bản này. Bạn sẽ chỉ sử dụng những cái hiện có để thực hiện ràng buộc dữ liệu.

Đây là mẫu mã/hướng dẫn thực hiện WPF với ràng buộc dữ liệu và kiểu MVVM.

Thiết lập dự án

Tôi tạo ra một ứng dụng WPF trong thuật sĩ New Project, và đặt tên nó là MyProject.

Tôi thiết lập tên dự án và không gian tên của mình để khớp với lược đồ được chấp nhận chung. Bạn nên thiết lập các thuộc tính này trong solution explorer -> project -> right click -> properties.

Project settings to set the correct namespaces

Tôi cũng có một chương trình thư mục tùy chỉnh Tôi thích sử dụng cho các dự án WPF:

enter image description here

Tôi bị mắc kẹt xem trong "View" thư mục riêng của mình cho các mục đích của tổ chức. Điều này cũng được phản ánh trong không gian tên, vì không gian tên của bạn phải khớp với các thư mục của bạn (namespace MyCompany.MyProject.View).

Tôi cũng sửa AssemblyInfo.cs, và dọn dẹp lắp ráp Tài liệu tham khảo và ứng dụng của tôi cấu hình, nhưng đó chỉ là một số sự nhàm chán mà tôi sẽ để lại như một bài tập cho người đọc :)

Tạo một cái nhìn

Bắt đầu trong nhà thiết kế và làm mọi thứ trông đẹp mắt. Không thêm bất kỳ mã nào phía sau hoặc thực hiện bất kỳ công việc nào khác. Chỉ cần chơi xung quanh trong các nhà thiết kế cho đến khi mọi thứ nhìn đúng (đặc biệt là khi bạn thay đổi kích thước). Đây là những gì tôi đã kết thúc với:

The view I ended up with

Xem/EntryView.xaml:

<Window x:Class="MyCompany.MyProject.View.EntryView" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     Title="Entry View" Height="350" Width="525"> 
    <Grid> 
     <Grid.RowDefinitions> 
      <RowDefinition Height="*" /> 
      <RowDefinition Height="Auto" /> 
     </Grid.RowDefinitions> 
     <Grid Grid.Row="0"> 
      <Grid.RowDefinitions> 
       <RowDefinition Height="Auto" /> 
       <RowDefinition Height="Auto" /> 
       <RowDefinition Height="Auto" /> 
       <RowDefinition Height="Auto" /> 
      </Grid.RowDefinitions> 
      <TextBox Text="Test 1" Grid.Row="0" /> 
      <TextBox Text="Test 2" Grid.Row="1" Margin="0,6,0,0" /> 
      <TextBox Text="Test 3" Grid.Row="2" Margin="0,6,0,0" /> 
      <TextBox Text="Test 4" Grid.Row="3" Margin="0,6,0,0" /> 
     </Grid> 
     <Grid Grid.Row="1"> 
      <Grid.ColumnDefinitions> 
       <ColumnDefinition Width="*" /> 
       <ColumnDefinition Width="Auto" /> 
       <ColumnDefinition Width="Auto" /> 
      </Grid.ColumnDefinitions> 
      <Button Content="Edit" IsEnabled="True" Grid.Column="0" 
       HorizontalAlignment="Left" Width="75" /> 
      <Button Content="Save" IsEnabled="False" Grid.Column="1" 
       Width="75" /> 
      <Button Content="Cancel" IsEnabled="False" Grid.Column="2" 
       Width="75" Margin="6,0,0,0" /> 
     </Grid> 
    </Grid> 
</Window> 

Xem/EntryView.xaml.cs:

using System.Windows; 

namespace MyCompany.MyProject.View 
{ 
    public partial class EntryView : Window 
    { 
     public EntryView() 
     { 
      InitializeComponent(); 
     } 
    } 
} 

tôi didn không tạo bất kỳ thuộc tính Name nào trên các điều khiển này. Đó là mục đích. Tôi sẽ sử dụng MVVM và sẽ không sử dụng bất kỳ mã nào phía sau. Tôi sẽ để cho nhà thiết kế làm những gì nó muốn làm, nhưng tôi sẽ không chạm vào bất kỳ mã nào.

Tạo một mô hình xem

Tiếp theo, tôi sẽ làm cho mô hình quan điểm của tôi. Điều này nên được thiết kế theo cách mà nó phục vụ quan điểm, nhưng lý tưởng nhất có thể được xem độc lập. Tôi sẽ không lo lắng về điều đó quá nhiều, nhưng vấn đề là bạn không để có sự tương đương 1 đến 1 đối với các điều khiển chế độ xem và xem các đối tượng mô hình.

Tôi cố gắng làm cho các chế độ xem/xem của mình có ý nghĩa trong ngữ cảnh ứng dụng lớn hơn, vì vậy, tôi sẽ bắt đầu định dạng mô hình xem tại đây. Chúng tôi sẽ làm cho "biểu mẫu có thể chỉnh sửa" này thành mục nhập rolodex.

Chúng tôi sẽ tạo ra một lớp helper mà chúng ta cần đầu tiên ...

ViewModel/DelegateCommand.cs:

using System; 
using System.Windows.Input; 

namespace MyCompany.MyProject.ViewModel 
{ 
    public class DelegateCommand : ICommand 
    { 
     private readonly Action<object> _execute; 
     private readonly Func<object, bool> _canExecute; 

     public DelegateCommand(Action execute) 
      : this(execute, CanAlwaysExecute) 
     { 
     } 

     public DelegateCommand(Action execute, Func<bool> canExecute) 
     { 
      if (execute == null) 
       throw new ArgumentNullException("execute"); 

      if (canExecute == null) 
       throw new ArgumentNullException("canExecute"); 

      _execute = o => execute(); 
      _canExecute = o => canExecute(); 
     } 

     public bool CanExecute(object parameter) 
     { 
      return _canExecute(parameter); 
     } 

     public void Execute(object parameter) 
     { 
      _execute(parameter); 
     } 

     public event EventHandler CanExecuteChanged; 

     public void RaiseCanExecuteChanged() 
     { 
      if (CanExecuteChanged != null) 
       CanExecuteChanged(this, new EventArgs()); 
     } 

     private static bool CanAlwaysExecute() 
     { 
      return true; 
     } 
    } 
} 

ViewModel/EntryViewModel.cs:

using System; 
using System.ComponentModel; 
using System.Windows.Input; 

namespace MyCompany.MyProject.ViewModel 
{ 
    public class EntryViewModel : INotifyPropertyChanged 
    { 
     private readonly string _initialName; 
     private readonly string _initialEmail; 
     private readonly string _initialPhoneNumber; 
     private readonly string _initialRelationship; 

     private string _name; 
     private string _email; 
     private string _phoneNumber; 
     private string _relationship; 

     private bool _isInEditMode; 

     private readonly DelegateCommand _makeEditableOrRevertCommand; 
     private readonly DelegateCommand _saveCommand; 
     private readonly DelegateCommand _cancelCommand; 

     public EntryViewModel(string initialNamename, string email, 
      string phoneNumber, string relationship) 
     { 
      _isInEditMode = false; 

      _name = _initialName = initialNamename; 
      _email = _initialEmail = email; 
      _phoneNumber = _initialPhoneNumber = phoneNumber; 
      _relationship = _initialRelationship = relationship; 

      MakeEditableOrRevertCommand = _makeEditableOrRevertCommand = 
       new DelegateCommand(MakeEditableOrRevert, CanEditOrRevert); 

      SaveCommand = _saveCommand = 
       new DelegateCommand(Save, CanSave); 

      CancelCommand = _cancelCommand = 
       new DelegateCommand(Cancel, CanCancel); 
     } 

     public string Name 
     { 
      get { return _name; } 
      set 
      { 
       _name = value; 
       RaisePropertyChanged("Name"); 
      } 
     } 

     public string Email 
     { 
      get { return _email; } 
      set 
      { 
       _email = value; 
       RaisePropertyChanged("Email"); 
      } 
     } 

     public string PhoneNumber 
     { 
      get { return _phoneNumber; } 
      set 
      { 
       _phoneNumber = value; 
       RaisePropertyChanged("PhoneNumber"); 
      } 
     } 

     public string Relationship 
     { 
      get { return _relationship; } 
      set 
      { 
       _relationship = value; 
       RaisePropertyChanged("Relationship"); 
      } 
     } 

     public bool IsInEditMode 
     { 
      get { return _isInEditMode; } 
      private set 
      { 
       _isInEditMode = value; 
       RaisePropertyChanged("IsInEditMode"); 
       RaisePropertyChanged("CurrentEditModeName"); 

       _makeEditableOrRevertCommand.RaiseCanExecuteChanged(); 
       _saveCommand.RaiseCanExecuteChanged(); 
       _cancelCommand.RaiseCanExecuteChanged(); 
      } 
     } 

     public string CurrentEditModeName 
     { 
      get { return IsInEditMode ? "Revert" : "Edit"; } 
     } 

     public ICommand MakeEditableOrRevertCommand { get; private set; } 
     public ICommand SaveCommand { get; private set; } 
     public ICommand CancelCommand { get; private set; } 

     private void MakeEditableOrRevert() 
     { 
      if (IsInEditMode) 
      { 
       // Revert 
       Name = _initialName; 
       Email = _initialEmail; 
       PhoneNumber = _initialPhoneNumber; 
       Relationship = _initialRelationship; 
      } 

      IsInEditMode = !IsInEditMode; // Toggle the setting 
     } 

     private bool CanEditOrRevert() 
     { 
      return true; 
     } 

     private void Save() 
     { 
      AssertEditMode(isInEditMode: true); 
      IsInEditMode = false; 
      // Todo: Save to file here, and trigger close... 
     } 

     private bool CanSave() 
     { 
      return IsInEditMode; 
     } 

     private void Cancel() 
     { 
      AssertEditMode(isInEditMode: true); 
      IsInEditMode = false; 
      // Todo: Trigger close form... 
     } 

     private bool CanCancel() 
     { 
      return IsInEditMode; 
     } 

     private void AssertEditMode(bool isInEditMode) 
     { 
      if (isInEditMode != IsInEditMode) 
       throw new InvalidOperationException(); 
     } 

     #region INotifyPropertyChanged Members 

     public event PropertyChangedEventHandler PropertyChanged; 

     private void RaisePropertyChanged(string propertyName) 
     { 
      if (PropertyChanged != null) 
       PropertyChanged(this, 
        new PropertyChangedEventArgs(propertyName)); 
     } 

     #endregion INotifyPropertyChanged Members 
    } 
} 

Như thường lệ đối với loại quy trình làm việc này, có một số yêu cầu tôi đã bỏ lỡ khi ban đầu creatin g xem. Ví dụ, tôi đã tìm ra rằng nó sẽ có ý nghĩa để có một tính năng "hoàn nguyên" mà undoes những thay đổi, nhưng giữ cho hộp thoại mở. Tôi cũng đã tìm ra rằng tôi có thể sử dụng lại nút chỉnh sửa cho mục đích này. Vì vậy, tôi đã tạo một thuộc tính mà tôi sẽ đọc để lấy tên của nút chỉnh sửa.

Mô hình chế độ xem chứa rất nhiều mã để làm điều gì đó đơn giản, nhưng hầu hết trong số đó là bản mẫu để hooking lên các thuộc tính. Điều này boilerplate cung cấp cho bạn một số quyền lực, mặc dù. Nó giúp cô lập bạn khỏi chế độ xem của bạn, vì vậy, chế độ xem của bạn có thể thay đổi đáng kể mà không có thay đổi hoặc chỉ thay đổi nhỏ đối với mô hình chế độ xem.

Nếu mô hình chế độ xem quá lớn, bạn có thể bắt đầu đẩy mô hình đó vào mô hình chế độ xem phụ bổ sung. Tạo chúng ở bất kỳ đâu có ý nghĩa nhất và trả lại chúng dưới dạng thuộc tính trên mô hình chế độ xem này. Cơ chế ràng buộc dữ liệu WPF hỗ trợ chuỗi dữ liệu trong bối cảnh dữ liệu.Bạn sẽ tìm hiểu về bối cảnh dữ liệu này một chút sau đó khi chúng ta kết nối mọi thứ.

Hooking lên nhằm mô hình điểm của chúng tôi

Để treo lên nhìn sang một mô hình xem, bạn phải thiết lập các DataContext tài sản trên quan điểm để trỏ đến mô hình nhìn của bạn.

Một số người thích khởi tạo và chỉ định mô hình chế độ xem trong mã XAML. Mặc dù điều này có thể hiệu quả nhưng tôi muốn giữ chế độ xem và kiểu xem độc lập với nhau, vì vậy tôi đảm bảo rằng tôi sử dụng một số lớp thứ ba để kết nối hai.

Thông thường tôi muốn sử dụng thùng chứa phụ thuộc để gắn tất cả mã của tôi, đó là rất nhiều công việc, nhưng giữ tất cả các phần độc lập. Nhưng đối với một ứng dụng đơn giản này, tôi thích sử dụng lớp App để ràng buộc nội dung của tôi với nhau. Chúng ta hãy đi sửa nó:

App.xaml:

<Application x:Class="MyCompany.MyProject.App" 
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
      Startup="ApplicationStartup"> 
    <Application.Resources> 

    </Application.Resources> 
</Application> 

App.xaml.cs:

using System.Windows; 

namespace MyCompany.MyProject 
{ 
    public partial class App : Application 
    { 
     private void ApplicationStartup(object sender, StartupEventArgs e) 
     { 
      // Todo: Somehow load initial data... 
      var viewModel = new ViewModel.EntryViewModel(
       "some name", "some email", "some phone number", 
       "some relationship" 
       ); 

      var view = new View.EntryView() 
      { 
       DataContext = viewModel 
      }; 

      view.Show(); 
     } 
    } 
} 

Bây giờ bạn có thể chạy dự án của bạn, mặc dù logic chúng tôi xây dựng won không làm gì cả. Điều này là do khung nhìn ban đầu của chúng ta được tạo ra, nhưng nó không thực sự làm bất kỳ ràng buộc dữ liệu nào.

Thiết lập dữ liệu ràng buộc

Cho phép quay trở lại và chỉnh sửa nhằm thúc hooking nó tất cả lên.

Editing Xem/EntryView.xaml:

<Window x:Class="MyCompany.MyProject.View.EntryView" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     Title="Rolodex Entry" 
     Height="350" Width="525" 
     MinWidth="300" MinHeight="200"> 
    <Grid Margin="12"> 
     <Grid.RowDefinitions> 
      <RowDefinition Height="*" /> 
      <RowDefinition Height="Auto" /> 
     </Grid.RowDefinitions> 
     <Grid Grid.Row="0"> 
      <Grid.RowDefinitions> 
       <RowDefinition Height="Auto" /> 
       <RowDefinition Height="Auto" /> 
       <RowDefinition Height="Auto" /> 
       <RowDefinition Height="Auto" /> 
      </Grid.RowDefinitions> 
      <Grid.ColumnDefinitions> 
       <ColumnDefinition Width="Auto" /> 
       <ColumnDefinition Width="*" /> 
      </Grid.ColumnDefinitions> 
      <TextBlock Text="Name:" Grid.Column="0" Grid.Row="0" /> 
      <TextBox Text="{Binding Name, UpdateSourceTrigger=PropertyChanged}" 
        IsEnabled="{Binding IsInEditMode}" Grid.Column="1" 
        Grid.Row="0" Margin="6,0,0,0" /> 
      <TextBlock Text="E-mail:" Grid.Column="0" Grid.Row="1" 
         Margin="0,6,0,0" /> 
      <TextBox Text="{Binding Email, UpdateSourceTrigger=PropertyChanged}" 
        IsEnabled="{Binding IsInEditMode}" Grid.Column="1" 
        Grid.Row="1" Margin="6,6,0,0" /> 
      <TextBlock Text="Phone Number:" Grid.Column="0" Grid.Row="2" 
         Margin="0,6,0,0" /> 
      <TextBox Text="{Binding PhoneNumber, UpdateSourceTrigger=PropertyChanged}" 
        IsEnabled="{Binding IsInEditMode}" Grid.Column="1" Grid.Row="2" 
        Margin="6,6,0,0" /> 
      <TextBlock Text="Relationship:" Grid.Column="0" Grid.Row="3" 
         Margin="0,6,0,0" /> 
      <TextBox Text="{Binding Relationship, UpdateSourceTrigger=PropertyChanged}" 
        IsEnabled="{Binding IsInEditMode}" Grid.Column="1" Grid.Row="3" 
        Margin="6,6,0,0" /> 
     </Grid> 
     <Grid Grid.Row="1"> 
      <Grid.ColumnDefinitions> 
       <ColumnDefinition Width="*" /> 
       <ColumnDefinition Width="Auto" /> 
       <ColumnDefinition Width="Auto" /> 
      </Grid.ColumnDefinitions> 
      <Button Content="{Binding CurrentEditModeName}" 
        Command="{Binding MakeEditableOrRevertCommand}" 
        Grid.Column="0" HorizontalAlignment="Left" 
        Width="75" /> 
      <Button Content="Save" Command="{Binding SaveCommand}" 
        Grid.Column="1" Width="75" /> 
      <Button Content="Cancel" Command="{Binding CancelCommand}" 
        Grid.Column="2" Width="75" Margin="6,0,0,0" /> 
     </Grid> 
    </Grid> 
</Window> 

tôi đã làm rất nhiều công việc ở đây. Thứ nhất, những thứ tĩnh:

  • tôi đã thay đổi tiêu đề của hình thức để phù hợp với ý tưởng Rolodex
  • tôi đã thêm nhãn cho các lĩnh vực, kể từ bây giờ tôi biết những gì họ áp dụng cho
  • Tôi đã thay đổi chiều rộng tối thiểu/chiều cao, kể từ khi tôi nhận thấy điều khiển được việc cắt đứt

Tiếp theo các liên kết dữ liệu:

  • tôi bị ràng buộc tất cả các lĩnh vực văn bản t o các thuộc tính thích hợp trên mô hình xem
  • Tôi đã tạo các trường văn bản update the view model on every keypress (UpdateSourceTrigger=PropertyChanged). Điều này là không cần thiết cho ứng dụng này, nhưng có thể hữu ích trong tương lai.Tôi đã thêm nó rảnh rỗi bạn khỏi nhìn nó lên khi bạn cần nó :)
  • tôi bị ràng buộc các IsEnabled lĩnh vực của mỗi hộp văn bản để các IsInEditMode tài sản
  • tôi bị ràng buộc các nút để các lệnh tương ứng của họ
  • tôi bị ràng buộc chỉnh sửa tên nút của (Content sở hữu) đối với tài sản tương ứng trên mô hình xem

Dưới đây là kết quả

Read-only mode Edit mode

Bây giờ tất cả logic UI hoạt động, ngoại trừ những logic chúng tôi đã để lại nhận xét Todo. Tôi để lại những điều chưa được thực hiện bởi vì họ phải làm với một kiến ​​trúc ứng dụng cụ thể, và tôi không muốn tham gia vào đó cho bản demo này.

Ngoài ra, vanilla WPF không có cách MVVM rất sạch sẽ để đóng một biểu mẫu mà tôi biết. Bạn có thể sử dụng mã-đằng sau để làm điều đó, hoặc bạn có thể sử dụng một trong số hàng tá thư viện bổ sung WPF cung cấp cách làm sạch của riêng chúng hơn.

phụ thuộc Thuộc tính

Bạn có thể đã nhận thấy rằng tôi đã không tạo ra một tùy chỉnh đơn phụ thuộc về tài sản trong mã của tôi. Các thuộc tính phụ thuộc mà tôi đã sử dụng đều là trên các điều khiển hiện tại (ví dụ: Text, ContentCommand). Đây là cách nó thường hoạt động trong WPF, bởi vì ràng buộc dữ liệu và kiểu dáng (mà tôi đã không nhận được vào) cung cấp cho bạn rất nhiều tùy chọn. Nó cho phép bạn tùy chỉnh hoàn toàn giao diện và hành động của các điều khiển tích hợp.

Trong các khung công tác GUI trước của Windows, bạn thường phải phân lớp các điều khiển hiện có hoặc tạo các điều khiển tùy chỉnh để có giao diện tùy chỉnh. Lý do duy nhất để thực hiện các điều khiển tùy chỉnh trong WPF là kết hợp các mẫu của nhiều điều khiển theo cách có thể tái sử dụng hoặc tạo một điều khiển hoàn toàn mới từ đầu.

Ví dụ: nếu bạn đang tạo hộp văn bản tự động hoàn thành được ghép nối với một điều khiển bật lên để hiển thị các giá trị được tự động hoàn thành từ đó. Trong trường hợp này, bạn có thể muốn thực hiện một điều khiển tùy chỉnh, với các thuộc tính phụ thuộc tùy chỉnh (chẳng hạn như nguồn tự động hoàn thành). Bằng cách đó bạn có thể sử dụng lại quyền kiểm soát trong suốt ứng dụng của mình và các ứng dụng khác.

Nếu bạn không thực hiện điều khiển tùy chỉnh hoặc tạo các lớp không phải UI đặc biệt có thể trực tiếp khởi tạo và sử dụng trong XAML và liên kết dữ liệu với, bạn có thể sẽ không cần phải tạo thuộc tính phụ thuộc.

+0

Giải pháp từng bước tuyệt vời và chân thành cảm kích thời gian/công sức. Tôi có nhiều điều để tìm hiểu/hiểu được trong tư duy phát triển này. – DRapp

+0

@DRapp: Nếu bạn muốn tôi có thể viết một ví dụ về các công cụ thuộc tính phụ thuộc quá :) Có thể sẽ lâu hơn một chút vì tôi không sử dụng chúng thường xuyên. –

+0

cảm ơn, nhưng không cần thiết. Tôi cần phải tiêu hóa một số vấn đề cơ bản, lấy mẫu chúng bằng môi trường của tôi (suy nghĩ) và cố gắng thu thập thông tin, đi bộ, sau đó chạy. – DRapp

1

Cách đơn giản để xem chúng là chúng là thuộc tính trỏ đến thuộc tính khác.

Chúng thực sự là định nghĩa của thuộc tính, xác định tên thuộc tính, loại, giá trị mặc định, v.v. nhưng giá trị thực của thuộc tính không được lưu với định nghĩa thuộc tính.

Vì vậy, bạn có thể nói thuộc tính Kích hoạt của nút sẽ trỏ đến thuộc tính trên một lớp cụ thể hoặc nó sẽ trỏ đến thuộc tính CheckBoxA.IsChecked hoặc thậm chí bạn có thể nói nó chỉ đơn giản là trỏ đến một giá trị boolean của False.

// Value points to the current DataContext object's CanSaveObject property 
<Button IsEnabled="{Binding CanSaveObject}" /> 

// Value points to the IsChecked property of CheckBoxA 
<Button IsEnabled="{Binding ElementName=CheckBoxA, Path=IsChecked}" /> 

// Value points to the value False 
<Button IsEnabled="False" /> 
Các vấn đề liên quan