0

I can't for the love of god sort this out. I did see this answer: How to Bind data to DataGridComboBoxColumn in DataGrid using MVVM and many more for that matter but I am not sure what I am doing wrong. Here's my thinking. I have a DataGrid that is bound to Views collection. Each row is represented by a object of class ViewWrapper ViewWrapper has a property called ViewTemplate that is of type ViewWrapper. So basically view wrapper can store another view wrapper inside of it. Now, I want to hook up a ComboBox to a list of ViewWrapper objects stored in variable called ViewTemplates. That's available on a ViewModel. It holds all possible view wrappers that a View Template property can be potentially set to. Now, I want to bind the SelectedItem of the ComboBox to ViewWrapper.ViewTemplate from the DataGrid row. I can't get this thing to work.

Here's my setup:

XAML:

<UserControl x:Class="GrimshawRibbon.Revit.Views.ViewManager.ViewManagerView"
             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:i="http://schemas.microsoft.com/expression/2010/interactivity"
             xmlns:local="clr-namespace:GrimshawRibbon.Revit.Views.ViewManager"
             xmlns:ex="clr-namespace:GrimshawRibbon.Revit.Wpf.Extensions"
             xmlns:controls="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro"
             xmlns:cmd="clr-namespace:GalaSoft.MvvmLight.Command;assembly=GalaSoft.MvvmLight.Platform"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="500">
    <UserControl.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.xaml" />
                <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Fonts.xaml" />
                <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Colors.xaml" />
                <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/Blue.xaml" />
                <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/BaseLight.xaml" />
                <ResourceDictionary Source="pack://application:,,,/GrimshawRibbon;component/Revit/Wpf/Style/GrimshawTheme.xaml"/>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </UserControl.Resources>
    <Grid>
        <ex:DataGridEx x:Name="dgViews" 
                               Style="{StaticResource AzureDataGrid}" 
                               Margin="10" 
                               AutoGenerateColumns="False" 
                               ItemsSource="{Binding Views, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" 
                               CanUserAddRows="False" 
                               IsReadOnly="False" 
                               SelectionMode="Extended" 
                               SelectionUnit="FullRow" 
                               SelectedItemsList="{Binding SelectedViews, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
            <i:Interaction.Triggers>
                <i:EventTrigger EventName="CellEditEnding">
                    <cmd:EventToCommand PassEventArgsToCommand="True" Command="{Binding CellEditEndingCommand}"/>
                </i:EventTrigger>
            </i:Interaction.Triggers>
            <DataGrid.Columns>
                <DataGridTextColumn Header="Name" Binding="{Binding Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Width="*"/>
                <DataGridTextColumn Header="ViewType" Binding="{Binding ViewType}" Width="100" IsReadOnly="True"/>
                <DataGridTextColumn Header="ViewGroup" Binding="{Binding ViewGroup, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Width="120" IsReadOnly="False"/>
                <DataGridTextColumn Header="ViewSubGroup" Binding="{Binding ViewSubGroup, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Width="120" IsReadOnly="False"/>
                <DataGridCheckBoxColumn ElementStyle="{DynamicResource MetroDataGridCheckBox}" 
                                        EditingElementStyle="{DynamicResource MetroDataGridCheckBox}" 
                                        Header="OnSheet" 
                                        Binding="{Binding OnSheet, Mode=TwoWay}" 
                                        IsReadOnly="True" 
                                        Width="80">
                </DataGridCheckBoxColumn>
                <DataGridComboBoxColumn Header="ViewTemplate" Width="150" SelectedItemBinding="{Binding WhatDoISetThisTo?}">
                    <DataGridComboBoxColumn.ElementStyle>
                        <Style TargetType="ComboBox">
                            <Setter Property="ItemsSource" Value="{Binding ViewTemplates}"/>
                            <Setter Property="IsReadOnly" Value="True"/>
                        </Style>
                    </DataGridComboBoxColumn.ElementStyle>
                    <DataGridComboBoxColumn.EditingElementStyle>
                        <Style TargetType="ComboBox">
                            <Setter Property="ItemsSource" Value="{Binding ViewTemplates}"/>
                        </Style>
                    </DataGridComboBoxColumn.EditingElementStyle>
                </DataGridComboBoxColumn>
            </DataGrid.Columns>
        </ex:DataGridEx>
    </Grid>
</UserControl>

ViewModel:

public class ViewManagerViewModel : ViewModelBaseEx
    {
        public ViewManagerModel Model;
        public ObservableCollection<ViewWrapper> Views { get; private set; }
        public ObservableCollection<ViewWrapper> ViewTemplates { get; private set; }
        public IList SelectedViews { get; set; }
        public RelayCommand<DataGridCellEditEndingEventArgs> CellEditEndingCommand { get; set; }

        public ViewManagerViewModel(Document doc)
        {
            Model = new ViewManagerModel(doc);
            Views = Model.CollectViews();
            ViewTemplates = Model.CollectViewTemplates();
            CellEditEndingCommand = new RelayCommand<DataGridCellEditEndingEventArgs>(args => OnCellEditEnding(args));
        }

        /// <summary>
        /// Logic for handling cell editing events.
        /// </summary>
        /// <param name="e">DataGrid Row object.</param>
        private void OnCellEditEnding(DataGridCellEditEndingEventArgs e)
        {
            var wrapper = e.Row.Item as ViewWrapper;
            switch (e.Column.SortMemberPath)
            {
                case "Name":
                    Model.ChangeName(wrapper);
                    break;
                case "ViewGroup":
                    Model.SetParameter(wrapper, "View Group", wrapper.ViewGroup);
                    break;
                case "ViewSubGroup":
                    Model.SetParameter(wrapper, "View Sub Group", wrapper.ViewSubGroup);
                    break;
                default:
                    break;
            }
        }

        public override void Apply()
        {
            var vw = new List<ViewWrapper>();
            foreach (ViewWrapper v in SelectedViews)
            {
                vw.Add(v);
            }

            Model.Delete(vw);

            // update collection so that rows get deleted in datagrid
            foreach (ViewWrapper i in vw)
            {
                Views.Remove(i);
            }
        }
    }

ViewWrapper class:

    public abstract class ElementWrapper : ObservableObject
    {
        public virtual object Self { get; set; }
        public virtual ElementId ID { get; set; }
        public virtual string Name { get; set; }
    }



    public class ViewWrapper : ElementWrapper
    {
        public string ViewType { get; set; }
        public bool IsSelected { get; set; }
        public bool OnSheet { get; set; }
        public string ViewGroup { get; set; }
        public string ViewSubGroup { get; set; }
        public ViewWrapper ViewTemplate { get; set; }

    }
Community
  • 1
  • 1
konrad
  • 3,544
  • 4
  • 36
  • 75

1 Answers1

2

The SelectedItemBinding property should be bound to the ViewTemplate property of the ViewWrapper object that represents the current row.

And since the ViewTemplates collection is defined in the view model you should use a RelativeSource binding to be able to bind to it.

Try this:

<DataGridComboBoxColumn Header="ViewTemplate" Width="150" SelectedItemBinding="{Binding ViewTemplate}">
    <DataGridComboBoxColumn.ElementStyle>
        <Style TargetType="ComboBox">
            <Setter Property="ItemsSource" Value="{Binding DataContext.ViewTemplates, RelativeSource={RelativeSource AncestorType=DataGrid}}"/>
            <Setter Property="IsReadOnly" Value="True"/>
        </Style>
    </DataGridComboBoxColumn.ElementStyle>
    <DataGridComboBoxColumn.EditingElementStyle>
        <Style TargetType="ComboBox">
            <Setter Property="ItemsSource" Value="{Binding DataContext.ViewTemplates, RelativeSource={RelativeSource AncestorType=DataGrid}}"/>
        </Style>
    </DataGridComboBoxColumn.EditingElementStyle>
</DataGridComboBoxColumn>
mm8
  • 163,881
  • 10
  • 57
  • 88
  • This only gets me partially there. I can now see all of the `ViewTemplates` in my dropdown, but none of the values are selected. Some of the row items will already have a value for ViewTemplate assigned and in that case when the selected item of the combo box is bound to it, it should set the proper value from the dropdown. Right? – konrad Feb 24 '17 at 14:41
  • It depends on how the ViewTemplate property is being set. You need to set to an instance of a ViewWrapper that is present in the ViewTemplates collection of the view model. – mm8 Feb 24 '17 at 14:42
  • well, they are the same class. what if i overwrote the `Equals` method on that wrapper class. Would that tell it that they are the same instance per say, because yes, they are both instantiated separately so i can see how it thinks they are not the same object. – konrad Feb 24 '17 at 14:47
  • Indeed it did! Thank you for help. It seems to be doing all right now. I just need to resurrect styling from the Metro library. I should be able to just set it from a Dynamic Resource right? – konrad Feb 24 '17 at 14:58