0

I have a toolbar that show many Button with Image and TextBlock.

Then, I create a CommandManager to manager all Button's commands. So, I want to implement a factory to assign action by Button's TextBlock.

This is my xaml and Command function, I try to pass all Button's Text, but I don't know how to do.

<StackPanel>
    <StackPanel.Resources>
        <Style TargetType="{x:Type Button}">
            <Setter Property="Command" Value="{Binding ActionCommand}"/>
            <Setter Property="CommandParameter" Value="{Binding Path=Text}"/>
        </Style>
    </StackPanel.Resources>
    <Button>
        <StackPanel>
            <Image Source="/Resources/ToolBar/open.png"/>
            <TextBlock Text="Open"/>
        </StackPanel>
    </Button>
    <Button>
        <StackPanel>
            <Image Source="/Resources/ToolBar/save.png"/>
            <TextBlock Text="Save"/>
        </StackPanel>
    </Button>
</StackPanel>

ActionManager:

public ICommand ActionCommand { get { return new RelayCommand(_onActionCommand); } }

private void _onActionCommand(object parameter)
{
    if (parameter == null)
    {
        return;
    }

    string buttonContent = parameter as string;
    switch (buttonContent)
    {
        case "Open":
            new OpenWindow().ShowDialog();
            break;
        case "Open":
            new Save();
            break;
    }
}
Po-Sen Huang
  • 445
  • 6
  • 24
  • Why hard-code the button text? Why not provide properties for the text values for each command? Even better, why switch on the text at all? Why not just provide a separate `ICommand` implementation for each command? Your question is too broad, as there are many different ways you _could_ approach the problem. If you really wanted, you could even bind `CommandParameter={Binding RelativeSource={x:RelativeSource Self}}` and then in the code-behind find the `TextBlock` child to retrieve the `Text` property. Not that I'd advise that, but given your literal question, that'd work. – Peter Duniho May 19 '17 at 03:32
  • Can I find the `TextBlock`'s `Text` property in xaml by RelativeSource? – Po-Sen Huang May 19 '17 at 03:35
  • No...`RelativeSource` doesn't offer that as an option. You can walk the tree toward ancestors, but not toward descendants. But in code-behind, you can go whichever direction you like. I'm not suggesting you _should_. But you can, if you really insist. – Peter Duniho May 19 '17 at 03:37
  • Thanks, I can do it in code-behind, like you said. But I want to try get children in xaml. – Po-Sen Huang May 19 '17 at 03:42
  • You can't get children in XAML, not like that. There are examples where you could get them by name, but in the XAML you have shown, naming the `TextBlock` elements wouldn't help, because you would need to somehow use a different name for each time you apply the style. You could probably get it to work by making the buttons into a single `DataTemplate`, but that'd require even more re-working of your current data modeling. – Peter Duniho May 19 '17 at 03:44

3 Answers3

1

A Button has no concept of "Text" but you could set the Tag property to a string and pass this one:

<StackPanel>
    <StackPanel.Resources>
        <Style TargetType="{x:Type Button}">
            <Setter Property="Command" Value="{Binding ActionCommand}"/>
            <Setter Property="CommandParameter" Value="{Binding Path=Tag, RelativeSource={RelativeSource Self}}"/>
        </Style>
    </StackPanel.Resources>
    <Button Tag="Open">
        <StackPanel>
            <Image Source="/Resources/ToolBar/open.png"/>
            <TextBlock Text="Open"/>
        </StackPanel>
    </Button>
    <Button Tag="Save">
        <StackPanel>
            <Image Source="/Resources/ToolBar/save.png"/>
            <TextBlock Text="Save"/>
        </StackPanel>
    </Button>
</StackPanel>
mm8
  • 163,881
  • 10
  • 57
  • 88
0

i would have done this way :

<Button Tag="AnyUniqueString">

and bind the command to it

<Setter Property="CommandParameter" Value="{Binding Path=Tag}"/>

so you are not linked to the text button (u can translate it) - but take care that with one command for all, yo will have trouble manage the refresh and can_execute that will enable/disable your buttons. Perhaps not so complicated to bind each button to separate commands...?

I use it like this in my solution CBR

<StackPanel Margin="10,0,10,0" Orientation="Vertical">
                <Button Style="{DynamicResource CbrStandardButton}" Margin="2,10,2,10"
                        Command="{Binding ForwardCommand}" CommandParameter="CatalogNewCommand" >
                    <DockPanel Margin="10">
                        <Image Source="/CBR;component/Resources/Images/32x32/library_new.png" Width="32"></Image>
                        <Label Style="{DynamicResource CbrLabel}"
                               Content="{LocalizationExtension ResModul=CBR, Key=HomeView.LblActionNew, DefaultValue=Start a new library}" />
                    </DockPanel>
                </Button>
                <Button Style="{DynamicResource CbrStandardButton}" Margin="2,10,2,10"
                        Command="{Binding ForwardCommand}" CommandParameter="BookOpenCommand" >
                    <DockPanel Margin="10">
                        <Image Source="/CBR;component/Resources/Images/32x32/book/book_read.png" Width="32"></Image>
                        <Label Style="{DynamicResource CbrLabel}"
                               Content="{LocalizationExtension ResModul=CBR, Key=HomeView.LblActionRead, DefaultValue=Read a book}" />
                    </DockPanel>
                </Button>
                <Button Style="{DynamicResource CbrStandardButton}" Margin="2,10,2,10"
                        Command="{Binding ForwardCommand}" CommandParameter="SysHelpCommand">
                    <DockPanel Margin="10">
                        <Image Source="/CBR;component/Resources/Images/32x32/book_type/book_type_xps.png" Width="32"></Image>
                        <Label Style="{DynamicResource CbrLabel}"
                               Content ="{LocalizationExtension ResModul=CBR, Key=HomeView.LblActionTutorial, DefaultValue=Quick start tutorial}" />
                    </DockPanel>
                </Button>
            </StackPanel>
GCamel
  • 612
  • 4
  • 8
0

you can use this Markup Extension:

https://www.codeproject.com/Articles/456589/Bindable-Converter-Parameter

it allows you to bind command parameter to a xaml property. so you can, for example, put some identifier in the tag field for your button and bind it to the command parameter using the extension. This way you use only one command, only one binding and you get all you need to distinguish buttons in your command handler.

Hope it helps