MahApps.Metro icon indicating copy to clipboard operation
MahApps.Metro copied to clipboard

DropDownButton, command binding failed on itemssource

Open TheCamel opened this issue 1 year ago • 5 comments

Describe the bug

With the same model, ItemsSource is bind to an observable collection of ViewModelItem

the first items are working, check is ok and command is called

if items are added after, the command is not called

Steps to reproduce

<mah:DropDownButton Margin="5 5 10 5"
								Padding="8"
								Content="{DynamicResource DisplayMode.Title}"
								DisplayMemberPath="Header"
								ItemsSource="{Binding Displays}">
				<mah:DropDownButton.Icon>
					<mah:PathIcon Width="18"
								  Height="18"
								  Margin="6"
								  Data="M9,6H5V10H7V8H9M19,10H17V12H15V14H19M21,16H3V4H21M21,2H3C1.89,2 1,2.89 1,4V16A2,2 0 0,0 3,18H10V20H8V22H16V20H14V18H21A2,2 0 0,0 23,16V4C23,2.89 22.1,2 21,2" />
				</mah:DropDownButton.Icon>
				<mah:DropDownButton.ItemContainerStyle>
					<Style BasedOn="{StaticResource {x:Type MenuItem}}"
						   TargetType="{x:Type MenuItem}">
						<Setter Property="Command"
								Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type mah:DropDownButton}}, Path=DataContext.ChangeDisplayModeCommand}" />
						<Setter Property="CommandParameter"
								Value="{Binding Mode}" />
						<Setter Property="IsCheckable"
								Value="True" />
						<Setter Property="IsChecked"
								Value="{Binding IsSelected}" />
					</Style>
				</mah:DropDownButton.ItemContainerStyle>
</mah:DropDownButton>

then start


Displays.Add(new DisplayModeItem() { Mode = DisplayMode.Pictogramme, IsSelected = true, Header = StringManager.Instance.GetString("DisplayMode.Picto") });
Displays.Add(new DisplayModeItem() { Mode = DisplayMode.Grid, Header = StringManager.Instance.GetString("DisplayMode.Grid") });
Displays.Add(new DisplayModeItem() { Mode = DisplayMode.Platform, Header = StringManager.Instance.GetString("DisplayMode.Platform") });
Display = DisplayMode.Pictogramme;

after another event add some items

plans.ForEach(p=> Displays.Add( new DisplayModeItem() { Header = p.Name, Mode = DisplayMode.Map, Tag = p } ) );

checking these items is not calling the command

but the IsSelected changed and the binding below works

<Setter Property="IsChecked"
								Value="{Binding IsSelected}" />

Environment

MahApps.Metro version: last
Target Framework: .Net Core 8

TheCamel avatar Jul 31 '24 09:07 TheCamel

How is ViewModelItem defined?

timunie avatar Jul 31 '24 11:07 timunie

i don't think it's relevant because the command is in the parent.. ChangeDisplayModeCommand item is like that

` public partial class DisplayModeItem : ObservableObject { public DisplayMode Mode { get; set; }

[ObservableProperty]
public bool isVisible = true;

[ObservableProperty]
public bool isSelected = false;
partial void OnIsSelectedChanged(bool value)
{
	if(value)
	{
		StrongReferenceMessenger.Default.Send(new ChangeDisplayMessage(this));
	}
}

public string Header { get; set; }

public object Tag { get; set; }

} `

TheCamel avatar Jul 31 '24 11:07 TheCamel

btw i found a workaround by sending a message to the parent when the IsSelected change

TheCamel avatar Jul 31 '24 11:07 TheCamel

DisplayMode, Header and Tag are not observable and thus will not invalidate the command. If you use the MVVM Toolkit, you may need to invalidate the partent command when selection is changed. this is by design for performace reasons and not a bug in MahApps

timunie avatar Jul 31 '24 13:07 timunie

There is no need for that , theses properties are not involved in the problem. and there no need to invalidate the command because its allways true.

IsSelected is well updated when I click an item

<Setter Property="Command" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type mah:DropDownButton}}, Path=DataContext.ChangeDisplayModeCommand}" />

the command in the style is not working for added items

TheCamel avatar Jul 31 '24 14:07 TheCamel