Search code examples
c#wpfmvvm

retrieve string text located in an itemcontrol canvas composed of several elements by clicking on it


There is my WPF code :

<ItemsControl
            x:Name="ICAgentAffiché"
            MinHeight="{Binding HauteurPlanning}"
            HorizontalAlignment="Stretch"
            ItemsSource="{Binding Path=AffichageAgent}">
                <ItemsControl.ItemsPanel>
                    <ItemsPanelTemplate>
                        <Canvas Background="Transparent"/>
                    </ItemsPanelTemplate>
                </ItemsControl.ItemsPanel>
            <ItemsControl.ItemContainerStyle>
                <Style TargetType="ContentPresenter">
                        <Setter Property="Canvas.Left" Value="{Binding Left}" />
                    <Setter Property="Canvas.Top" Value="{Binding Top}" />
                </Style>
                </ItemsControl.ItemContainerStyle>
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <Label
                            x:Name="LbAgentAffiche"
                        Width="{Binding Width}"
                        Height="17"
                        Padding="0"         
                        HorizontalContentAlignment="Center"
                        VerticalContentAlignment="Top"
                        Panel.ZIndex="22"                     
                        Background="{Binding Color, Converter={StaticResource ServiceSectionColorConverter}, Mode=OneWay}"
                        BorderBrush="Black"
                        BorderThickness="0.5"
                        FontSize="10"
                        MouseLeftButtonDown="Canvas_MouseLeftButtonDown"
                        MouseLeftButtonUp="Canvas_MouseLeftButtonUp"
                        MouseMove="Canvas_MouseMove"                           
                        Tag="{Binding Color}">
                        <StackPanel>
                            <Grid x:Name="gridLabel">
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="auto"/>
                                    <ColumnDefinition Width="auto"/>
                                </Grid.ColumnDefinitions>
                                <Image Grid.Column="0" Source="{Binding BackgroundPointage}" UseLayoutRounding="True" RenderOptions.BitmapScalingMode="NearestNeighbor" VerticalAlignment="Center"  HorizontalAlignment="Center" Margin="0,2,0,0"></Image>
                                <Label Name="LabelAgent" Grid.Column="1" VerticalAlignment="Center"  Padding="5,0,0,0" Content="{Binding Path=NomPrenom}" ></Label>
                            </Grid>
                        </StackPanel>
                    </Label>
                </DataTemplate>
                </ItemsControl.ItemTemplate>
            </ItemsControl>

Previously, I didn't have the "stackpanel" part, and only the "LastName" binding in the label content.

Which gave me this result:

enter image description here

When I clicked on it, I only retrieved the string in a variable, via this code behind :

    private void Canvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        ((PlanningJournalierViewModel)(this.DataContext)).AgentSelected(sender.ToString());
    }

Sender.ToString() contained only the string, which was perfect.

Today, I added the stackpanel to my code to add an image in addition to the string :

enter image description here

My problem is that when I click on it, the application crashes. It's no longer a label with just one string, but an object containing several elements (image + text). Is it possible, by clicking on it, to retrieve only the string (and not the image), so that it works properly again?


Solution

  • Try this:

    var label = (Label)sender;
    var viewmodel = (YourViewModel)label.DataContext;
    var wantedText = viewmodel.NomPrenom;
    

    where YourViewModel is the model that is in your AffichageAgent collection.

    Btw, a Grid with two autosize colums is the same as a horizontal StackPanel. And better than a horizontal StackPanel (which is not responsive) is to use a DockPanel with defaults. And the outer StackPanel is not needed.

    Furthermore, i think the MouseMove event handler should move to the Canvas itself, not on all the labels.

    Also the MouseLeftButtonDown and up eventhandler can move to the Canvas itself, just use e.Source or e.OriginalSource to see which label was clicked, i think e.Source is the one.

    And using the outer Label is kind of strange. What is the purpose here? A border with an image and text next to each other?

    So,

    <Border Background=".." BorderBrush=".." BorderThickness="..">
      <DockPanel>
        <Image ..>
        <TextBlock..>
      </DockPanel>
    </Border>
    

    And finally:

    • HorizontalAlignment="Stretch" is always the default for an element.
    • The HorizontalAlignment of the image is ignored since it is in a auto size column.
    • Don't use Tag!
    • Don't give any element in an ItemTemplate a name, since there are multiple of them