Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WPF Casting in Binding Path

This is a similar problem to WPF Binding : Casting in binding path, where I need to cast an object in a XAML binding statement. But I can't seem to understand how to craft the binding in my particular case.

The answer to that question references PropertyPath XAML Syntax, and the relevant section is (I believe) Single Property, Attached or Otherwise Type-Qualified.

In my case, in my main View Model I have a dictionary that maps strings to objects that implement a base interface:

Dictionary<string, IFlintStone> FlintStones { get; set;}

public interface IFlintStone { Walk, Talk etc}
public class FlintStone : IFlintStone { .. }

However I also have these additional objects and interfaces which subclass the base object:

public interface IFred : IFlintStone { Eat, Drink, Yell etc }
public interface IWilma : IFlintStone { Wash, Clean, Cook etc }

public class Fred : FlintStone, IFred {..}
public class Wilma : FlintStone, IWilma {..}

And eventually I populate my dictionary like:

FlintStones["Fred"] = new Fred();
FlintStones["Wilma"] = new Wilma();

Now, in my XAML I have a user control for rendering a Fred object, and another one for rendering a Wilma object. I can set the data context of these user controls doing something like:

<FredControl DataContext="{Binding Path=FlintStones[Fred]}" />
<WilmaControl DataContext="{Binding Path=FlintStones[Wilma]}" />

However my understanding is that this will only expose the IFlintStone components of those objects to their respective user controls. But I want to expose IFred to the <FredControl> and IWilma to the <WilmaControl>

Is this possible and what would the binding syntax be in this case?

Using ideas from the links I referenced above, I have tried things like:

<FredControl DataContext="{Binding path=(myns:Fred.FlintStones[Fred])}" />

and

<FredControl DataContext="{Binding path=(myns:Fred).FlintStones[Fred]}" />

(Where myns is an xaml namespace definition pointing to the Fred object in the assembly.)

But the program either crashes and burns on start, or it complains that it can't find Fred as a property of the current data context.

like image 336
Peter M Avatar asked Oct 07 '14 20:10

Peter M


1 Answers

Here is a working version of my interpretation of your issue:

MainWindow.xaml

<Window x:Class="WpfApplication22.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfApplication22"
        Title="MainWindow" Height="350" Width="525">
    <StackPanel>
        <TextBlock Text="{Binding Path=FlintStones[Fred].FlintStone}" />
        <TextBlock Text="{Binding Path=FlintStones[Fred].(local:Fred.Yell)}" />
        <local:FredControl DataContext="{Binding Path=FlintStones[Fred]}" />
        <TextBlock />
        <TextBlock Text="{Binding Path=FlintStones[Wilma].FlintStone}" />
        <TextBlock Text="{Binding Path=FlintStones[Wilma].(local:Wilma.Clean)}" />
        <local:WilmaControl DataContext="{Binding Path=FlintStones[Wilma]}" />
    </StackPanel>
</Window>

MainWindow.xaml.cs

using System.Windows;
using System.Collections.Generic;

namespace WpfApplication22
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public Dictionary<string, IFlintStone> FlintStones { get; set; }

        public MainWindow()
        {
            InitializeComponent();

            FlintStones = new Dictionary<string, IFlintStone>();
            FlintStones["Fred"] = new Fred();
            FlintStones["Wilma"] = new Wilma();

            this.DataContext = this;
        }
    }

    public interface IFlintStone
    {
        string FlintStone { get; set; }
    }
    public interface IFred : IFlintStone
    {
        string Yell { get; set; }
    }
    public interface IWilma : IFlintStone
    {
        string Clean { get; set; }
    }

    public class Fred : IFred
    {
        public string FlintStone { get; set; }
        public string Yell { get; set; }

        public Fred()
        {
            FlintStone = "Fred Flintstone";
            Yell = "Yabba Dabba Doo";
        }
    }

    public class Wilma : IWilma
    {
        public string FlintStone { get; set; }
        public string Clean { get; set; }

        public Wilma()
        {
            FlintStone = "Wilma Flintstone";
            Clean = "Mammoth Dish Washer";
        }
    }
}

FredControl.xaml

<UserControl x:Class="WpfApplication22.FredControl"
             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" 
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <StackPanel Background="Beige">
        <TextBlock Text="{Binding FlintStone}" />
        <TextBlock Text="{Binding Yell}" />
    </StackPanel>
</UserControl>

WilmaControl.xaml

<UserControl x:Class="WpfApplication22.WilmaControl"
             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" 
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <StackPanel Background="AntiqueWhite">
        <TextBlock Text="{Binding FlintStone}" />
        <TextBlock Text="{Binding Clean}" />
    </StackPanel>
</UserControl>

FredControl.xaml.cs and WilmaControl.xaml.cs are unmodified (just InitializeComponent(); in the constructors).

And a screenshot:

enter image description here

like image 121
J.H. Avatar answered Oct 16 '22 20:10

J.H.