2016-07-07 45 views
1

是否可以使用與MVVM WPF模式相關的屬性創建自定義控件?如何使用MVVM WPF體系結構創建自定義UserControl

如果是,您如何在另一個MVVM應用程序中使用CustomControl並公開依賴項屬性?

編輯:

下面一個簡單的例子,讓我創造一個customControl然後我用它命名爲「TestCustomControl」一個又一個WPF應用程序。 但是,依賴屬性對我來說根本不起作用。

enter image description here

CustomControlView.xaml

<UserControl xmlns:dxg="http://schemas.devexpress.com/winfx/2008/xaml/grid" xmlns:dxe="http://schemas.devexpress.com/winfx/2008/xaml/editors" x:Class="MyCustomControl.MyCustomUserControl" 
     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:dxmvvm="http://schemas.devexpress.com/winfx/2008/xaml/mvvm" 
     xmlns:myCustomControl="clr-namespace:MyCustomControl" 
     mc:Ignorable="d" 
     d:DesignHeight="300" d:DesignWidth="300"> 

<dxmvvm:Interaction.Triggers> 
    <dxmvvm:EventToCommand Command="{Binding LoadCommand}" EventName="Loaded" /> 
</dxmvvm:Interaction.Triggers> 

<Grid> 
    <Grid.RowDefinitions> 
     <RowDefinition Height="Auto" /> 
     <RowDefinition Height="*" /> 
    </Grid.RowDefinitions> 

    <dxe:ButtonEdit Height="40" Grid.Row="0"/> 
    <dxg:GridControl Grid.Row="1" ItemsSource="{Binding MyItems}" AutoGenerateColumns="AddNew"/> 
</Grid> 

CustomControlView.xaml.cs

using System.Windows; 
using System.Windows.Controls; 
namespace MyCustomControl 
{ 
    /// <summary> 
    /// Interaction logic for MyCustomUserControl.xaml 
    /// </summary> 
    public partial class MyCustomUserControl : UserControl 
    { 
     public MyCustomUserControl() 
     { 
      InitializeComponent(); 
      this.DataContext = new CustomControlViewModel(FilePath); 
     } 
     /// <summary> 
     /// File Path 
     /// </summary> 
     public static readonly DependencyProperty FilePathProperty = DependencyProperty.Register(
      "FilePath", typeof(string), typeof(MyCustomUserControl), new PropertyMetadata(string.Empty)); 
     public string FilePath 
     { 
      get { return (string)GetValue(FilePathProperty); } 
      set 
      { 
       SetValue(FilePathProperty, value); 
      } 
     } 
    } 
} 

CustomControlViewModel.cs

using System; 
using System.Collections.Generic; 
using System.Collections.ObjectModel; 
using System.IO; 
using System.Linq; 
using DevExpress.Mvvm; 
using DevExpress.Mvvm.DataAnnotations; 
namespace MyCustomControl 
{ 
    public class CustomControlViewModel:ViewModelBase 
    { 
     #region Fields 
     private ObservableCollection<string> _myItems; 
     private string _path; 
     #endregion 

     #region Constructors 
     public CustomControlViewModel(string path) 
     { 
      _path = path; 
     } 
     #endregion 

     #region Commands 

     [Command] 
     public void Load() 
     { 
      IEnumerable<string> allLinesText = new List<string>(); 
      try 
      { 
       allLinesText = File.ReadAllLines(_path).ToList(); 
      } 
      catch (Exception e) 
      { 

       Console.WriteLine(e.ToString()); 
      } 

      MyItems = new ObservableCollection<string>(allLinesText); 
     } 
     #endregion 

     #region Properties 
     public ObservableCollection<string> MyItems 
     { 
      get { return _myItems; } 
      set { SetProperty(ref _myItems, value,() => MyItems); } 
     } 
     #endregion 
    } 
} 

MainWindow.xaml

<Window xmlns:MyCustomControl="clr-namespace:MyCustomControl;assembly=MyCustomControl" 
    x:Class="TestCustomControl.MainWindow" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:testCustomControl="clr-namespace:TestCustomControl" 
    Title="MainWindow" Height="350" Width="525"> 
<Window.DataContext> 
    <testCustomControl:MainViewModel/> 
</Window.DataContext> 
<Grid> 
    <MyCustomControl:MyCustomUserControl FilePath="{Binding MyFile}"/> 
</Grid> 

MainViewModel.cs

using DevExpress.Mvvm; 
namespace TestCustomControl 
{ 
    public class MainViewModel: ViewModelBase 
    { 
     #region Fields 
     private string _myFile;   
     #endregion 

     #region Constructors 
     public MainViewModel() 
     { 
      MyFile = "List.txt"; 
     } 
     #endregion 

     #region Properties 
     public string MyFile 
     { 
      get { return _myFile; } 
      set { SetProperty(ref _myFile, value,() => MyFile); } 
     } 
     #endregion 
    } 
} 

NB: 「LIST.TXT」 是放置到」文件.. \ TestCustomControl \ bin \ Debug「

有人能幫我找到爲什麼我的依賴屬性不起作用嗎?

+0

UserControl或自定義控件將始終公開依賴項屬性以支持數據綁定。但是,這與您使用它的應用程序的體系結構完全無關。無論是否是MVVM,對於UserControl代碼都無關緊要。值得一提的是,典型的UserControl不應該定義自己的視圖模型,特別是它不應該明確地設置自己的DataContext。相反,DataContext應該從其父控件或窗口繼承。 – Clemens

+1

可重複使用的控件完全是UI,不應該帶有自己的視圖模型。就像TextBox沒有TextBoxViewModel一樣。只需將您需要的作爲DependencyProperties公開,並將代碼放在代碼隱藏中,並且可以在任何類型的WPF應用程序中使用該控件。 – Will

+0

@Will對於像'Textbox'這樣的簡單東西來說,這似乎是一個很好的建議,它只能綁定到'string'。但是用戶控件如何編輯像'User'類那樣複雜的東西,會有很多複雜和嵌套的屬性?當然,User的用戶控件將被綁定到User的一個實例。不會把'用戶'視爲控件的視圖模型嗎?在某些方面,我覺得'string'是'Textbox'的視圖模型。 –

回答

0

這顯然是可能的,這是創建自定義控件的最佳方式。因爲沒有依賴屬性,我們不能輕鬆地重用自定義控件。使用依賴項屬性時,重新使用性變得非常容易。您可以使用ICommand作爲依賴屬性,從而遵循MVVM模式,並且具有更簡潔的代碼。

如果我詳細說明如何在另一個MVVM應用程序中重用CustomControl,它會太寬泛,無法在這裏回答。你可以去Visual Studio並創建一個自定義控件。在後面的代碼中,在視圖中定義一些依賴屬性,這些屬性綁定到您認爲是動態的屬性。在另一個應用程序中重用這個非常自定義的控件,並在重用它時設置這些屬性。

您也可以嘗試用ICommand將某些事件路由到視圖模型。即列表項選擇改變事件的依賴屬性可以將命令路由到對應的視圖模型。

+0

我知道可以創建自定義控件。但問題是,是否可以使用MVVM arch創建它。因爲我已經在代碼後面創建了一個具有依賴項屬性的自定義控件,並且我在另一個wpf應用程序中也使用了它。然而,當我試圖用MVVM創建自定義控件時,我並沒有消費依賴屬性! – xtensa1408

+0

誰告訴你不能在MVVM中使用依賴屬性?這顯然是可能的。假設你有一個從按鈕派生的自定義控件。你想在其中使用MVVM。在代碼後面用類型** ICommand ** say ** ButtonDoubleClicked **定義一個依賴項屬性。在按鈕的雙擊處理程序上引發此命令。現在,當您重新使用此自定義控件時,請將相應視圖模型中的** ButtonDoubleClicked **定義爲某個ICommand屬性,然後調用它。這只是一個簡短的例子。你可以在谷歌中獲得很多例子。 – ViVi

+0

@ xtensa1408:可重用控件沒有視圖模型,也不需要。你可以用後面的代碼創建一個自定義控件。然後,您可以在綁定到視圖模型的視圖中重用它。希望你明白了。 – ViVi

相關問題