Click here to Skip to main content
14,975,931 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
I am writing a C# WPF application and following the MVVM pattern.
My ViewModel has an object in it called NetworkMain
My View has a DataGrid which binds to an ObservableCollection called FlowControls which is inside NetworkMain

My DataGrid Itemsource is defined as follows:

C#
<DataGrid ItemsSource="{Binding Path=NetworkMain.FlowControls}">


The above is working fine.

I want one of my columns in the DataGrid to be a ComboBox.
My column is defined as shown in the code at the bottom of this question.

The problem I have is I want the source of the ComboBox to use a collection called Pipes which is in NetworkMain and not FlowControls.

How can I do this?
I tried using Binding Path=NetworkMain.Pipes but I think it is looking for NetworkMain from within FlowControls which isn't correct.

Hope the above makes sense.

What I have tried:

XAML
<DataGridTemplateColumn Header="Downstream Pipe ID">
    <DataGridTemplateColumn.CellTemplate>
        <DataTemplate>
            <ComboBox 
                SelectedItem="{Binding Path=SelectedDownstreamPipeID, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                ItemsSource="{Binding Path=NetworkMain.Pipes}"
                DisplayMemberPath="Description" >
            </ComboBox>
        </DataTemplate>
    </DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>




EDIT

I have updated the XAML as follows and I now get the list I want in the ComboBox. What I can't get to work is the setting of the selected item.
I get the following error:
System.Windows.Data Error: 1 : Cannot create default converter to perform 'two-way' conversions between types 'Drain.Models.Network.Conduit' and 'System.String'. Consider using Converter property of Binding.


XAML
<UserControl.Resources>
    <CollectionViewSource 
        x:Key="Conduits" Source="{Binding NetworkMain.Conduits}">
    </CollectionViewSource>
</UserControl.Resources>


XAML
<DataGridComboBoxColumn 
    Header="Downstream Pipe ID"  
    SelectedItemBinding="{Binding outgoingConduit, Mode=OneWayToSource}" 
    ItemsSource="{Binding Source={StaticResource Conduits}}" 
    DisplayMemberPath="ID"/>


C#
public ObservableCollection<Conduit> Conduits { get; set; } = new();


C#
public Conduit outgoingConduit 
        { 
            get; 
            set; 
        }



I tried adding the following convertor:

XAML
<conv:ConduitObjectConvertor x:Key="ConduitObjectConvertor" />


XAML
SelectedItemBinding="{Binding outgoingConduit, Mode=TwoWay, Converter={StaticResource ConduitObjectConvertor}}"



I copied and pasted a convertor from an example online and I thought I adapted it correctly but I still get errors. The convertor is here:

C#
public class ConduitObjectConvertor : TypeConverter
    {
        public override bool CanConvertFrom(ITypeDescriptorContext context,
        Type sourceType)
        {
            return sourceType == typeof(Conduit);
        }

        public override object ConvertFrom(ITypeDescriptorContext context,
            System.Globalization.CultureInfo culture, object value)
        {
            return value as Conduit;
        }

        public override bool CanConvertTo(ITypeDescriptorContext context,
            Type destinationType)
        {
            return destinationType == typeof(Conduit);
        }

        public override object ConvertTo(ITypeDescriptorContext context,
            System.Globalization.CultureInfo culture, object value, Type destinationType)
        {
            return value == null ? null : value as Conduit;
        }
    }


The error I get is:

InvalidCastException: Unable to cast object of type 'Drain.Helper.Convertors.ConduitObjectConvertor' to type 'System.Windows.Data.IValueConverter'.
Posted
Updated 14-Jun-21 22:44pm
v2
Comments
Gerry Schmitz 14-Jun-21 13:30pm
   
Probably should be considering a DataGridComboBoxColumn first.

https://docs.microsoft.com/en-us/dotnet/api/system.windows.controls.datagridcomboboxcolumn?view=net-5.0

1 solution

How about naming an element further up the hierarchy:
XAML
<UserControl x:Name="RootElement" ...
Then bind to the DataContext.NetworkMain.Pipes property on that element:
XAML
<ComboBox
    SelectedItem="{Binding Path=SelectedDownstreamPipeID, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
    ItemsSource="{Binding ElementName=RootElement, Path=DataContext.NetworkMain.Pipes}"
    DisplayMemberPath="Description"
/>
   
Comments
Richard!i! 15-Jun-21 4:50am
   
I was pulling my hair with this in an parallel to you providing an answer. See edits to the question. I alsmost got it to work, but I saw from your response I was missing the UpdateSourceTrigger=PropertyChanged} on the selected item. I'll keep the list resource as I have it since it's working. Thanks for that final nugget of info to get it working.

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




CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900