Laden...

Wie binde ich ein Command an einen Button

Erstellt von Kriz vor 6 Jahren Letzter Beitrag vor 6 Jahren 2.080 Views
K
Kriz Themenstarter:in
141 Beiträge seit 2017
vor 6 Jahren
Wie binde ich ein Command an einen Button

Hi zusammen,

folgende Herausforderung: Ich habe in User Control die quasi nur ein Button mit anderer grafischer Darstellung ist, nun möchte ich an die Command-Property binden, steh allerdings auf dem Schlauch wie ich es am geschicktesten anstelle...
xaml:

<UserControl x:Class="Shifter.Common.ShifterButton"
             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" 
             xmlns:common="clr-namespace:Shifter.Common"
             mc:Ignorable="d" 
             d:DesignHeight="40" d:DesignWidth="40"
             DataContext="{Binding RelativeSource={RelativeSource Self}}">
    <UserControl.Resources>
        <common:InverseBooleanConverter x:Key="InverseBooleanConverter"/>
        <Style x:Key="FocusVisual">
            <Setter Property="Control.Template">
                <Setter.Value>
                    <ControlTemplate>
                        <Rectangle Margin="2" SnapsToDevicePixels="true" Stroke="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}" StrokeThickness="1" StrokeDashArray="1 2"/>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
        <SolidColorBrush x:Key="Button.Static.Background" Color="#FFC4F0FF"/>
        <SolidColorBrush x:Key="Button.Static.Border" Color="#FFC5C5C5"/>
        <SolidColorBrush x:Key="Button.MouseOver.Background" Color="#FF7AA5B3"/>
        <SolidColorBrush x:Key="Button.MouseOver.Border" Color="#FF3C7FB1"/>
        <SolidColorBrush x:Key="Button.Pressed.Background" Color="#FFC4E5F6"/>
        <SolidColorBrush x:Key="Button.Pressed.Border" Color="#FF2C628B"/>
        <SolidColorBrush x:Key="Button.Disabled.Background" Color="#FFF4F4F4"/>
        <SolidColorBrush x:Key="Button.Disabled.Border" Color="#FFADB2B5"/>
        <SolidColorBrush x:Key="Button.Disabled.Foreground" Color="#FF838383"/>
    </UserControl.Resources>
    <Button Name="button" 
            Click="button_Click" 
            Width="30" 
            Height="30"
            Cursor="Hand"
            Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Common:ShifterButton}}, Path=ClickHereCommand}">>
        <Button.Template>
            <ControlTemplate TargetType="{x:Type Button}">
                <Border Name="buttonBorder" Width="30" Height="30">                    
                    <StackPanel>
                        <Image Name="img" Source="{Binding NormalImage}" Stretch="Fill"/>
                    </StackPanel>
                </Border>
                <ControlTemplate.Triggers>
                    <Trigger Property="IsDefaulted" Value="true">
                        <Setter Property="BorderBrush" TargetName="buttonBorder" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}"/>
                    </Trigger>
                    <Trigger Property="IsMouseOver" Value="true">
                        <Setter TargetName="buttonBorder" Property="Effect">
                            <Setter.Value>
                                <DropShadowEffect ShadowDepth="-1"/>
                            </Setter.Value>
                        </Setter>                        
                    </Trigger>
                    <Trigger Property="IsPressed" Value="true">
                        
                    </Trigger>
                    <Trigger Property="IsEnabled" Value="false">
                        <Setter TargetName="buttonBorder" Property="Effect">
                            <Setter.Value>
                                <BlurEffect Radius="5"/>
                            </Setter.Value>
                        </Setter>
                        <Setter Property="Background" TargetName="buttonBorder" Value="{StaticResource Button.Disabled.Background}"/>
                        <Setter Property="BorderBrush" TargetName="buttonBorder" Value="{StaticResource Button.Disabled.Border}"/>
                        
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Button.Template>
    </Button>
</UserControl>

Code Behind:

public partial class ShifterButton : UserControl
    {
        public event RoutedEventHandler Click;

        public ShifterButton()
        {
            InitializeComponent();
        }

         public ICommand ClickHereCommand
        {
            get { return (ICommand)GetValue(ClickHereCommandProperty); }
            set { SetValue(ClickHereCommandProperty, value); }
        }
        public static readonly DependencyProperty ClickHereCommandProperty =
            DependencyProperty.Register("ClickHereCommand", typeof(ICommand), typeof(ShifterButton), new UIPropertyMetadata(null));


        public ImageSource NormalImage
        {
            get { return (ImageSource)GetValue(NormalImageProperty); }
            set { SetValue(NormalImageProperty, value); }
        }
        public static readonly DependencyProperty NormalImageProperty = DependencyProperty.Register("NormalImage", typeof(ImageSource), typeof(ShifterButton), new UIPropertyMetadata(null));

        private void button_Click(object sender, RoutedEventArgs e)
        {
            if (Click != null)
            {
                Click(this, e);
            }
        }


    }

Zielfenster xaml:

<common:ShifterButton ClickHereCommand="{Binding AddCommand}" x:Name="btnAdd" NormalImage="pack://application:,,,/Art/add.png" Height="30" Width="30" Margin="230,0,0,165" />

Zielfenster ViewModel:

public ICommand AddCommand { get; set; }
AddCommand = new RelayCommand(o => AddEntry());

Im Fehlerfenster sagt er mir, dass das UserControl keine Property "AddCommand" hat, was ja auch richtig und logisch ist, da sie ja in meinem ViewModel des Zielfensters ist. Wie stell ich es also an, dass das Binding an der richtigen Stelle sucht?

Wie ich es auch anstelle, ich bekomme Fehlermeldungen... 8o

709 Beiträge seit 2008
vor 6 Jahren

Hi!
Wenn das nur ein Button mit anderem Aussehen ist, könntest du das auch als Style definieren.
Dann hast du nach außen einen Button mit allem, was dazu gehört.

K
Kriz Themenstarter:in
141 Beiträge seit 2017
vor 6 Jahren

Mit Styles funktioniert das wunderbar, wollte es aber mal als UserControl versuchen da ich es fur später vllt mal gebrauchen kann, also das Wissen wie es geht...

709 Beiträge seit 2008
vor 6 Jahren

Welche Fehlermeldungen bekommst du denn?

Ich habe deinen Code eben mal ausprobiert und bei mir wird mein Command wunderbar ausgeführt.
Das einzige, was ich weg gelassen habe, ist die Definition eines Bildes.

709 Beiträge seit 2008
vor 6 Jahren

Oh, ich habe gerade gesehen, dass ich eine einzige Änderung doch gemacht habe:

Ich habe beim Border im ControlTemplate noch folgendes hinzugefügt:

Background="{TemplateBinding Background}"

Und dann im Window den Hintergrund des ShifterButtons gesetzt, damit ich ihn mangels Bildes sehe.
Wenn du die Hintergrundfarbe auf "Transparent" setzt, sollte es klappen.
Sonst klickst du durch deinen Button durch.

T
461 Beiträge seit 2013
vor 6 Jahren

Hallo,

habs nicht getestet und auch den Sinn nicht ganz verstanden was dahinter steckt aber um auf das ViewModel zugreifen zu können und nicht auf das UserControl Eigene, müßte man folgendes noch hinzufügen:


<common:ShifterButton ClickHereCommand="{Binding ElementName=self, Path=AddCommand}" x:Name="btnAdd" NormalImage="pack://application:,,,/Art/add.png" Height="30" Width="30" Margin="230,0,0,165" />

Grüße

Ich habe den Titel mal angepasst, so dass Suchende auch etwas damit anfangen können. EDIT: Ich sollte beim Wort "Shift" im Titel das "f" nicht vergessen... 😄

K
Kriz Themenstarter:in
141 Beiträge seit 2017
vor 6 Jahren

@pinki
Also die Fehlermeldung sieht so aus:

System.Windows.Data Error: 40 : BindingExpression path error: 'AddCommand' property not found on 'object' ''ShifterButton' (Name='btnAdd')'. BindingExpression:Path=AddCommand; DataItem='ShifterButton' (Name='btnAdd'); target element is 'ShifterButton' (Name='btnAdd'); target property is 'ClickHereCommand' (type 'ICommand')

Ich würde jetzt aus dieser Fehlermeldung interpretieren, dass das Objekt "bntAdd" vom Typ "ShifterButton" keine Property "AddCommand" hat. Was ja, wie gesagt, klar ist, da diese Property in meinem ViewModel des eigentlichen Fensters ist, wo der Button benutzt werden soll...
Hast Du denn, als Du es ausprobiert hast, auch mit ViewModel gearbeitet?

@ThomasE.
Der Sinn dahinter ist, an ein Command eines UserControls binden zu können. Sicher, in dieser Situation kann ich auch einfach einen Style nehmen, mir gehts aber gerade darum zu verstehen warum es nicht geht, damit ich gewappnet bin, falls ich es mal brauche.
Nachdem ich deinen Tip gefolgt bin, wird mir folgendes angezeigt:

System.Windows.Data Error: 4 : Cannot find source for binding with reference 'ElementName=self'. BindingExpression:Path=AddCommand; DataItem=null; target element is 'ShifterButton' (Name='btnAdd'); target property is 'ClickHereCommand' (type 'ICommand')
709 Beiträge seit 2008
vor 6 Jahren

Hi,
mir ist gerade aufgefallen, dass ich noch eine Zeile nicht habe:

DataContext="{Binding RelativeSource={RelativeSource Self}}"

Ich hatte nur den Inhalt des UserControls kopiert.

Edit: Ja, ich habe das auch an eine Eigenschaft eines ViewModels gebunden.

K
Kriz Themenstarter:in
141 Beiträge seit 2017
vor 6 Jahren

@pinki
Perfekt, das war es. Ich bedanke mich recht herzlich!