Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Assigning an event or command to a DataTemplate in ResourceDictionary

Tags:

c#

wpf

xaml

I have the following class:

public class Day
{
    public int Date { get; set; }
    public String DayName { get; set; }

    public Day()
    {

    }

    public Day(int date, string dayName)
    {
        Date = date;
        DayName = dayName;

        CommandManager.RegisterClassCommandBinding(typeof(Day), new CommandBinding(DayClick, new ExecutedRoutedEventHandler(OnExecutedDayClick), 
            new CanExecuteRoutedEventHandler(OnCanExecuteDayClick)));
    }

    public static readonly RoutedCommand DayClick = new RoutedCommand("DayClick", typeof(Day));

    private static void OnCanExecuteDayClick(object sender, CanExecuteRoutedEventArgs e)
    {
        ((Day)sender).OnCanExecuteDayClick(e);
    }

    private static void OnExecutedDayClick(object sender, ExecutedRoutedEventArgs e)
    {
        ((Day)sender).OnExecutedDayClick(e);
    }

    protected virtual void OnCanExecuteDayClick(CanExecuteRoutedEventArgs e)
    {
        e.CanExecute = true;
        e.Handled = false;
    }

    protected virtual void OnExecutedDayClick(ExecutedRoutedEventArgs e)
    {
        string content = String.Format("Day {0}, which is {1}, was clicked.", Date.ToString(), DayName);
        MessageBox.Show(content);
        e.Handled = true;
    }
}

I am using the following DataTemplate (that is in a ResourceDictionary) to render it:

<DataTemplate DataType="{x:Type local:Day}">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <Rectangle Grid.ColumnSpan="2" x:Name="rectHasEntry" Fill="WhiteSmoke"/>
        <TextBlock Grid.Column="0" x:Name="textBlockDayName" Text="{Binding DayName}" 
                               FontFamily="Junction" FontSize="11" Background="Transparent" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,2,0,0"/>
        <TextBlock Grid.Column="1" x:Name="textBlockDate" Text="{Binding Date}" 
                               FontFamily="Junction" FontSize="11" Background="Transparent" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,2,0,0"/>
        <Rectangle Grid.ColumnSpan="2" x:Name="rectMouseOver" Fill="#A2C0DA" Opacity="0"
                               Style="{StaticResource DayRectangleMouseOverStyle}">
        </Rectangle>
    </Grid>
</DataTemplate>

No problems so far, I can get it on screen.

What I want to be able to do is assign a Command, or use an event, so that when the user clicks on the Day it will notify the parent of the Day object that it has been clicked.

I've tried the following:

<Rectangle.CommandBindings>
    <CommandBinding Command="{x:Static local:Day.NextDay}"
                             Executed="{x:Static local:Day.OnExecutedDayClick}"
                             CanExecute="{x:Static local:Day.OnCanExecuteDayClick}"/>
</Rectangle.CommandBindings>

to try and bind the commands that are in the Day class but it didn't work. I got an error stating:

'ResourceDictionary' root element requires a x:Class attribute to support event handlers in the XAML file. Either remove the event handler for the Executed event, or add a x:Class attribute to the root element.

Which I think means that there is no code-behind file for a ResourceDictionary, or something to that effect.

In any event, I'm not sure if I should be using Commands here, or somehow tying events to the Rectangle in question, or if this is even possible. I've seen various places where it sure looks like it's possible, I'm just unable to translate what I'm seeing into something that actually works, hence this post.

Thanks in advance.

like image 864
Scott Avatar asked Mar 26 '10 21:03

Scott


1 Answers

You cann't declare CommandBinding here, in this case you can assign the command here in DataTemplate and declare CommandBinding in your main Window or Page.

Edit:

In this way you can use Commands with your custom control. Create a custom control and Declare Commands and Command Bindings also inside the control itself as in this Sample.

MyCustomControl.cs

    static MyCustomControl()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(MyCustomControl), new FrameworkPropertyMetadata(typeof(MyCustomControl)));
        InitializeCommands();
    }
    
    private static RoutedCommand _myCommand;

    public static RoutedCommand MyCommand
    {
        get
        {
            return _myCommand;
        }
    }

    private static void InitializeCommands()
    {
        _myCommand = new RoutedCommand("MyCommand", typeof(MyCustomControl));
        CommandManager.RegisterClassCommandBinding(typeof(MyCustomControl),
                                new CommandBinding(_myCommand , OnMyCommandExecute));
    }

    private static void OnMyCommandExecute(object sender, ExecutedRoutedEventArgs e)
    {
        MyCustomControl control = sender as MyCustomControl;
        if (control != null)
        {
            //logic for this command
        }
    }
    

and in your generic.xaml write this style and assign commands like this:

generic.xaml

<Style TargetType="{x:Type local:MyCustomControl}">
    <Setter Property="HorizontalAlignment" Value="Center"/>
    <Setter Property="VerticalAlignment" Value="Center"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type local:MyCustomControl}">
                <Grid>
                    <RepeatButton Command="{x:Static local:MyCustomControl.MyCommand}"  >Click</RepeatButton>
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>
like image 130
viky Avatar answered Sep 24 '22 10:09

viky