2016-07-07 86 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

相关问题