使用附加属性在 ViewModel 中进行访问控制






4.12/5 (12投票s)
本文展示了如何使用附加属性在 ViewModel 中访问控件。
引言
在 MVVM 中,有时我们需要在 ViewModel
中访问特定的控件。例如,如果我想将 IEnumerable
绑定到 DataGrid
,因为我无法在运行时确定字段。现在,如果我绑定 IEnumerable<dynamic>
并设置 AutogeneratedColumns = true
,DataGrid
仍然不会显示记录,因为每一行都作为具有动态属性表示字段的 "ExpandoObject
" 返回。在这种情况下,我必须动态添加列。为此,我需要 DataGrid
控件。现在,要获取 ViewModel
中的 dataGrid
控件,我们可以使用附加属性。让我们尝试一下。
背景
为了更好地理解本文,我建议阅读关于附加属性的内容。
Using the Code
首先,在 ViewModel
中为控件定义附加属性。
Public static readonly DependecyProperty DataGridProperty = _
DependencyProperty.RegisterAttached("DataGrid", typeof(DataGrid),
typeof(MainWindowViewModel),
New FrameworkPropertyMetadata(OnDataGridChanged));
public static void SetDataGrid(DependencyObject element, DataGrid value)
{
element.SetValue(DataGridProperty, value);
}
public static DataGrid GetDataGrid(DependencyObject element)
{
return (DataGrid)element.GetValue(DataGridProperty);
}
将 name
属性分配给控件。现在我们需要将控件与此附加属性绑定。
<Window x:Class="AccessControlsInViewModel.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:AccessControlsInViewModel"
Title="Access Controls In ViewModel" Height="350" Width="525">
<DockPanel>
<StackPanel Orientation="Horizontal" DockPanel.Dock="Top" Margin="0,0,0,25">
<Button Content="Add Columns" Command="{Binding AddCommand}" />
</StackPanel>
<DataGrid Name="accessGrid" ItemsSource="{Binding ListOfPerson}"
local:MainWindowViewModel.DataGrid="{Binding ElementName=accessGrid}" />
</DockPanel>
</Window>
这里我使用 ElementName
绑定将控件与附加属性绑定。
使用附加属性的原因是我们需要将整个控件与属性绑定,并且没有内置属性可用于执行此操作。
然后定义一个 static
变量来存储控件,并在附加属性更改事件上分配其值。
// DataGrid Instance in the viewModel
private static DataGrid dataGrid = null;
// DataGrid Property changed event
public static void OnDataGridChanged
(DependencyObject obj, DependencyPropertyChangedEventArgs args)
{
dataGrid = obj as DataGrid;
}
现在我们已经在 ViewModel
中拥有了可用的控件。因此,我们可以实现与在代码隐藏文件中所能做的一切相同的功能。
对于 DataGrid
示例,在添加 button
的命令上,我们可以像这样添加列
private static void AddDynamicColumnsToDataGrid()
{
IEnumerable<IDictionary<string, object>>
rows = dataGrid.ItemsSource.OfType<IDictionary<string, object>>();
IEnumerable<string> columns = rows.SelectMany
(d => d.Keys).Distinct(StringComparer.OrdinalIgnoreCase);
foreach (string text in columns)
{
// now set up a column and binding for each property
var column = new DataGridTextColumn
{
Header = text,
Binding = new Binding(text)
};
dataGrid.Columns.Add(column);
}
}
关注点
为了解决这个问题,我同时在 Button
上添加了单击事件和命令,并且这个技巧对我来说真的有效。但是由于我正在使用 MVVM,我需要在 ViewModel
中执行此操作,并且我找到了这个解决方案。