MoonKnight
MoonKnight

Reputation: 23833

How to Get a Reference to a ViewModel

All, I have a custom DataGridView control which overrides the DataGidView's OnItemsSourceChanged event. Inside this event I need to get a reference to a data set in the relevant ViewModel. Code is

public class ResourceDataGrid : DataGrid
{
    protected override void OnItemsSourceChanged(
        System.Collections.IEnumerable oldValue, 
        System.Collections.IEnumerable newValue)
    {
        if (Equals(newValue, oldValue)) 
            return;
        base.OnItemsSourceChanged(oldValue, newValue);

        ResourceCore.ResourceManager manager = ResourceCore.ResourceManager.Instance();
        ResourceDataViewModel resourceDataViewModel = ?? // How do I get my ResourceDataViewModel
        List<string> l = manger.GetDataFor(resourceDataViewModel); 
        ...
    }
}

On the marked line I want to know how to get a reference to ResourceDataViewModel resourceDataViewModel. The reson is that i have multiple tabs each tab contains a data grid and ascociated ViewModel, the ViewModel holds some data that I need to retrieve [via the ResourceManager] (or is there another, better way?).

The question is, from the above event, how can I get the ascociated ResourceDataViewModel?

Thanks for your time.

Upvotes: 1

Views: 3475

Answers (3)

Lawrence
Lawrence

Reputation: 3297

You ask if there is a better way... In my experience if you find yourself subclassing a UI element in WPF there ususally is.

You can get away from embedding business logic (the choice of which data to display in the grid), by databinding your entire tab control to a view model.

To demonstrate - here is a very simple example. This is my XAML for the window hosting the tab control:

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <TabControl ItemsSource="{Binding Tabs}" SelectedItem="{Binding SelectedTab}">
            <TabControl.ItemContainerStyle>
                <Style TargetType="TabItem">
                    <Setter Property="Header" Value="{Binding TabName}"></Setter>
                </Style>
            </TabControl.ItemContainerStyle>
            <TabControl.ContentTemplate>
                <DataTemplate>
                    <Grid>
                        <DataGrid ItemsSource="{Binding TabData}"></DataGrid>
                    </Grid>
                </DataTemplate>
            </TabControl.ContentTemplate>
        </TabControl>
    </Grid>
</Window>

The data context of my window is a TabsViewModel (I am using the NotificationObject that can be found in the PRISM NuGet Package):

public class TabsViewModel: NotificationObject
{
    public TabsViewModel()
    {
        Tabs = new[]
            {
                new TabViewModel("TAB1", "Data 1 Tab 1", "Data 2 Tab1"), 
                new TabViewModel("TAB2", "Data 1 Tab 2", "Data 2 Tab2"), 
            };
    }

    private TabViewModel _selectedTab;
    public TabViewModel SelectedTab
    {
        get { return _selectedTab; }
        set
        {
            if (Equals(value, _selectedTab)) return;
            _selectedTab = value;
            RaisePropertyChanged(() => SelectedTab);
        }
    }

    public IEnumerable<TabViewModel> Tabs { get; set; } 
}

public class TabViewModel
{
    public TabViewModel(string tabName, params string[] data)
    {
        TabName = tabName;
        TabData = data.Select(d => new RowData(){Property1 = d}).ToArray();
    }
    public string TabName { get; set; }
    public RowData[] TabData { get; set; }
}

public class RowData
{
    public string Property1 { get; set; }
}

This is obviously an over simplified case, but it means that if there is any business logic about precisely what data to show in each tab, this can reside in one of the view models, as opposed to the code behind. This gives you all the 'separation of concerns' benefits that MVVM is designed to encourage...

Upvotes: 1

McGarnagle
McGarnagle

Reputation: 102723

Get the DataContext and cast it to the view-model type:

var viewModel = this.DataContext as ResourceDataViewModel

Upvotes: 3

ΩmegaMan
ΩmegaMan

Reputation: 31576

Put a static reference to it on your app, when the VM is created place its reference on the static and access it as needed.

Upvotes: 1

Related Questions