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
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.
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...
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.
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.
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... 😄
@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')
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.