0

I have a wrap panel that is populated by a number of instances of my custom control, "GameIconControl." My goal is to have them get removed from the wrap panel when the custom control is double clicked.

The wrap panel is bound to an ObservableCollection.

Below is the custom control xaml. I've tried to add the double click command binding, but it doesn't know how to find the command once it's loaded in the wrap panel. As an experiment, when the MainViewModel loads each GameIconControl, I tried setting the DataContext for each to "this," because the MainViewModel is where the command is. No luck.

<Style TargetType="{x:Type assets:GameIconControl}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type assets:GameIconControl}">
                <Border Margin="3"
                        Background="Transparent"
                        BorderBrush="{TemplateBinding BorderBrush}"
                        BorderThickness="{TemplateBinding BorderThickness}">
                    <StackPanel HorizontalAlignment="Center"
                                VerticalAlignment="Center"
                                Orientation="Vertical">

                        <Image Source="{TemplateBinding Icon}" />
                        <ContentPresenter Height="Auto"
                                          Margin="3"
                                          HorizontalAlignment="Center"
                                          ContentSource="GameName" />
                    </StackPanel>
                        <i:Interaction.Triggers>
                            <i:EventTrigger EventName="MouseDoubleClick">
                                <command:EventToCommand Command="{Binding MoveGameIconToGamesList, Mode=OneWay}" />
                            </i:EventTrigger>
                        </i:Interaction.Triggers>
                </Border>

            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

The code behind for the control is pretty plain. Three DPs and constructors:

static GameIconControl()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(GameIconControl), new FrameworkPropertyMetadata(typeof(GameIconControl)));
    }

    public GameIconControl(){}

    public GameIconControl(string name, BitmapImage icon)
    {
        Icon = icon;
        GameName = name;
    }

    public GameIconControl(string name, BitmapImage icon, Game game) {
        GameForControl = game;
        Icon = icon;
        GameName = name;
    }

    public const string IconPropertyName = "Icon";
    public const string GameNamePropertyName = "GameName";
    public const string GamePropertyName = "Game";


    public string GameName
    {
        get { return (string)GetValue(GameNameProperty); }
        set { SetValue(GameNameProperty, value); }
    }

    public static readonly DependencyProperty GameNameProperty =
        DependencyProperty.Register(GameNamePropertyName, typeof(string), typeof(GameIconControl), new UIPropertyMetadata(default(string)));


    public BitmapImage Icon
    {
        get { return (BitmapImage)GetValue(IconProperty); }
        set { SetValue(IconProperty, value); }
    }

    public static readonly DependencyProperty IconProperty =
        DependencyProperty.Register(IconPropertyName, typeof(BitmapImage), typeof(GameIconControl), new PropertyMetadata(default(BitmapImage)));


    public Game GameForControl
    {
        get { return (Game)GetValue(GameProperty); }
        set { SetValue(GameProperty, value); }
    }

    public static readonly DependencyProperty GameProperty =
        DependencyProperty.Register(GamePropertyName, typeof(Game), typeof(GameIconControl), new PropertyMetadata(default(Game)));
}

Any help is greatly appreciated.

Lastly, here is the opening xaml. I'm using MVVM Lite:

<Window x:Class="Saved_Game_Backup.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:cc="clr-namespace:Saved_Game_Backup.Assets"
    xmlns:command="http://www.galasoft.ch/mvvmlight"
    xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
    xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
    xmlns:viewModel="clr-namespace:Saved_Game_Backup.ViewModel"
    DataContext="{Binding Path=Main,
                          Source={StaticResource Locator}}">
Sheridan
  • 68,826
  • 24
  • 143
  • 183
CubemonkeyNYC
  • 273
  • 3
  • 17
  • 1
    try to use `RelativeSource FindAncestor` binding as shown [here](http://stackoverflow.com/a/1127964/2998271). That enable you to bind to control's parent DataContext, but haven't tried it from within style as in your case. – har07 Jan 22 '14 at 08:16

2 Answers2

1

I think MainViewModel is not a DataContext for GameItemControl. To overcome this problem you can create a StaticResource for MainViewModel and use that in binding. The following code snippet will help you,

    <WrapPanel.Resources>
      <local:MainViewModel x:Key="viewModel" />
    </WrapPanel.Resources>

    <command:EventToCommand Command="{Binding MoveGameIconToGameList,Mode=OneWay,     

            Source={StaticResource viewModel}}" />

Let me know if this helps.

Regards, Riyaj Ahamed I

  • The is confusing my xaml. I don't have a local namespace. The ViewModels are in the namespace "viewModel," so it's forcing it to but still breaking. I added the window's opening xaml. – CubemonkeyNYC Jan 22 '14 at 05:20
1

Sorry, but you're doing it all wrong. In WPF, we manipulate data items, not UI elements. So to create your scenario, you'd create a data type class (that implements the INotifyPropertyChanged interface) and then declare a DataTemplate that defines what each instance of your class should look like in the UI... in your case, your DataTemplate would have a GameIconControl in it. Bind a collection of these classes to the ItemsSource property of a collection control and the Framework will do all the rendering work for you.

This way, you can bind directly from the DataTemplate to the Command in your view model and you don't have any problems trying to data bind to properties of the UserControl. Better still, to remove an item from the UI, you just need to remove an item from your collection in the view model and the UI will automatically update.

For your future reference, it is generally not a good idea to set the DataContext of a UserControl as you have. Rather than doing that, you can access the UserControl DependencyPropertys using a RelativeSource Binding like this:

<TextBlock Text="{Binding PropertyName, RelativeSource={RelativeSource AncestorType={
    x:Type views:Saved_Game_Backup.MainWindow}}}" />

Furthermore, you can bind to a property or Command that is from any DataContext that is set on a UserControl (preferably from outside the control) like this:

<TextBlock Text="{Binding DataContext.PropertyName, RelativeSource={RelativeSource 
    AncestorType={x:Type views:Saved_Game_Backup.MainWindow}}}" />
Sheridan
  • 68,826
  • 24
  • 143
  • 183
  • Thanks. Trying to set the DataContext on the control was just my inexperienced flailing trying to make it work. It seemed wrong even to me, but I wasn't sure how to proceed. The rendering was already being done in a wrap panel and was working fine adding/removing them, but by methods other than double clicking on them in the panel. – CubemonkeyNYC Jan 22 '14 at 15:16