Click here to Skip to main content
15,881,380 members
Articles / Desktop Programming / WPF

Access Controls in ViewModel using Attached Properties

Rate me:
Please Sign up or sign in to vote.
4.12/5 (13 votes)
12 Sep 2011CPOL2 min read 61.8K   1.4K   13   10
This article shows how we can access controls in the viewmodel using attached properties.

Introduction

In MVVM, there are situations when we need to have the access of the particular controls in the ViewModel. For example, if I want to bind IEnumerable<dynamic /> to the DataGrid because I am not able to determine the fields till runtime. Now if I bind IEnumerable<dynamic> and set AutogeneratedColumns = true then also DataGrid will not show the records because each row is returned as an "ExpandoObject" with dynamic properties representing the fields. In this case, I have to add the columns dynamically. To do that, I need the DataGrid control. Now to get the dataGrid control in the ViewModel we can use attached property. Let's try.

Background

For better understanding of this article, I would recommend reading of the attached properties.

Using the Code

First of all, define the attached property for the control in the ViewModel.

VB.NET
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);  
 }

Assign the name property on the control. Now we need to bind the control with this attached property.

XML
<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>

Here I have binded the control with the attached property using the ElementName binding.

The reason behind using attached property is here we need to bind the whole control with the property and there is no in-built property available for doing this.

Then define a static variable for the control and assign its value on the attached property changed event.

C#
// 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;  
 }

Now we have the control available in the ViewModel. So we can achieve everything that we can do in the code behind file.

For the DataGrid example, on the add button's command we can add the columns like this:

C#
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);
}
}

Points of Interest

To solve this problem, I have added click and command both on the Button and the trick has really worked for me. But as I was using MVVM, I needed to do it in the ViewModel and I found out this solution.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
India India
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralMy vote of 3 Pin
hari111r14-Jun-13 0:47
hari111r14-Jun-13 0:47 
GeneralMy vote of 5 Pin
Abadani12-Feb-13 4:11
Abadani12-Feb-13 4:11 
Questionblabla, but my five Pin
Guillaume Waser17-Jul-12 8:14
Guillaume Waser17-Jul-12 8:14 
GeneralMy vote of 2 Pin
Paul D'hertoghe30-Jan-12 3:48
professionalPaul D'hertoghe30-Jan-12 3:48 
SuggestionAnother Approach Pin
Dave Kerr13-Sep-11 1:16
mentorDave Kerr13-Sep-11 1:16 
GeneralMy vote of 5 Pin
Rajnikant Rajwadi12-Sep-11 18:38
Rajnikant Rajwadi12-Sep-11 18:38 
QuestionVery bad idea PinPopular
Eugene Sadovoi11-Sep-11 14:44
Eugene Sadovoi11-Sep-11 14:44 
You should NEVER access your controls from ViewModel.
GeneralRe: Very bad idea Pin
Yuriy Zanichkovskyy11-Sep-11 20:44
Yuriy Zanichkovskyy11-Sep-11 20:44 
GeneralRe: Very bad idea Pin
Bhavik Barot12-Sep-11 5:03
Bhavik Barot12-Sep-11 5:03 
GeneralRe: Very bad idea Pin
Eugene Sadovoi12-Sep-11 14:11
Eugene Sadovoi12-Sep-11 14:11 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.