在本系列的这一部分中,我们将解决如何在插件类和视图模型类之间以及视图模型类和 WPF 窗口之间关联值。
首先,在窗口中创建一些控件,就像我在下面所做的那样。
我们有一个组合框、三个单选按钮、一个文本框、两个复选框和一个确定按钮。这些是在 Windows 中经常使用的一些控件。我们需要将一些变量与每个控件相关联,但单选按钮除外,它们共享一个变量。
为了关联它们,我们需要创建一个定义类,我们将其称为视图模型类。
在创建视图模型类之前,让我们先从 nu-get 下载“Prism”库。我们将使用 Prism 库作为我们的 MVVM 类的基础库。
现在,我们为新的视图模型类创建一个新的类文件。我们将其命名为“MyViewModel.cs”。打开新创建的文件并修改文件,使其继承类成为视图模型类所需的函数:
使用 Prism.MVVM; 命名空间 MyRevitWPFProgram { 类 vmodThisWindow : BindableBase { } }
BindableBase 基类只是从 INotifyPropertyChanged 接口类派生的简化类,其中已经包含事件声明和函数。
现在我们创建我们需要的变量。所有控件都有其对应的变量类型,因此我们必须知道分配给哪个变量。从 TextBox 收集文本字符串时,我们需要一个字符串变量。当我们需要一个文本框的数字时,我们需要一个带有字符串转换器的数字变量。当我们需要一些东西来监控一个项目是否被选中时,每个项目的布尔值,或者带有转换器和单选按钮参数的整数。WPF 初学者可以在 Internet 上获得有关这些的更多详细信息。
但是我想推荐一件事:不要在视图模型中使用任何 REVIT 类。使用这些类将无法让您在 Visual Studio 中使用 WPF 自动化功能的功能,最终窗口将不会显示在设计屏幕中,从而使您无法以图形方式修改窗口的内容。我最近才通过 Visual Studio Community 2015 验证了这一点。
所以我为我的窗口声明了我的变量,如下所示。
私有ObservableCollection< string > _StringSelection; 私人 字符串_selectedString; 私人 int _radioOption; 私人 布尔_isSelectedOption3; 私人 布尔_isSelectedAddMe; 私人 布尔_isSelectedAddMeToo; 私有字典<字符串,整数> _dicIdString; public ObservableCollection< string > StringSelection { 得到 { 返回_StringSelection; } 放 { _StringSelection =值; } } 公共 字符串SelectedString { 得到 { 返回_selectedString; } 放 { _selectedString =值; RaisePropertyChanged( "SelectedString" ); } } 公共 int RadioOption { 得到 { 返回_radioOption; } 放 { _radioOption =值; RaisePropertyChanged( "RadioOption" ); } } public bool IsSelectedOption3 { 得到 { 返回_isSelectedOption3; } 放 { _isSelectedOption3 =值; RaisePropertyChanged( "IsSelectedOption3" ); } } public bool IsSelectedAddMe { 得到 { 返回_isSelectedAddMe; } 放 { _isSelectedAddMe =值; RaisePropertyChanged( "IsSelectedAddMe" ); } } public bool IsSelectedAddMeToo { 得到 { 返回_isSelectedAddMeToo; } 放 { _isSelectedAddMeToo =值; RaisePropertyChanged( "IsSelectedAddMeToo" ); } } 公共字典<字符串,整数> DicIdString { 得到 { 返回_dicIdString; } 放 { _dicIdString =值; } }
以下是我在创建视图模型类时声明变量时建议的主要技巧:
一个。) 当您的窗口中有一个组合框时,请了解其用途。例如,如果您想放置某些家庭类型的数据并仅选择其中一种,则使用Dictionary 类并将名称指定为键,将Id 的IntegerValue 指定为值。但是,如果内容看起来很复杂(例如,以名称、ID 和颜色作为主要信息的材料),请为该内容创建一个唯一的类并仅包含您需要的变量。在这种情况下,您可以使用简单的 List<> 类或更复杂的 IObservableCollection<> 类(但由于大多数时候组合框的内容不会改变,List<> 就足够了)。
创建字典时,永远不要忘记在 DisplayMemberPath 属性中输入单词“Key”,在 SelectedValuePath 属性中输入单词“Value”。This will make the combo box propagate only the keys to show in the combo box, and when one is selected, return its corresponding integervalue of the id.
另一方面,当使用类列表时,使用 Binding 过程将一个类项绑定到 DisplayMemberPath 要在组合框中显示的内容,并将另一个类项绑定到 SelectedValuePath 属性。
在这两种情况下,将变量绑定到组合框的 SelectedValue 属性,其类型与您在 SelectedValuePath 属性中绑定的类型相同。此变量必须是独立的,您可能不需要向其添加 RaisePropertyChanged() 函数。
b.) 当使用 get-set 声明变量并从窗口内的任何控件处理用户输入的一部分时,始终在 'set 的最后一部分调用 RaisePropertyChanged(“<name of the public variable>”) ' 分割。
c.) 不要在构造函数中包含参数。也不要创建构造函数的重载。创建视图模型类后执行所有变量分配。
自动化绑定过程
当声明了所有变量后,首先编译程序并确保它没有错误。否则,您无法使用将上下文绑定到 WPF 窗口的交互方法。
现在我们将使用这种交互式方法将视图模型类绑定到我们的 XAML 窗口。
在 XAML 的设计视图中选择窗口框架,然后从属性窗口转到DataContext属性并单击它旁边的“新建”按钮。这会将您带到下方的窗口。
从嵌套列表中 选择“MyViewModel”类,然后按OK。这将自动将您的视图模型集成到您的 WPF 窗口。
在上图中,您可以通过使用 <Window.DataContext> 封闭我们的视图模型类来验证 Visual Studio 是否让我们将我们的视图模型类绑定到 WPF 窗口。
接下来,我们以类似的方式将变量绑定到窗口控件。
首先,从设计视图中选择TextBox,然后从属性中,单击右侧的小框(黑色阴影;表示它具有设置值)。
然后从上下文菜单中,选择“创建数据绑定...”
这会将您带到另一个窗口,如下所示。
确保 Binding Type 设置为Data context,以便您可以在窗口右侧看到我们创建的视图模型类。展开MyViewModel,就会出现我们声明的所有变量。选择SelectedString : (String)并按OK。
现在我们可以从 XAML 代码检查它是否使我们绑定。应该和我下面的一样。可以看到在TextBox 的Text 属性中绑定了SelectedString。
绑定单选按钮
这里的一个复杂领域是将三个单选按钮绑定到一个变量 RadioOption 中。我们将使用转换器并在每个单选按钮中集成转换器参数。
下面是我如何编写我的 Converter 类。我创建了一个名为 MyConverterRadioButton 的新类,它派生自 IValueConverter 接口。
public class MyConverterRadioButton : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfoculture)
{
return (parameter.ToString() == value.ToString());
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return (bool)value ? 参数:Binding.DoNothing;
}
}
由于我们在 Visual Studio 的“属性”窗口中使用自动化功能,因此我们将转换器类与所有单选按钮相关联。
在属性窗口中,单击 IsChecked 属性右侧的方块以显示下面的窗口。在窗口的右侧,选择RadioOption变量(1),然后在下面的Converter选项中下拉组合框(2),然后选择“<Add value converter...>”(3)
这将带您进入如下所示的子窗口。如果您创建的转换器类出现(在本例中为 MyConverterRadioButton),则选择该类并按 OK。否则,在返回到此窗口之前,先恢复并编译程序。
选择转换器类后,我们现在可以使用前一个窗口在每个单选按钮中分配转换器参数。在 ConverterParameter 字段中,为第一个单选按钮输入“0”,为第二个单选按钮输入“1”,为第三个 (4) 输入“2”。完成后按 OK (5)。结果将反映在 XAML 代码中。
接下来,一旦选择了第三个单选按钮,我们将关联文本框以进行编辑。选择窗口的文本框,然后在“属性”面板中,按 IsEnabled 属性右侧的方块。然后从上下文菜单中选择创建数据绑定。
从窗口中,选择变量 IsSelectedOption3 (1) 并按 OK (2)。
然后我们将在 RadioOption set 函数中使用下面的代码更新我们的视图模型类,以便在每次选择第三个单选按钮时激活它,否则将其停用。
公共 int RadioOption
{
获取
{
返回 _radioOption;
}
设置
{
_radioOption = 值;
IsSelectedOption3 = 值 == 2;
RaisePropertyChanged(“RadioOption”);
}
}
绑定复选框
绑定复选框很简单,因为该方法与上面提到的其他方法类似。但这一次,我们必须单击两个复选框的 IsChecked 属性的方块,并创建数据绑定。相应地使用 IsSelectedAddMe 和 IsSelectedAddMeToo。
绑定按钮命令
尽管该区域在我们的示例中没有发挥重要作用,但了解如何绑定它们以及在执行程序时它们的功能是必不可少的。
将此代码添加到视图模型类中并重新编译程序。
#region 命令和操作
public ICommand OKCommand
{
get
{
return new DelegateCommand(OKAction);
}
}
private void OKAction()
{
// 此函数将在按钮事件后执行。
}
#endregion
我们只是在按下 OK 按钮时给它一个动作。为了给事件一个与 MVVM 兼容的动作,首先我们从 ICommand 类中创建一个变量 OKCommand。然后在它的 get 函数中,代码只返回一个新的 DelegateCommand 声明,它有一个 OKAction 参数,这将是一个要调用的 void 函数。DelegateCommand 是 Prism 的一个函数,因此请确保在您的项目中安装了 Prism 以便能够使用它。
一旦命令被调用,被调用的函数就会执行,但是,正如上面的评论中提到的,OKAction 将在按下它的事件之后执行。例如,您从名为 OKButton_Click() 的 Button 生成一个事件。OKButton_Click() 中的代码将在 OKAction() 之前先执行。您始终可以通过调试程序来验证它并亲自查看。
现在你知道了通常事件和MVVM事件定义的命令事件的执行顺序,将程序规划成它的重要性;什么必须前后,或者可能,彼此的必要性。在这种情况下,由于 OK 按钮是唯一的按钮,我们可能不会在 OKAction 内部添加代码,但是当涉及到其他按钮时,这个技巧可能会更方便。
现在我们完成了为按钮定义命令事件。编译一下,看看有没有错误。如果没有,让我们从“属性”窗口绑定它。
在 Properties 窗口的 Miscellaneous 组中,有一个名为 Command 的项目。此项接受任何 ICommand 类型的变量,这将在下面进一步说明。单击右侧的方块,然后从上下文菜单中选择“创建数据绑定”。
在窗口中,选择 OKCommand 变量 (1) 并按 OK (2)。如果你注意到,OKCommand 是 ICommand 的变量,它被 WPF 识别。
大佬地址View-ViewModel-ing for your WPF Windows (Revit API with WPF Series 3/3) | Math, CAD and BIM Thingyshttps://mathcadbimthingy.wordpress.com/2017/01/25/view-viewmodel-ing-for-your-wpf-windows-revit-api-with-wpf-series-33/