2013-05-08 15 views
9

Điều này đã khiến tôi bối rối khi tôi nghĩ rằng tôi đã xem xét mọi thứ nhưng tôi phải thiếu một cái gì đó. Tôi đã đi ra khỏi mô hình MVVM truyền thống từ các tạp chí MSDN:Phương thức ưu tiên để ràng buộc trong MVVM, Mẫu dữ liệu trong tệp Tài nguyên hoặc chỉ DataContext trong chính Chế độ xem?

http://msdn.microsoft.com/en-us/magazine/dd419663.aspx

trong khi học tập MVVM. Tuy nhiên tôi thường sao chép hầu hết các mã và sau đó thay thế nó như tôi cần nhưng hôm nay tôi muốn xây dựng một cái gì đó từ đầu và thấy rằng có thể có nhiều hơn nó hơn tôi nghĩ. MVVM dường như không hoạt động với các ràng buộc khi tôi sử dụng từ điển tài nguyên nhưng thực hiện trực tiếp với datacontext. Câu hỏi này cuối cùng muốn tìm các nhà phát triển khác đề xuất sử dụng ràng buộc mà họ tìm thấy.

Tóm tắt câu hỏi là: Tại sao 'DataTemplate' trong Từ điển tài nguyên xuất hiện để không hoạt động được hiển thị bên dưới, nhưng phương pháp 'DataContext' trực tiếp thực hiện với chế độ xem ngay lập tức cho các ràng buộc?

Có phải vì tôi đang tạo một hỗn hợp mã phía sau với chế độ xem cài đặt trong mã phía sau. Hoặc có khả năng vì cái gì khác. Nó xuất hiện tài sản của tôi và nó thực hiện được thiết lập chính xác trong viewmodel nếu tôi đặt 'DataContext' trực tiếp trong XAML của View, nhưng tại sao không có trong Resource Dictionary? Tôi nghĩ rằng lợi thế của phương pháp đó là bạn có thể thiết lập một loạt các mối quan hệ cùng một lúc. Tôi tò mò nếu có một số thiết lập khác cần phải được thực hiện để làm cho nó hoạt động. Nó là tò mò trong ví dụ chính của phương pháp MVVM họ sử dụng mẫu dữ liệu nhưng nó xuất hiện có nhiều hơn để thiết lập chúng hơn tôi đang làm để có được 'ràng buộc' của họ để làm việc.

GÌ không làm việc cho ME:

Tôi đã cố gắng để làm một số công cụ rất cơ bản trong một XAML cửa sổ chính, để lại một số mã của tôi ra để làm cho nó thậm chí còn đơn giản hơn:

Main Window XAML :

<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:dxc="http://schemas.devexpress.com/winfx/2008/xaml/charts" x:Class="WPFTesting12_2.MainWindow" 
     Title="MainWindow" Height="350" Width="525"> 
    <Window.Resources> 
     <ResourceDictionary Source="Resources.xaml"/> 
    </Window.Resources> 
    <Grid> 
     <DockPanel x:Name="dockpanel"> 
      <Menu DockPanel.Dock="Top" Height="30"> 
       <MenuItem Header="Charting"> 
        <MenuItem Header="MVVMDataBound" x:Name="mnuDataBoundSeriesMVVMCharting" Click="mnuDataBoundSeriesMVVMCharting_OnClick"/> 
       </MenuItem> 
      </Menu> 
      <TextBlock Height="5" Background="Black" DockPanel.Dock="Top" /> 
      <DockPanel x:Name="dockchildren" DockPanel.Dock="Bottom"/> 
     </DockPanel> 
    </Grid> 
</Window> 

Main Window Mã Đằng sau:

public partial class MainWindow : Window 
    { 

     public MainWindow() 
     { 
      InitializeComponent(); 

      this.WindowState = WindowState.Maximized; 
     } 


     private void mnuDataBoundSeriesMVVMCharting_OnClick(object sender, RoutedEventArgs e) 
     { 
      View.DataBoundMVVMChart c = new DataBoundMVVMChart(); 

      dockchildren.Children.Clear(); 
      dockchildren.Children.Add(c); 
     } 
    } 
} 

điển Resource:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
        xmlns:vw="clr-namespace:WPFTesting12_2.View" 
        xmlns:vm="clr-namespace:WPFTesting12_2.ViewModel" 
        > 
    <DataTemplate DataType="{x:Type vm:DataBoundMVVMChartViewModel}"> 
    <vw:DataBoundMVVMChart/> 
</DataTemplate> 

<Style TargetType="MenuItem"> 
     <Setter Property="Background" Value="Wheat"/> 
    </Style> 
    <Style TargetType="Menu"> 
     <Setter Property="Background" Value="Wheat"/> 
    </Style> 

</ResourceDictionary> 

Xem cho DataBoundMVVMChart.xaml:

<UserControl x:Class="WPFTesting12_2.View.DataBoundMVVMChart" 
      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:local="clr-namespace:WPFTesting12_2.ViewModel" 
      mc:Ignorable="d" 
      d:DesignHeight="300" d:DesignWidth="300"> 
    <UserControl.Resources> 
     <ResourceDictionary Source="..\Resources.xaml"/> 
    </UserControl.Resources> 
    <Grid> 
     <DockPanel> 
      <Menu DockPanel.Dock="Top"> 
       <MenuItem Header="TesterContent"/> 
      </Menu> 
      <Label DockPanel.Dock="Bottom" Width="300" x:Name="label" Height="50" Foreground="Blue" FontSize="24" Content="{Binding Path=HelloString}"/> 
     </DockPanel> 
    </Grid> 
</UserControl> 

ViewModel để ràng buộc vào Xem trên:

namespace WPFTesting12_2.ViewModel 
{ 
    class DataBoundMVVMChartViewModel : INotifyPropertyChanged 
    { 
     private string _HelloString; 

     public string HelloString 
     { 
      get { return _HelloString; } 
      set 
      { 
       _HelloString = value; 
       RaisePropertyChanged("HelloString"); 
      } 
     } 

     public DataBoundMVVMChartViewModel() 
     { 
      HelloString = "Hello there from the ViewModel"; 
     } 

     public event PropertyChangedEventHandler PropertyChanged; 

     protected void RaisePropertyChanged(string propertyName) 
     { 
      if (PropertyChanged != null) 
       PropertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName)); 
     } 
    } 
} 

Được rồi bây giờ là ràng buộc sẽ thất bại trong giao diện nhưng Tuy nhiên, các nguồn lực của màu sắc sẽ đến. Vì vậy, tôi đã nghĩ rằng tôi đã làm điều gì sai trái nhưng mã phía sau sẽ có được tài sản ngay lập tức.Vì vậy, hãy chuyển sang:

GÌ DID LÀM VIỆC:

Magicially nếu tôi chỉ cần thêm bốn dòng để quan điểm:

Thêm phần này vào tờ khai trong phân khúc 'UserControl' ở phía trên:

xmlns:local="clr-namespace:WPFTesting12_2.ViewModel" 

Sau đó thiết lập một tham chiếu đến DataContext của UserControl:

<UserControl.DataContext> 
     <local:DataBoundMVVMChartViewModel/> 
    </UserControl.DataContext> 

Trả lời

27

Điều quan trọng cần nhận ra khi làm việc với WPF là có hai lớp: lớp dữ liệu (DataContext) và lớp giao diện người dùng (XAML).

Các kết nối được sử dụng để lấy dữ liệu từ lớp dữ liệu vào lớp Chế độ xem.

Khi bạn viết

<UserControl.DataContext> 
    <local:DataBoundMVVMChartViewModel/> 
</UserControl.DataContext> 

Bạn đang nói với WPF rằng nó nên tạo một đối tượng mới của DataBoundMVVMChartViewModel và sử dụng nó cho các lớp dữ liệu UserControl đó.

Khi bạn viết

<Label Content="{Binding HelloString}" /> 

bạn đang nói Label để tìm trong lớp dữ liệu của nó (DataContext) cho một tài sản gọi là "HelloString", và sử dụng nó cho các Content tài sản.

Nếu thuộc tính "HelloString" không tồn tại trong lớp dữ liệu (trừ khi bạn đặt DataContext như bạn đã làm với <UserControl.DataContext>), ràng buộc sẽ thất bại và không có gì hiển thị ngoại trừ lỗi liên kết trong đầu ra của bạn cửa sổ.

DataTemplate từ ResourceDictionary của bạn khác với DataContext.

Thực tế, ResourceDictionary chỉ là những gì nó giống như - một từ điển các nguồn lực mà WPF có thể sử dụng trong ứng dụng khi cần.Nhưng các đối tượng trong Từ điển không phải là một phần mặc định của giao diện người dùng của ứng dụng. Thay vào đó, chúng cần phải được tham chiếu theo một cách nào đó để được sử dụng.

Nhưng trở lại của bạn DataTemplate

<DataTemplate DataType="{x:Type vm:DataBoundMVVMChartViewModel}"> 
    <vw:DataBoundMVVMChart/> 
</DataTemplate> 

WPF sử dụng DataTemplates biết làm thế nào để vẽ loại cụ thể của các đối tượng. Trong trường hợp của bạn, điều này DataTemplate là nói với WPF rằng bất cứ lúc nào nó cần phải vẽ một đối tượng của loại DataBoundMVVMChartViewModel, nó phải làm như vậy bằng cách sử dụng một DataBoundMVVMChart.

Để chèn một đối tượng vào giao diện người dùng, một tài sản Content thường được sử dụng, chẳng hạn như

MyLabel.Content = new DataBoundMVVMChartViewModel(); 

hoặc

<ContentControl Content="{Binding SomeDataboundChartViewModelProperty}" /> 

Tôi thực sự bắt đầu học MVVM với chính xác cùng article bạn được liên kết trong câu hỏi của bạn, và gặp nhiều rắc rối trong việc tìm ra nó, điều này dẫn tôi đến việc viết blog về WPF/MVVM nhằm mục đích đặc biệt cho người mới bắt đầu như tôi :)

Nếu bạn quan tâm, tôi có một vài bài viết blog về WPF/MVVM có thể giúp bạn hiểu công nghệ tốt hơn.

Đối với câu hỏi thực tế của bạn:

phương pháp ưa thích cho liên kết trong MVVM, Mẫu dữ liệu trong Tài nguyên nộp hoặc chỉ DataContext trong Xem chinh no?

tôi thích sử dụng một DataTemplate trong .Resources nơi nào đó, như sau đó UI bạn không được gắn cụ thể với một cụ DataContext.

Điều này đặc biệt quan trọng khi tạo các điều khiển có thể sử dụng lại với MVVM. Ví dụ: nếu bạn có CalculatorUserControl và bạn đã gán nó DataContext trong chính điều khiển như với <UserControl.DataContext>, thì bạn không bao giờ có thể sử dụng CalculatorUserControl với bất kỳ DataContext nào khác ngoài mã được tạo khi điều khiển được tạo.

Vì vậy, thường tôi đặt DataContext cho toàn bộ ứng dụng một lần lúc khởi động, và sử dụng DataTemplates nói với WPF làm thế nào để vẽ khác nhau ViewModels hoặc Models trong ứng dụng của tôi.

Toàn bộ ứng dụng của tôi tồn tại trong lớp dữ liệu và XAML chỉ đơn thuần là giao diện thân thiện với người dùng để tương tác với lớp dữ liệu. (Nếu bạn muốn xem mẫu mã, hãy xem Simple MVVM Example bài đăng của tôi)

+0

Tôi làm theo những gì bạn đang viết nhưng bạn mất tôi khi bạn nêu một phần về việc chèn một đối tượng vào giao diện người dùng. Bạn đang nói về lớp ngoài có tại MainWindow.xaml hoặc bên trong tại userControl gọi là? Tôi chỉ bối rối như tôi có được bản chất những gì các mẫu dữ liệu đang làm nhưng không phải lý do tại sao nó không hoạt động nếu tôi tham khảo ResourceDictionary và nó chọn lên màu sắc của tôi setttings nhưng không phải là một phần mẫu. Khi tôi nhìn vào ví dụ nó xuất hiện tất cả mọi thứ được nối đúng, nhưng mỗi khi tôi thường làm MVVM tôi sao chép toàn bộ ví dụ. Cảm ơn các ví dụ của bạn, tôi sẽ xem xét chúng. – djangojazz

+0

@djangojazz WPF cho phép bạn chèn bất kỳ 'đối tượng' nào vào cây giao diện người dùng. Theo mặc định, WPF vẽ tất cả các mục mà nó không biết cách vẽ bằng 'TextBlock' hiển thị' .ToString() 'của đối tượng, tuy nhiên' DataTemplates' có thể được sử dụng để báo cho WPF biết cách render đối tượng. Ví dụ, thay đổi lệnh bấm menu của bạn thành 'dockchildren.Children.Add (new DataBoundMVVMChartViewModel());'. Bạn thường sẽ thấy một cái gì đó như "WPFTesting12_2.ViewModel.DataBoundMVVMChartViewModel" trong giao diện người dùng, tuy nhiên vì 'DataTemplate' của bạn trong' ', nó sẽ được vẽ bằng cách sử dụng' DataBoundMVVMChart' thay thế. – Rachel

+0

@djangojazz (Rất tiếc, tôi quên 'DockPanels' chỉ cho phép các đối tượng giao diện người dùng được thêm vào, vì vậy bạn cần sử dụng điều khiển cho phép bất kỳ đối tượng nào được thêm vào ví dụ trong nhận xét trên của tôi để hoạt động, chẳng hạn như '' hoặc '

2

Nếu bạn muốn sử dụng ngầm DataTemplates bạn phải sử dụng các phương phápxem mô hình đầu tiên, bạn tuy nhiên thêm một xem để DockPanel bạn mà không cần một cái nhìn mô hình như bối cảnh của nó. Nếu bạn chỉ cần thêm kiểu xem tương ứng (vào một số ContentControl hoặc ItemsControl), chế độ xem sẽ được tạo tự động từ DataTemplate với kiểu xem là DataContext.

ví dụ:

<ItemsControl Name="ic"/> 

ic.Items.Add(new DataBoundMVVMChartViewModel()); 

Cá nhân tôi thích này trên xem đầu tiên (ví dụ như thêm một cái nhìn mà sau đó gán riêng DataContext của nó), bởi vì bạn thường muốn tham chiếu đến xem mô hình, quan điểm chỉ là phụ và được điều khiển gián tiếp bằng cách tương tác với mô hình xem.

+0

Tôi nhầm lẫn với câu trả lời của bạn vì tôi nghĩ bạn phải tạo các chế độ xem theo cách thủ công như đó là những gì mẫu dữ liệu đã làm. đối với một đối tượng viewmodel hiện có. Bạn có nghĩa là xem nên được thực hiện của bảng dock và nó có thể có nhiều mối quan hệ với nhiều viewmodels? Bạn sẽ phải tha thứ cho tôi vì tôi vẫn đang cố gắng học MVVM ở cấp độ sâu hơn. – djangojazz

+0

'DataTemplates' là bản thiết kế cho những gì * nên được tạo * để hiển thị một kiểu dữ liệu nhất định. Nếu bạn thêm một mô hình khung nhìn vào một số điều khiển hỗ trợ nó ('DockPanel' chỉ cho phép các điều khiển (do đó các khung nhìn) được thêm vào, không phải dữ liệu), kế hoạch chi tiết sẽ được thực thi và khung nhìn cho mô hình khung nhìn đó được tạo ra. Nếu bạn sử dụng 'DataTemplates', bạn không nên tự tạo khung nhìn, đó là toàn bộ điểm của việc sử dụng chúng. Về mặt các mối quan hệ, nó thường là 1 dạng xem-view với 1 view, những gì tôi nói không liên quan gì đến mối quan hệ nhiều-nhiều. –

+0

Được rồi tôi đoán sau đó khung tham chiếu duy nhất của tôi là ví dụ MSDN và trong ví dụ đó, chúng tạo ra các khung nhìn. Vì vậy, là mẫu của tôi không làm việc do bản chất của dữ liệu không được phép trong một điều khiển dock? Nếu tôi thay đổi nó để được kiểm soát tab truyền thống trong ví dụ MSDN nó vẫn sẽ cần một phần của viewmodel để thêm những thứ như: ic.dockpanel.Add (new DataBoundMVVMChartViewModel)) ;? Về cơ bản tôi đang tự hỏi liệu lớp điều khiển có luôn ở chế độ xem trên cùng hay không và bạn không thể bắt đầu điều khiển bằng quyền truy cập vào chế độ xem với mẫu dữ liệu ở giữa hư không – djangojazz

Các vấn đề liên quan