C# 如何使用MVVM WPF架构创建自定义UserControl
是否可以创建一个自定义控件,该控件具有与MVVM WPF模式相关的依赖项属性 如果是,如何在另一个MVVM应用程序中使用CustomControl并公开依赖项属性 编辑: 下面是一个简单的示例,允许我创建一个customControl,然后在另一个名为“TestCustomControl”的WPF应用程序中使用它。但是,依赖属性对我来说根本不起作用 CustomControlView.xamlC# 如何使用MVVM WPF架构创建自定义UserControl,c#,wpf,mvvm,devexpress,C#,Wpf,Mvvm,Devexpress,是否可以创建一个自定义控件,该控件具有与MVVM WPF模式相关的依赖项属性 如果是,如何在另一个MVVM应用程序中使用CustomControl并公开依赖项属性 编辑: 下面是一个简单的示例,允许我创建一个customControl,然后在另一个名为“TestCustomControl”的WPF应用程序中使用它。但是,依赖属性对我来说根本不起作用 CustomControlView.xaml <UserControl xmlns:dxg="http://schemas.devexpre
<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>
NB:“List.txt”是放置在“.\TestCustomControl\bin\Debug”中的文件
有人能帮我找到我的dependency属性不起作用的原因吗?这显然是可能的,也是创建自定义控件的最佳方法。因为没有依赖属性,我们无法轻松重用自定义控件。使用依赖属性,可重用性变得非常容易。您可以使用事件ICommand作为依赖属性,从而遵循MVVM模式并拥有更干净的代码 如果我详细说明如何在另一个MVVM应用程序中重用CustomControl,那么在这里就无法回答了。您可以直接转到VisualStudio并创建一个自定义控件。在代码隐藏中,定义一些依赖项属性,这些属性绑定到视图中您认为是动态的属性。在另一个应用程序中重用这个定制控件,并在重用它的同时设置这些属性
您还可以尝试使用ICommand将一些事件路由到视图模型。ie列表项选择更改事件的Dependency属性可以将命令路由到相应的视图模型。这显然是可能的,也是创建自定义控件的最佳方法。因为没有依赖属性,我们无法轻松重用自定义控件。使用依赖属性,可重用性变得非常容易。您可以使用事件ICommand作为依赖属性,从而遵循MVVM模式并拥有更干净的代码 如果我详细说明如何在另一个MVVM应用程序中重用CustomControl,那么在这里就无法回答了。您可以直接转到VisualStudio并创建一个自定义控件。在代码隐藏中,定义一些依赖项属性,这些属性绑定到视图中您认为是动态的属性。在另一个应用程序中重用这个定制控件,并在重用它的同时设置这些属性
您还可以尝试使用ICommand将一些事件路由到视图模型。ie列表项选择更改事件的依赖项属性可以将命令路由到相应的视图模型。用户控件或自定义控件将始终公开依赖项属性以支持数据绑定。然而,这与使用它的应用程序的体系结构完全无关。它是否是MVVM对于UserControl代码来说并不重要。需要记住的一点是,典型的UserControl不应该定义自己的视图模型,特别是不应该显式地设置自己的DataContext。相反,DataContext应该从其父控件或窗口继承。可重用控件仅为UI,不应附带自己的视图模型。就像TextBox没有TextBoxViewModel一样。只需将您需要的内容作为DependencyProperties公开,并将您的代码放入codebehind中,您就可以在任何类型的WPF应用程序中使用该控件。@对于像只绑定到
字符串的文本框
这样简单的东西,这似乎是一个很好的建议。但是,如果用户控件用于编辑一些复杂的东西,比如user
类,这些类将具有许多复杂的嵌套属性,那么该怎么办呢?当然用户
的用户控件将绑定到用户
的实例。该用户
不是控件的视图模型吗?在某种程度上,我觉得string
是Textbox
的视图模型。在使用MVVM时,我倾向于以两种方式之一使用用户控件:要么作为更复杂的数据模板,用户控件假设它的DataContext
将始终是特定类型的,要么作为独立控件,例如日历控件
或弹出控件
,它使用依赖属性接收显示所需的任何输入。看看你是否想要一个例子。@BradleyUffner我一直都是这样做的,但是虚拟机不是为UC设计的,UC是为虚拟机设计的,并且希望DataContext是那种类型的。当人们用UC的视图模型替换UC的DataContext时,他们会自讨苦吃。区别很小,但非常重要。MVVM标记中满是有绑定问题的人,因为他们将UI逻辑放入为UC设计的VM中,然后必须与另一个VM交互。UserControl或custom Control始终会公开依赖项属性以支持数据绑定。然而,这与使用它的应用程序的体系结构完全无关。它是否是MVVM对于UserControl代码来说并不重要。需要记住的一点是,典型的UserControl不应该定义自己的视图模型,特别是不应该显式地设置自己的DataContext。相反,DataContext应该从其父控件或窗口继承。可重用控件仅为UI,不应附带自己的视图模型。就像TextBox没有TextBoxViewModel一样。只需将您需要的内容作为DependencyProperties公开,并将您的代码放入codebehind中,您就可以在任何类型的WPF应用程序中使用该控件。@对于像只绑定到字符串的文本框
这样简单的东西,这似乎是一个很好的建议。但是,如果用户控件用于编辑一些复杂的东西,比如user
类,这些类将具有许多复杂的嵌套属性,那么该怎么办呢?用户肯定是c
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);
}
}
}
}
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
}
}
<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>
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
}
}