KSF
KSF

Reputation: 388

How to cast in XAML to access sub-class properties

In my project I have a list of Units which is being used as the source of data for a DataGrid. The Units type has two types of subclasses, AUnits and BUnits. Each Unit in the list is either an AUnit or aBUnit. My issue is when I try to bind to a property specific to one of the subclass unit types, XAML doesn't see it and I just get back 0's. Normally, if this was being done in C# I would just cast it and access the property, but I am not able to do that at this point in my code. The bindings are being created in C# like this:

 dgtc.Header = Properties.Resources.MaxPressure;
 dgtc.MinWidth = 25;
 dgtc.Width = Properties.Settings.Default.MaxPressureColumnWidth;
 dgtc.IsReadOnly = true;
 dgtc.Binding = new Binding("Unit.MaxDepthRelativeToEntry")
 {
     Converter = new DistanceUnitsConverter()
 };

Where dgtc is a DataGridTextColumn. Unit.MaxDepthRelativeToEntry comes through as 0 because it is a property on the subclass of an AUnit, so XAML thinks I am trying to access an non-existent property.

I have read this answer and so far I have tried some of the following syntaxes:

dgtc.Binding = new Binding("AUnit.MaxDepthRelativeToEntry")
dgtc.Binding = new Binding("Unit(MyNameSpace:AUnit).MaxDepthRelativeToEntry")
dgtc.Binding = new Binding("Unit(MyNameSpace:AUnit.MaxDepthRelativeToEntry)")

and was not able to get any of those to work. I have also tried doing this through a converter, but the issue is, I don't have the list of units available to me when I am constructing the DataGrid/ setting up the bindings/etc. so I am not able to grab the property out of the instance and return it. Does anyone know of any way that I can, preferably in XAML, get to the properties of a subclass type of the type I am binding to?

Edit:

My DataGrid has the following XAML:

<DataGrid x:Name="JobListView"
              AutoGenerateColumns="False"
              ItemsSource="{Binding UnitStatusCollection, Mode=TwoWay}"
              CanUserDeleteRows="False"
              Style="{StaticResource JobGridViewStyle}"
              SelectedItem="{Binding JobsListViewSelectedUnitInfo, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
              Utility:DataGridColumnsBehavior.BindableColumns="{Binding DataGridColumns}"
              ContextMenu="{StaticResource ListViewContextMenu}"
              Margin="10,5,10,2"
              Grid.Row="2"
              SelectionMode="Single"
              SelectionUnit="FullRow"
              HorizontalAlignment="Stretch"
              HorizontalContentAlignment="Stretch"
              RowStyle="{StaticResource DataGridRowStyle}"
              CellStyle="{StaticResource DataGridCellStyle}"
              AlternationCount="2"
              HorizontalScrollBarVisibility="Visible"
              VerticalScrollBarVisibility="Visible"
              CanUserResizeRows="False"
              HorizontalGridLinesBrush="#d6d6d6"
              VerticalGridLinesBrush="#d6d6d6"
              Background="#EAEAEA"
              >

The ItemsSource is set to the UnitStatusCollection which is an ObservableCollection of a class called UnitInfo which holds a Unit and a UnitStatus. I need to access the property MaxDepthRelativeToEntry in Unit of UnitInfo. But I need to be able to see Unit as AUnit

Upvotes: 0

Views: 1687

Answers (1)

Rachel
Rachel

Reputation: 132548

If you are binding to a list of Unit objects, then the DataContext for your DataGridTextColumn should be the AUnit or BUnit object itself, so your binding path should just be new Binding("MaxDepthRelativeToEntry").

You might get some kind of runtime warning for properties that only exist on one SubClass but not others, but it shouldn't throw an exception.

Here's a quick code sample to give an example :

XAML :

<DataGrid x:Name="dgTest" AutoGenerateColumns="False" CanUserAddRows="False">
    <DataGrid.Columns>
        <DataGridTextColumn Header="A" Binding="{Binding A}" />
        <DataGridTextColumn Header="B" Binding="{Binding B}" />
        <DataGridTextColumn Header="C" Binding="{Binding C}" />
    </DataGrid.Columns>
</DataGrid>

Code-Behind :

var test = new List<ClassA>();
test.Add(new ClassB() { A = "A", B = "B" });
test.Add(new ClassC() { A = "A", C = "C" });
dgTest.ItemsSource = test;

where the classes are defined as

public class ClassA
{
    public string A { get; set; }
}

public class ClassB : ClassA
{
    public string B { get; set; }
}

public class ClassC : ClassA
{
    public string C { get; set; }
}

Output :

enter image description here

It also works the exact same way if I write the binding in code-behind instead of in XAML :

colB.Binding = new Binding("B")

Upvotes: 2

Related Questions