Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Menu problem in AvalonStudio and Core2D #564

Closed
grokys opened this issue Jun 16, 2016 · 4 comments
Closed

Menu problem in AvalonStudio and Core2D #564

grokys opened this issue Jun 16, 2016 · 4 comments

Comments

@grokys
Copy link
Member

grokys commented Jun 16, 2016

cc: @danwalmsley @wieslawsoltes

There is a menu problem in AvalonStudio and Core2D where menu items are created dynamically from Items. The XAML in the case of Core2D currently looks like this:

            <MenuItem.DataTemplates>
                <DataTemplate DataType="Project:XContainer">
                    <MenuItem Header="{Binding Name}" Command="{Static Editor:Commands.ApplyTemplateCommand}" CommandParameter="{Binding}">
                        <MenuItem.Icon>
                            <CheckBox Name="icon" Classes="menu">
                                <i:Interaction.Behaviors>
                                    <behaviors:BindTagToVisualRootDataContextBehavior/>
                                </i:Interaction.Behaviors>
                                <CheckBox.IsChecked>
                                    <MultiBinding Mode="OneWay" Converter="{Static converters:ObjectEqualityMultiConverter.Instance}">
                                        <Binding ElementName="icon" Path="DataContext" Converter="{Static converters:ObjectToObjectConverter.Instance}"/>
                                        <Binding ElementName="icon" Path="Tag.Project.CurrentContainer.Template" Converter="{Static converters:ObjectToObjectConverter.Instance}"/>
                                    </MultiBinding>
                                </CheckBox.IsChecked>
                            </CheckBox>
                        </MenuItem.Icon>
                    </MenuItem>
                </DataTemplate>
            </MenuItem.DataTemplates>

This is causing a problem because the data template is creating a MenuItem which gets placed inside the MenuItem created by Avalonia! If you think about it, this makes sense - when you write a DataTemplate for a list box you don't have a <ListBoxItem> at the root - the DataTemplate describes the contents. This is the same in WPF - you have to use ItemContainerStyle to set the MenuItem.Header (http://weblogs.asp.net/okloeten/5149692 describes our exact same problem in WPF).

We don't have ItemContainerStyle, but our styling system is more powerful than WPF's so we shouldn't need it. However, the following wasn't working:

              <Style Selector="MenuItem">
                <Setter Property="Header" Value="{Binding Name}"/>
              </Style>

But I've fixed that, so the basic case should work.

The next problem is that Core2D wants to set the MenuItem.Icon property too. Putting the <CheckBox> as the style value failed however, as the same CheckBox was getting assigned to each MenuItem.

The solution for this was to add a <Template> which can be placed inside a style value. So the equivalent of the original Core2D DataTemplate above is:

              <Style Selector="MenuItem">
                <Setter Property="Header" Value="{Binding Name}"/>
                <Setter Property="Icon">
                  <Template>
                    <CheckBox Name="icon" Classes="menu">
                      <i:Interaction.Behaviors>
                        <behaviors:BindTagToVisualRootDataContextBehavior/>
                      </i:Interaction.Behaviors>
                      <CheckBox.IsChecked>
                        <MultiBinding Mode="OneWay" Converter="{Static converters:ObjectEqualityMultiConverter.Instance}">
                          <Binding ElementName="icon" Path="DataContext" Converter="{Static converters:ObjectToObjectConverter.Instance}"/>
                          <Binding ElementName="icon" Path="Tag.Project.CurrentContainer.Template" Converter="{Static converters:ObjectToObjectConverter.Instance}"/>
                        </MultiBinding>
                      </CheckBox.IsChecked>
                    </CheckBox>
                  </Template>
                </Setter>
              </Style>

cc: @SuperJMN

This is also implemented, but it seems we're hitting an OmniXaml bug. I will try to reproduce in a short sample and add an OmniXaml issue. I will close this issue when everything is working.

@grokys
Copy link
Member Author

grokys commented Jun 17, 2016

Ok, this wasn't an OmniXaml problem, sorry @SuperJMN ;)

It should now be fixed in master. The full XAML for Core2D's Template menu should be:

        <MenuItem Header="Te_mplate" Items="{Binding Project.Templates}">
            <MenuItem.Styles>
              <Style Selector="MenuItem">
                <Setter Property="Header" Value="{Binding Name}"/>
                <Setter Property="Icon">
                  <Template>
                    <CheckBox Name="icon" Classes="menu">
                      <i:Interaction.Behaviors>
                        <behaviors:BindTagToVisualRootDataContextBehavior/>
                      </i:Interaction.Behaviors>
                      <CheckBox.IsChecked>
                        <MultiBinding Mode="OneWay" Converter="{Static converters:ObjectEqualityMultiConverter.Instance}">
                          <Binding ElementName="icon" Path="DataContext" Converter="{Static converters:ObjectToObjectConverter.Instance}"/>
                          <Binding ElementName="icon" Path="Tag.Project.CurrentContainer.Template" Converter="{Static converters:ObjectToObjectConverter.Instance}"/>
                        </MultiBinding>
                      </CheckBox.IsChecked>
                    </CheckBox>
                  </Template>
                </Setter>
              </Style>
            </MenuItem.Styles>
        </MenuItem>

@grokys grokys closed this as completed Jun 17, 2016
@SuperJMN
Copy link
Contributor

;)

@wieslawsoltes
Copy link
Contributor

wieslawsoltes commented Jun 17, 2016

Thanks @grokys this works very nice.

Also added missing command bindings:

<Setter Property="Command" Value="{Static Editor:Commands.ApplyTemplateCommand}"/>
<Setter Property="CommandParameter" Value="{Binding}"/>

@wieslawsoltes
Copy link
Contributor

@grokys I have issue with command using your solution, in some cases commands are executed twice, first with valid CommandParameter and second time with different invalid object. There are two cases when it causes stack overflow.

This are my changes in Core2D: wieslawsoltes/Core2D@5a71dd5

This two cause StackOverflowException:
https://github.com/Core2D/Core2D/blob/5a71dd581b73e18c7d27f9b7ea3e46462b2ec792/src/Core2D.Avalonia/Views/EditorControl.xaml#L168
https://github.com/Core2D/Core2D/blob/5a71dd581b73e18c7d27f9b7ea3e46462b2ec792/src/Core2D.Avalonia/Controls/Project/ProjectControl.xaml#L84

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants