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

TemplateBinding to ICommand property not work #4546

Open
Meloman19 opened this issue Mar 17, 2021 · 10 comments
Open

TemplateBinding to ICommand property not work #4546

Meloman19 opened this issue Mar 17, 2021 · 10 comments
Labels
area-Binding area-Commanding AppBar, UICommand, MVVM, etc bug Something isn't working product-winui3 WinUI 3 issues team-Markup Issue for the Markup team wpf-vs-winui-mismatch

Comments

@Meloman19
Copy link

Describe the bug
TemplateBinding doesn't work for the ICommand property with Button inside template.

Steps to reproduce the bug

  1. Create CustomControl:
class MyControl : Control
{
    public static readonly DependencyProperty MyCommandProperty =
        DependencyProperty.Register("MyCommand", typeof(System.Windows.Input.ICommand), typeof(MyControl), new PropertyMetadata(null));

    public System.Windows.Input.ICommand MyCommand
    {
        get { return (System.Windows.Input.ICommand)GetValue(MyCommandProperty); }
        set { SetValue(MyCommandProperty, value); }
    }
}
  1. On root MainWindow:
<StackPanel>
    <StackPanel.Resources>
        <Style TargetType="local:MyControl">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="local:MyControl">
                        <Grid>
                            <Button Command="{TemplateBinding MyCommand}"
                                    Content="RUN"/>
                        </Grid>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </StackPanel.Resources>

    <local:MyControl x:Name="MyControl" />
    <TextBlock x:Name="TextBlock" />
</StackPanel>
  1. On code behind MainWindow
public sealed partial class MainWindow : Window
{
    public MainWindow()
    {
        this.InitializeComponent();

        MyControl.MyCommand = new RelayCommand(DO); // Classic RelayCommand
    }

    private void DO(object obj)
    {
        TextBlock.Text = "PRESSED";
    }
}

Expected behavior
After clicking on the button, the text must become "PRESSED". But it's not.
Similar TemplateBindings to other properties work fine.

Workaround
Change
Command="{TemplateBinding MyCommand}"
To
Command="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=MyCommand}"

Version Info

NuGet package version:
[Microsoft.ProjectReunion 0.5.0-prerelease]
[Microsoft.ProjectReunion.Foundation 0.5.0-prerelease]
[Microsoft.ProjectReunion.WinUI 0.5.0-prerelease]

Windows app type:

UWP Win32
Yes
Windows 10 version Saw the problem?
Insider Build (xxxxx)
October 2020 Update (19042) Yes
May 2020 Update (19041)
November 2019 Update (18363) Yes
May 2019 Update (18362)
October 2018 Update (17763)
April 2018 Update (17134)
Fall Creators Update (16299)
Creators Update (15063)
Device form factor Saw the problem?
Desktop Yes
Xbox
Surface Hub
IoT
@ghost ghost added the needs-triage Issue needs to be triaged by the area owners label Mar 17, 2021
@huoyaoyuan
Copy link

Should be also #4414

@StephenLPeters
Copy link
Contributor

@Meloman19 can you try the fix suggested in #4414 and confirm this is the same issue?

@StephenLPeters StephenLPeters added needs-author-feedback Asked author to supply more information. and removed needs-triage Issue needs to be triaged by the area owners labels Mar 18, 2021
@Meloman19
Copy link
Author

@StephenLPeters I tried and nothing changed.
I have no problem with style loading or template loading. Style loaded and Template is setted but TemplateBinding from MyControl.MyCommand to Button.CommandPropertynot worked. However TemplateBinding, for example, to Content is worked.

Example 2:

MyControl.cs
class MyControl : Control
{
   public MyControl()
   {
      DefaultStyleKey = typeof(MyControl);
   }

   public static readonly DependencyProperty MyCommandProperty =
         DependencyProperty.Register("MyCommand", typeof(System.Windows.Input.ICommand), typeof(MyControl), new PropertyMetadata(null));

   public System.Windows.Input.ICommand MyCommand
   {
      get { return (System.Windows.Input.ICommand)GetValue(MyCommandProperty); }
      set { SetValue(MyCommandProperty, value); }
   }

   public static readonly DependencyProperty MyContentProperty =
         DependencyProperty.Register("MyContent", typeof(object), typeof(MyControl), new PropertyMetadata(null));

   public object MyContent
   {
      get { return GetValue(MyContentProperty); }
      set { SetValue(MyContentProperty, value); }
   }
}
MainWindow.xaml
<StackPanel>
    <StackPanel.Resources>
        <Style x:Key="MyStyle"
               TargetType="local:MyControl">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="local:MyControl">
                        <Grid>
                            <Button Command="{TemplateBinding MyCommand}"
                                    Content="{TemplateBinding MyContent}"
                                    Click="Button_Click"/>
                        </Grid>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </StackPanel.Resources>

    <local:MyControl x:Name="MyControl"
                     Style="{StaticResource MyStyle}" />
</StackPanel>
MainWindow.cs
public sealed partial class MainWindow : Window
{
    public MainWindow()
    {
        this.InitializeComponent();

        MyControl.MyCommand = new RelayCommand(DO);
        MyControl.MyContent = "RUN";
    }

    private void DO(object obj)
    {
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        var button = sender as Button;

        bool hasCommand = button.Command != null;
        bool hasContent = button.Content != null;
    }
}

I see Button from Template and see "RUN" as content. If clicked on Button_Click I got hasCommand = false and hasContent = true.

@ghost ghost added needs-triage Issue needs to be triaged by the area owners and removed needs-author-feedback Asked author to supply more information. labels Mar 19, 2021
@StephenLPeters
Copy link
Contributor

Hmm, how about using {Binding RelativeParent={RelativeParent TemplatedParent} Path=MyCommand}

@StephenLPeters StephenLPeters added needs-author-feedback Asked author to supply more information. and removed needs-triage Issue needs to be triaged by the area owners labels Mar 19, 2021
@Meloman19
Copy link
Author

@StephenLPeters I already wrote about this :) RelativeSource works.

Workaround
Change
Command="{TemplateBinding MyCommand}"
To
Command="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=MyCommand}"

I know this is a low priority bug (if at all it's bug). But this behavior differs from WPF and UWP.

@ghost ghost added needs-triage Issue needs to be triaged by the area owners and removed needs-author-feedback Asked author to supply more information. labels Mar 20, 2021
@StephenLPeters
Copy link
Contributor

Ah, sorry missed that... Hmm, this feels like it should work.... I know that there is a requirement for {TemplateBinding} that the DependencyObject you are using it on be in the visual tree. But that looks to be the case here (especially given that your template bindings to content work). @llongley suggests that a potential reason could be that the ICommand interface has a different namespace in native and managed dlls, maybe this is tripping up template binding. Would need some debugging.

@StephenLPeters StephenLPeters added area-Binding team-Framework product-winui3 WinUI 3 issues needs-triage Issue needs to be triaged by the area owners and removed needs-triage Issue needs to be triaged by the area owners labels Mar 23, 2021
@codendone
Copy link
Contributor

Note: Still repros on the 0.5.5 release. (And, as noted above, this works properly on system UWP XAML.)

@chrisglein chrisglein added bug Something isn't working wpf-vs-winui-mismatch area-Commanding AppBar, UICommand, MVVM, etc and removed needs-triage Issue needs to be triaged by the area owners labels Aug 30, 2021
@Panda-Sharp
Copy link

Just started to play with WinUI, I started with 1.2, and I just hit this issue ... and I'm really surprised to see it here since March 2021!

@andreaslennartz
Copy link

Same issue as in #7003 - still present in 1.2, very annoying bug. Also very surprised to learn that this hasn't been fixed.

@Soap-141
Copy link

Any update on this?

@bpulliam bpulliam added the team-Markup Issue for the Markup team label Aug 22, 2023
@microsoft-github-policy-service microsoft-github-policy-service bot added the needs-triage Issue needs to be triaged by the area owners label Aug 22, 2023
@bpulliam bpulliam removed the needs-triage Issue needs to be triaged by the area owners label Aug 29, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-Binding area-Commanding AppBar, UICommand, MVVM, etc bug Something isn't working product-winui3 WinUI 3 issues team-Markup Issue for the Markup team wpf-vs-winui-mismatch
Projects
None yet
Development

No branches or pull requests

9 participants