Question

I'm developping a WPF app and ran into a problem about property binding. I designed a main menu for my app and I would like to have a random left margin value for each menu entries (one menu item is a button). I also redefine Button template. So far, here is my XAML code :

The MainMenuView.xaml :

<UserControl x:Class="OfficeTourismeBrantome.Views.MainMenuView"
         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="800" d:DesignWidth="300">
<UserControl.Resources>
    <Style x:Key="MenuItemButtonStyle" TargetType="Button">
        <Setter Property="FontSize" Value="35" />
        <Setter Property="FontFamily" Value="Segoe" />
        <Setter Property="Foreground" Value="#FFEBEDEA" />           
        <Setter Property="HorizontalContentAlignment" Value="Right" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type Button}">                        
                        <Canvas HorizontalAlignment="Stretch" Background="Aqua">
                        <ContentPresenter Canvas.Left="{Binding MenuLayout.MenuItemLeftMargin}" HorizontalAlignment="Center"                                                  
                                      VerticalAlignment="Center"/>
                        </Canvas>                            
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</UserControl.Resources>
<ItemsControl Name="menuButtonContainer" ItemsSource="{Binding Items}" Margin="{Binding MenuLayout.MenuMargin}">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <StackPanel Orientation="Vertical" />
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>        
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <Button 
                Style="{StaticResource ResourceKey=MenuItemButtonStyle}" 
                Margin="{Binding ElementName=menuButtonContainer, 
                                    Path=DataContext.MenuLayout.MenuItemMargin}"                    
                Height="{Binding ElementName=menuButtonContainer, 
                                    Path=DataContext.MenuLayout.MenuItemSize.Height}"
                Content="{Binding Text}"
                Command="{Binding ElementName=menuButtonContainer, 
                                    Path=DataContext.ChangeThemeCommand}"
                CommandParameter="{Binding Id}"
                />
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

As you can see, I got 2 differents levels here :

  1. The first level, which DataContext is UserControl one (MainMenuViewModel)
  2. The second one, which DataContext is inside the ItemControl that list MenuItems

On this code, only 1 thing is not working : The Canvas ContentPresenter Canvas.Left property binding :

<ContentPresenter Canvas.Left="{Binding MenuLayout.MenuItemLeftMargin}" HorizontalAlignment="Center"                                                  
                                  VerticalAlignment="Center"/>

My questions :

  1. Why the above binding not working? In step-by-step, I see the random value correctly assigned. There is no change on runtime so far, so I didn't implement INotifyPropertyChanged (actually all the others bindings work as expected).
  2. I realized that some of the properties in ItemTemplate (such as Height and Margin) should go in Style definition. When I try it, it doesn't bind...

I do it this way :

<UserControl.Resources>
        <Style x:Key="MenuItemButtonStyle" TargetType="Button">    
<Setter Property="Height" Value="{Binding MenuLayout.MenuItemSize.Height}" />
</Style>
</UserControl.Resources>

What should I put to make this binding working?

THanks for your answers !

Here is the ViewsModels :

MainMenuViewModel reduced to utile stuff (exposes MenuLayout property):

class MainMenuViewModel : LanguageChangedNotificationViewModelBase
{      

    private MenuLayout _menuLayout;

    /// <summary>
    /// Menu items list property
    /// </summary>
    public ObservableCollection<MenuItem> Items
    {
        get { return _items; }
        set { _items = value; }
    }

    public MenuLayout MenuLayout
    {
        get
        {
            return _menuLayout;
        }
        set
        {
            _menuLayout = value;
        }
    }

    /// <summary>
    /// Constructor (that calls base constructor)
    /// </summary>
    public MainMenuViewModel() : base()
    {
        // New menu items list instance
        Items = new ObservableCollection<MenuItem>();

        // Menu layout var needed for display
        MenuLayout = new MenuLayout();

    }

} }

And MenuLayout class :

namespace OfficeTourismeBrantome.Models

{ class MenuLayout { private Thickness _menuMargin;

    private Thickness _menuItemMargin;

    private Size _menuItemSize;

    public Thickness MenuItemMargin
    {
        get {
            _menuItemMargin.Left = GetRandomNumber();
            return _menuItemMargin; 
        }
        set { _menuItemMargin = value; }
    }


    public Thickness MenuMargin
    {
        get { return _menuMargin; }
        set { _menuMargin = value; }
    }

    public Size MenuItemSize
    {
        get { return _menuItemSize; }
        set { _menuItemSize = value; }
    }

    public double MenuItemLeftMargin
    {
        get
        {
            return GetRandomNumber();
        }
    }

    public MenuLayout()
    {
        MenuItemMargin = new Thickness(Properties.Settings.Default.mainMenuItemMarginLeft, Properties.Settings.Default.mainMenuItemMarginTop, Properties.Settings.Default.mainMenuItemMarginRight, Properties.Settings.Default.mainMenuItemMarginBottom);
        MenuMargin = new Thickness(Properties.Settings.Default.mainMenuMarginLeft, Properties.Settings.Default.mainMenuMarginTop, Properties.Settings.Default.mainMenuMarginRight, Properties.Settings.Default.mainMenuMarginBottom);
        MenuItemSize = new Size(100, 50);
    }

    private double GetRandomNumber()
    {
        double minimum = 0;
        double maximum = Properties.Settings.Default.mainMenuItemMarginLeft;
        Random random = new Random();
        return random.NextDouble(); //* (maximum - minimum) + minimum;
    }

}

}

No correct solution

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top