Search code examples
c#wpfxamlbindingflipper

Problem with binding to viewmodel inside of Materialdesign Flipper BackContent and ItemsControl DataTemplate


I have problem with Binding Text to Viewmodels property from DataTemplate of ItemsControl. I have problem Inside of Flippers BackContent but In FrontContent of flipper my Binding works correctly. Code where I have trouble:

<TextBlock FontSize="22" Text="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}},Path=DataContext.VMProperty}"/>

My full xaml is:

<Window x:Class="flipper.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:flipper"
    xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
    mc:Ignorable="d"
    Title="MainWindow" Height="450" Width="800">
<Grid>
    <ItemsControl ItemsSource="{Binding Items}" RenderTransformOrigin="0.141,0.181">
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <materialDesign:Flipper Style="{StaticResource MaterialDesignCardFlipper}" x:Name="FlipperCollection">
                    <materialDesign:Flipper.FrontContent>
                        <Border BorderThickness="0">
                            <Border.Background>
                                <LinearGradientBrush>
                                    <GradientStop Color="#09203F" Offset="1"/>
                                    <GradientStop Color="#3F4C6B" Offset="0"/>
                                </LinearGradientBrush>
                            </Border.Background>
                            <StackPanel Grid.Row="1"
                                        HorizontalAlignment="Center"
                                        VerticalAlignment="Center">
                                <TextBlock FontSize="22" Text="{Binding Name}" HorizontalAlignment="Center" Foreground="White"/>
                                <TextBlock FontSize="22" Text="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}},Path=DataContext.VMProperty}"/>
                                <Button Style="{StaticResource MaterialDesignFlatButton}"
                                        Command="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}},Path=DataContext.cmdEditCompany}"
                                        Margin="0" Padding="0 0 5 0" VerticalAlignment="Center"
                                        HorizontalAlignment="Center"
                                        MinWidth="70"
                                        Foreground="#E5F0FF">
                                    <materialDesign:PackIcon Kind="Edit"
                                                             Width="20"
                                                             Height="20"/>
                                </Button>
                            </StackPanel>
                        </Border>
                    </materialDesign:Flipper.FrontContent>
                    <materialDesign:Flipper.BackContent>
                        <StackPanel Background="#E509203F">
                            <TextBlock FontSize="22" Text="{Binding TestData}" Foreground="White"/>
                            <TextBlock FontSize="22" Text="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}},Path=DataContext.VMProperty}"/>

                            <Button Style="{StaticResource MaterialDesignFlatButton}"
                                        Command="{x:Static materialDesign:Flipper.FlipCommand}"
                                        Margin="0" Padding="0 0 5 0" VerticalAlignment="Center"
                                        HorizontalAlignment="Center"
                                        MinWidth="70"
                                        Foreground="#E5F0FF">
                                    <materialDesign:PackIcon Kind="ArrowLeft"
                                                             Width="20"
                                                             Height="20"/>
                                </Button>
                            </StackPanel>
                    </materialDesign:Flipper.BackContent>
                </materialDesign:Flipper>
            </DataTemplate>
        </ItemsControl.ItemTemplate>

        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <WrapPanel/>
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
    </ItemsControl>
</Grid>

Model and ViewModel is :

class Data
{
    public string Name { get; set; }
    public string TestData { get; set; }
}
class MainViewModel:BindableBase
{

    private string _name;
    public string Name
    {
        get { return _name; }
        set { SetValue(ref _name, value); }
    }

    private string _TestData;
    public string TestData
    {
        get { return _TestData; }
        set { SetValue(ref _TestData, value); }
    }

    private List<Data> _Items;
    public List<Data> Items
    {
        get { return _Items; }
        set { SetValue(ref _Items, value); }
    }

    public DelegateCommand cmdEditCompany { get; set; }

    public MainViewModel()
    {
        onload();
        cmdEditCompany = new DelegateCommand(EditCompany);
    }

    private string _VMProperty;
    public string VMProperty
    {
        get { return _VMProperty; }
        set { SetValue(ref _VMProperty, value); }
    }


    private void EditCompany()
    {
        Flipper.FlipCommand.Execute(this, null);
    }


    private void onload()
    {
        Items = new List<Data>();
        Items.Add(new Data(){Name = "Name1",TestData = "TestData1"});
        Items.Add(new Data(){Name = "Name2",TestData = "TestData2"});
        Items.Add(new Data(){Name = "Name3",TestData = "TestData3"});
        Items.Add(new Data(){Name = "Name4",TestData = "TestData4"});
        Items.Add(new Data(){Name = "Name5",TestData = "TestData5"});
        VMProperty = "VM Test value";
    }


}

How can I solve the problem?


Solution

  • Old question, but I hope this helps someone.

    This is because the Flipper.BackContent doesn’t belong to the visual or logical tree of the materialDesign:Flipper. The solution to this problem is to use the Freezable class. Freezable objects can inherit DataContext even if they are not in the visual or logical tree.

    public class BindingProxy : Freezable
    {
        protected override Freezable CreateInstanceCore() => new BindingProxy();
    
        public object Data
        {
            get => GetValue(DataProperty);
            set => SetValue(DataProperty, value);
        }
    
        public static readonly DependencyProperty DataProperty =
            DependencyProperty.Register("Data", typeof(object), typeof(BindingProxy), new UIPropertyMetadata(null));
    }
    

    Add to Window.Resources:

    <Window.Resources>
        <local:BindingProxy x:Key="proxy" Data="{Binding}" />
    </Window.Resources>
    

    Fix:

    <TextBlock FontSize="22" Text="{Binding Data.VMProperty, Source={StaticResource proxy}}"/>
    

    Note that the binding path has been prefixed with “Data” rather than "DataContext", since the path is now relative to the BindingProxy object.