6

I am working with icons.XAML images, inserting them into buttons above a text block. Everything looks great until I hover over the image itself. A gray box appears over the picture only:

enter image description here

How do I get rid of the gray box?

Here is one of the icons:

<Canvas x:Key="appbar_cog" Width="38" Height="46" Clip="F1 M 0,0L 76,0L 76,76L 0,76L 0,0" Background="Transparent">
    <Path Width="37.6263" Height="37.6262" Canvas.Left="15" Canvas.Top="5" Stretch="Fill" Fill="#FF5DBEBE" Data="F1 M 27.5314,21.8628L 33.0126,19.4224L 34.7616,23.3507C 36.6693,22.9269 38.6044,22.8903 40.4668,23.2026L 42.0083,19.1868L 47.6098,21.337L 46.0683,25.3528C 47.6612,26.3669 49.0747,27.6889 50.2088,29.2803L 54.1371,27.5313L 56.5776,33.0126L 52.6493,34.7616C 53.0731,36.6693 53.1097,38.6043 52.7974,40.4668L 56.8131,42.0083L 54.6629,47.6097L 50.6472,46.0683C 49.6331,47.6613 48.3111,49.0748 46.7197,50.2089L 48.4686,54.1372L 42.9874,56.5776L 41.2384,52.6493C 39.3307,53.0731 37.3957,53.1097 35.5333,52.7974L 33.9918,56.8131L 28.3903,54.6629L 29.9318,50.6472C 28.3388,49.6331 26.9252,48.3111 25.7911,46.7196L 21.8628,48.4686L 19.4224,42.9873L 23.3507,41.2383C 22.9269,39.3307 22.8903,37.3957 23.2026,35.5332L 19.1869,33.9918L 21.3371,28.3903L 25.3528,29.9318C 26.3669,28.3388 27.6889,26.9252 29.2804,25.7911L 27.5314,21.8628 Z M 34.3394,29.7781C 29.7985,31.7998 27.7564,37.1198 29.7781,41.6606C 31.7998,46.2015 37.1198,48.2436 41.6606,46.2219C 46.2015,44.2002 48.2436,38.8802 46.2219,34.3394C 44.2002,29.7985 38.8802,27.7564 34.3394,29.7781 Z "/>
</Canvas>

Here is the button I am using:

<Style x:Key="MenuButtonStyle" TargetType="{x:Type Button}">
            <Setter Property="Background" Value="#FF496161"/>
            <Setter Property="OverridesDefaultStyle" Value="True"/>
            <Setter Property="Margin" Value="0"/>
            <Setter Property="Template">
                <Setter.Value>

                    <ControlTemplate TargetType="{x:Type Button}">
                        <Border Name="Border" 
                        BorderThickness="3"
                        Padding="4,2" 
                        BorderBrush="#ff496161" 
                        CornerRadius="3" 
                        Background="{TemplateBinding Background}">
                            <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
                        </Border>

                        <ControlTemplate.Triggers>
                                <Trigger Property="IsMouseOver" Value="True">
                                <Setter TargetName="Border" Property="Background" Value="White"/>
                                <Setter TargetName="Border" Property="BorderBrush" Value="DarkOrange" />
                                </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

Here is the MenuView where I call the image:

  </UserControl.Resources>
<ItemsControl ItemsSource="{Binding Path=MenuItems}">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <Button x:Name="MenuButton" Width="110"  VerticalContentAlignment="Top" HorizontalContentAlignment="Center" Margin="0 0 0 0" IsEnabled="{Binding Path=IsActive}"
                    Command="{Binding RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}, Path=DataContext.MenuSelectedCommand}" 
                    CommandParameter="{Binding Path=CommandName}" Style="{StaticResource MenuButtonStyle}">
                <StackPanel x:Name="MenuPanel" Orientation="Vertical">
                    <MenuItem x:Name="Picture" HorizontalAlignment="Center" Icon="{Binding ImageAddress, Converter={StaticResource StringToResourceConverter}}" Background="Transparent"/>
                    <TextBlock x:Name="Words" HorizontalAlignment="Stretch" Margin="0 0 0 0" TextAlignment="Center" Text="{Binding Description}" FontFamily="Arial" FontSize="14" />                           
                </StackPanel>

            </Button>
            <DataTemplate.Triggers>

                <Trigger SourceName="MenuButton" Property="IsMouseOver" Value="True">
                    <Setter TargetName="Words" Property="Foreground" Value="Black"/>

                 </Trigger>

                <Trigger SourceName="MenuButton" Property="IsMouseOver" Value="False">
                    <Setter TargetName="Words" Property="Foreground" Value="White"/>

                </Trigger>

            </DataTemplate.Triggers>
        </DataTemplate>

    </ItemsControl.ItemTemplate>
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <StackPanel Orientation="Horizontal" HorizontalAlignment="Stretch" Margin="0 0 0 0" Background="#496161">
            </StackPanel>
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>

</ItemsControl>

EDIT: here is the MenuItems script that orders my icons.

namespace Inspection.Desktop.Common.ViewModel
{
public class MenuViewModel : BaseViewModel
{

    public ObservableCollection<MenuItem> MenuItems { get; set; }

    public MenuViewModel()
    {

    }

    public override void InitiatedData()
    {
        MenuItems = new ObservableCollection<MenuItem>();

        MenuItems.Add(new MenuItem { CommandName = "WorkList", Description = "My WorkList", ImageAddress = "appbar_home", RoleName = "Electrical", WirelessRequired = true });
        MenuItems.Add(new MenuItem { CommandName = "Download", Description = "Download", ImageAddress = "appbar_cloud_download", RoleName = "Electrical", WirelessRequired = true });
        MenuItems.Add(new MenuItem { CommandName = "FieldRequest", Description = "Field Request", ImageAddress = "appbar_input_pen", RoleName = "FAS", WirelessRequired = false });
        MenuItems.Add(new MenuItem { CommandName = "Mileage", Description = "Mileage", ImageAddress = "appbar_transit_car", RoleName = "FAS", WirelessRequired = false });
        MenuItems.Add(new MenuItem { CommandName = "Calendar", Description = "Calendar", ImageAddress = "appbar_calendar", RoleName = "FAS", WirelessRequired = true });
        MenuItems.Add(new MenuItem { CommandName = "Assign", Description = "Assign", ImageAddress = "appbar_list_check", RoleName = "Electrical", WirelessRequired = true });
        MenuItems.Add(new MenuItem { CommandName = "Reports", Description = "Reports", ImageAddress = "appbar_graph_line_up", RoleName = "Electrical", WirelessRequired = true });
        MenuItems.Add(new MenuItem { CommandName = "PAIRS", Description = "Go To PAIRS", ImageAddress = "appbar_globe", RoleName = "Electrical", WirelessRequired = true });
        MenuItems.Add(new MenuItem { CommandName = "Settings", Description = "Settings", ImageAddress = "appbar_cog", RoleName = "Electrical", WirelessRequired = false });

    }

    public override void InitiatedCommand()
    {
        MenuSelectedCommand = new RelayCommand<string>(MenuClicked);
    }

    public override void InitiatedMessages() { }

    public RelayCommand<string> MenuSelectedCommand { get; private set; }

    public void MenuClicked(string name)
    {
        //MenuItems.ToList().ForEach((menu)=> {
        //                                    menu.IsActive = menu.CommandName.ToLower() == name.ToLower() ? false : true;
        //                                    });
        Utilities.Messenger.InspectionMessenger.SendMessage<string>(Messages.VIEW_CHANGED, name);
    }
  }
}
Chris W.
  • 22,835
  • 3
  • 60
  • 94
tCoe
  • 401
  • 1
  • 5
  • 24
  • If you need any more info please let me know, I am a newbie to Stack. Thanks. – tCoe Mar 03 '16 at 19:59
  • No idea what the grey box is, like another control from behind or something like that? – CodingGorilla Mar 03 '16 at 20:06
  • 1
    Yea this seems like a pretty one-off scenario. Show me an example of the end result you're looking for and I'm sure we can sort you out with a cleaner solution. What I do for this type of thing is build your button template, slap in a Path bound to the Tag Property, and save all the "icons" aka path data in a resource dictionary so I can one line each one like where the static resource is just whatever icon you need for that instance. – Chris W. Mar 03 '16 at 20:16
  • @CodingGorilla Thank you for looking at my problem. It is almost acting like a separate 'IsMouseOver' trigger that I cannot find. – tCoe Mar 03 '16 at 20:59
  • 1
    @ChrisW. I will try to get a screen grab of the app with the issue happening so you can see what i am talking about. Your method of creating a resource is what i am trying to do, and I cannot find where this is coming from. So maybe the pic will help. – tCoe Mar 03 '16 at 21:02
  • 1
    @B.K. Thank you for adding the picture. – tCoe Mar 03 '16 at 21:33
  • 1
    @tCoe In your `ItemsControl` template, under `DataTemplate`, in the `Button` remove `IsEnabled="{Binding Path=IsActive}"` and see if that gray box still appears. I suspect that could be the culprit. – B.K. Mar 03 '16 at 21:48
  • @B.K. still doing the same thing... – tCoe Mar 03 '16 at 22:26
  • 2
    Is there a style for canvas anywhere in your app? – XAMlMAX Mar 03 '16 at 22:28
  • @XAMlMAX not that i know of... thats why i am hitting a wall with this. If it doesnt have it, will it act this way? – tCoe Mar 03 '16 at 22:32
  • 2
    Oh....you've got your "picture" embedded as a `MenuItem` that has it's own control template....that's where your background is coming from amigo. ;) ...you could make that thing way more organized and deliver the same functionality with a fraction of the xaml and DOM objects. – Chris W. Mar 03 '16 at 22:34
  • 1
    From what i can see it looks like there is a style being applied , i.e. lost focus style. What i would do is to have a handler for onloaded event, just for debug, and investigate the visual tree of the element. This way you can find out if there is a style being applied and what element is being applied. – XAMlMAX Mar 03 '16 at 22:36
  • 3
    It's because they've got it in there as a [MenuItem](https://msdn.microsoft.com/en-us/library/ms747082%28v=vs.85%29.aspx), which gives it color #ddd color to the background border of it via brush on highlight. – Chris W. Mar 03 '16 at 22:38
  • @ChrisW. I have an ordered list for display that references the icons in the icons.xaml. I reference that in the (ItemsControl ItemsSource="{Binding Path=MenuItems})...because i am so new to this whole deal, could you explain what i could do to make this better? IS there anything i could create this as that wouldnt have that? – tCoe Mar 03 '16 at 22:47
  • 2
    Yea it's quitting time in my time zone and I got errands to run but I'll pop you out something tomorrow. Basically your ItemTemplate is going to become ONE button, that uses ONE style, you won't have to change any of your bindings and can ditch the converter and the rest of that garbage, will be xaml only and you'll be done. Well, I think at least, how are you saving your "ImageAddress"? Is it just a string with the path data? – Chris W. Mar 03 '16 at 22:51
  • @ChrisW. the imageAddress is a property of the MenuItems csv list... i will edit to share the script for that. – tCoe Mar 03 '16 at 22:55
  • @XAMlMAX could you explain the "Lost Focus Style" or maybe give me an idea of the handler? – tCoe Mar 04 '16 at 14:52
  • 1
    Sweet looking icons!! – code4life Mar 04 '16 at 21:30

1 Answers1

3

Ok, so after you updated your question and we figured out that your culprit was the usage of MenuItem and it's inherited control template giving the #ddd gray color on highlight we talked about some quick refactoring for better practices. So here's an example of what I was talking about (that you'll probably want to tweak a little to fit your needs) and assumes that your "ImageAddress" is just pointed at Geometry path data to create your icons.

However if that's not the case, and you're literally using images that's fine too, just swap the Path object in the button template with Image or whatever you want to do. So anyway here's what I do with a quick example starting with the resources you'd plop in a Resource dict or wherever;

<Window.Resources>
        <!-- The "icons" -->
        <Geometry x:Key="ExampleIcon">M78,63 L69.333333,75 54.00093,76.333333 67.333747,89.000655 64.667184,101.66764 78.666641,93.667175 89.332417,102.33399 90.66603,89.667334 103.33171,77.00035 86.666127,75.666984 z</Geometry>
        <Geometry x:Key="ExampleIcon2">M72,62 L48,83 69,106 92,87 z</Geometry>

        <!-- The Button Template -->
        <Style x:Key="NeatoButtonStyle" TargetType="{x:Type Button}">
            <Setter Property="OverridesDefaultStyle" Value="True"/>
            <Setter Property="Background" Value="Transparent"/>
            <Setter Property="BorderBrush" Value="Transparent"/>
            <Setter Property="Foreground" Value="White"/>
            <Setter Property="BorderThickness" Value="3"/>
            <Setter Property="HorizontalContentAlignment" Value="Center"/>
            <Setter Property="VerticalContentAlignment" Value="Center"/>
            <Setter Property="Padding" Value="4,2"/>
            <Setter Property="Cursor" Value="Hand"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type Button}">                      

                            <Grid>
                                <Grid.RowDefinitions>
                                    <RowDefinition/>
                                    <RowDefinition Height="Auto"/>
                                </Grid.RowDefinitions>

                                <Border Grid.RowSpan="2"
                                        x:Name="border" 
                                        BorderBrush="{TemplateBinding BorderBrush}" 
                                        BorderThickness="{TemplateBinding BorderThickness}" 
                                        Background="{TemplateBinding Background}" 
                                        SnapsToDevicePixels="true"/>

                                <Path Stretch="Uniform"
                                      Data="{TemplateBinding Tag}"
                                      Fill="#FF5DBEBE"
                                      Margin="{TemplateBinding Padding}"/>

                                <ContentPresenter Grid.Row="1"
                                                  x:Name="contentPresenter" 
                                                  Focusable="False"                                               
                                                  Margin="{TemplateBinding Padding}" 
                                                  RecognizesAccessKey="True" 
                                                  SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
                                                  HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                                                  VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>

                            </Grid>

                        <ControlTemplate.Triggers>

                            <Trigger Property="IsMouseOver" Value="true">
                                <Setter Property="Background" TargetName="border" 
                                        Value="White"/>
                                <Setter Property="BorderBrush" TargetName="border" 
                                        Value="DarkOrange"/>
                                <Setter Property="TextElement.Foreground" TargetName="contentPresenter" 
                                        Value="Black"/>
                            </Trigger>

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

    </Window.Resources>

So you'll notice I took everything you had separated out and it now all lives in one template you can use from anywhere. There's also a couple example (albeit shotty quick little drawings lol) icon example path data in there at the top. So say we have buttons we need to make now. Well you just invoke what icon you want via the handy dandy Tag property at the instance like;

<StackPanel Orientation="Horizontal" 
    HorizontalAlignment="Center" VerticalAlignment="Center">

        <Button Content="Blah Blah"
                Style="{StaticResource NeatoButtonStyle}"
                Tag="{StaticResource ExampleIcon}"/>

        <Button Content="Blah Blah"
                Style="{StaticResource NeatoButtonStyle}"
                Tag="{StaticResource ExampleIcon2}"/>

</StackPanel>

Which allows a quick, easy, and manageable way to store your icons, use them as needed etc. I'd recommend setting a default for Tag in the template via a setter like; <Setter Property="Tag" Value="{StaticResource DefaultIconResourceName}"/> just so if someone forgets to set one, you have one there.

So now we have our button setup, but how do you use it in your instance of creating them via collection? Well we just swap your current ItemTemplate with something like;

<ItemsControl.ItemTemplate>
   <DataTemplate>

      <Button Content="{Binding Description}"                 
              Tag="{Binding ImageAddress}"
              Style="{StaticResource NeatoButtonStyle}"/>

   </DataTemplate>
</ItemsControl.ItemTemplate>

Which, in doing so eliminates a bunch of unnecessary clutter, as well as removes all those unnecessary DOM elements created for each instance by using the other nested templated controls.

That's it, you're done. Now if say you use the buttons all over the place and someone decides something needs tweaked, you do it in one spot and it gets inherited to every instance. As well as allowing some more flexibility for one-off scenarios where you maybe need to change other stuff easily.

Anyway hope this helps. Cheers!

ADDENDUM

If you wanted to add something like say a "Hover State" to the path you would just add a name to your Path inside the button template like;

<Path x:Name="ButtonIcon"
      Stretch="Uniform"
      Data="{TemplateBinding Tag}"
      Fill="#FF5DBEBE"
      Margin="{TemplateBinding Padding}"/>

Then just add a trigger for it to the existing IsMouseOver ones already sitting in the button template like for example;

<Setter Property="Fill" 
        TargetName="ButtonIcon" 
        Value="Red"/>

ADDENDUM TO THE ADDENDUM:

So to add a Disabled State we just add another trigger to handle it for us and give the visual of being disabled. So we would add another trigger like this into template right where we're handling IsMouseOver already.

<Trigger Property="IsEnabled" Value="false">
   <Setter TargetName="border" 
           Property="Background" 
           Value="{StaticResource DisabledBackgroundBrush}" />
   <Setter TargetName="border" 
           Property="BorderBrush" 
           Value="{StaticResource DisabledBorderBrush}" />
   <Setter Property="Foreground" 
           Value="{StaticResource DisabledForegroundBrush}"/>
</Trigger>

So now when IsEnabled=False our Border and our foreground reflect that state by using the default Disabled brushes while in that state.

Keep in mind it's still a Button control and comes with all the built in functionality of any standard default button. We just didn't cover all the bases for the sake of this example.

So if you need IsEnabled, IsKeyboardFocused, IsPressed etc, you can just add whatever you need in there form.

Chris W.
  • 22,835
  • 3
  • 60
  • 94
  • If i could uptick this more than once i would. That's a huge amount of work! Thank you very much! – tCoe Mar 04 '16 at 17:02
  • 1
    @tCoe eh, not really, took around ten minutes. Ya might hit that checkmark icon on there to mark it correct if it answered your question though so folks know you're sorted. Have a good weekend amigo! – Chris W. Mar 04 '16 at 17:08
  • quick question on this just to be sure i am reading it right. the "Data" field from the canvas is the "geometry" field that i need to add to my windows.resources? and i should do this for each icon? – tCoe Mar 04 '16 at 17:41
  • 1
    Yep `Data` is the property of the `Path` element that holds your Path Geometry. – Chris W. Mar 04 '16 at 17:49
  • In the 'NeatoButtonStyle', is there a way i can control the color of the "ExampleIcon"? this would be helpful if the BA people think it is too light when the background changes to white...Thank you again. – tCoe Mar 04 '16 at 21:07
  • 1
    @tCoe yea, if you see the `Fill` property on the `Path` inside the Button template I have it set to the hex color you had in your example. You could change it there. You could also add a trigger to change it on hover too if you want, or you could TemplateBinding to Foreground and it will inherit whatever the Foreground color is. Or if you wanted to get real fancy you could add an [attached property](http://stackoverflow.com/questions/3940597/how-to-create-a-dependency-property-on-an-existing-control) to set it inline at the instance of button if you wanted. – Chris W. Mar 04 '16 at 21:18
  • 1
    @tCoe see the addendum at the bottom of the answer for some more info to handle their hover color discrepancies, and have a good weekend dude! – Chris W. Mar 04 '16 at 21:24
  • Last thing, I am trying to get some of the buttons to disable based on a variable that I have set equal to the internet connection state. Everything I am looking up says I should have some type of converter. Is there a way to include this into the button on the data template? Of course a third color set would be necessary on the button template but I can handle that part... – tCoe Mar 07 '16 at 19:51
  • 1
    @tCoe sure thing, see the "addendum to the addendum" at the bottom of the updated answer. Also, one thing I often do is just put another border over top of everything with the disabled brush as background etc, and toggle it's visibility separately for IsEnabled=false instead of applying setters to different properties on the same object for every instance. So then if it's disabled, the whole button just gets a semi-transparent overlay for the disabled visual. :) – Chris W. Mar 07 '16 at 20:00
  • is there a way to apply this to some of the buttons instead of all of them? I don't want all of the buttons effected by this. I researched as long as i could about creating another style and using the "IsEnabled" property. Unfortunately, it keeps breaking when I have a setter equal to my variable. – tCoe Mar 07 '16 at 23:01
  • 1
    @tCoe Of course man, so in your ItemTemplate where Button lives just add something like `IsEnabled="{Binding DataContext.IsEnabled, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type MyControl}}}"` and then you can hit IsEnabled from the parent ViewModel or just `IsEnabled="{Binding Blah}"` from your list viewmodel. Make sense? Don't forget to notifyofpropertychanged if it's dynamic. – Chris W. Mar 07 '16 at 23:13
  • I am having issues with the 'MyControl' ancestor type. My Visual Studio doesn't support that, and I am not sure what type to put in there as a replacement. I tried pointing it to my variables class of 'InternetAvailablility' and the variable within the class of "IsInternetAvailable". I have that class stored in the 'AssemblyInfo.cs', but that doesn't work either. The hard part is that it will run the program, but not throw any errors or actually open the program window. – tCoe Mar 08 '16 at 15:41
  • 1
    @tCoe Yea "MyControl" is just whatever the parent with the datacontext would be. So could be a Window, or UserControl, or whatever. You could always just give your view an x:Name and swap the Ancestory stuff for just `ElementName=TheViewsOrControlsxName`, the point is you're just trying to hit the datacontext from inside the datatemplate of your ItemTemplate. – Chris W. Mar 08 '16 at 15:44
  • 1
    Oh and I should probably add, if you don't even need the datacontext hit, you could just do {Binding} the same way you're bringing in the "Description" and "ImageAddress" aka the button content word. I just added that stuff in there for further example. – Chris W. Mar 08 '16 at 15:53
  • the powers that be have said that i must reference the c# MenuItem script instead of repeating the button code. they also do not want me to copy the geometry info into the style, instead they want me to reference icons.xaml. this is an excellent working solution, but apparently unacceptable in the application being built. – tCoe Mar 11 '16 at 22:43
  • 1
    Well that's their call to make, but it's not a correct one in an enterprise app. Good luck brother – Chris W. Mar 11 '16 at 22:58
  • thanks man you have been really helpful. and i would agree with you on this method. unfortunately i dont get to make the decision... back to square one.... – tCoe Mar 11 '16 at 23:04
  • No worries man, that's the way of the world, have a great weekend! – Chris W. Mar 11 '16 at 23:05
  • Is there a way that i can get the image by setting the 'Tag' to the name of the icon in the 'Icons.xaml' file? I know i would have to change the section around some but if that can happen then i can get this working. – tCoe Mar 14 '16 at 16:16
  • 1
    @tCoe hmm we're getting into it now where I'm at a bit of a disadvantage not having in front of me. If they're all saved as Canvas in your icons.xaml file then if I'm understanding you correctly you would just change the `Path` object in the button template to `ContentControl` and you can pass it in that way like `` – Chris W. Mar 14 '16 at 16:32
  • 1
    @tCoe errrrr I'm sorry. I mean you would still use Tag like `` then at your instance it would be `Tag="{StaticResource IconName}"` – Chris W. Mar 14 '16 at 16:35
  • This works except for the color. is there different syntax there to call the 'Path.Fill' property? also my Icon name will be fed in as a dynamic property of the 'menuitem'. In the MenuView.xaml, if i use {binding Imageaddress} then it will pas the words of the title into the place where the image goes, but the {StaticResource ImageAddress} fails to render. – tCoe Mar 14 '16 at 16:42
  • i sent you a message – tCoe Mar 14 '16 at 18:33
  • 1
    @tCoe cool I've got some meetings but I'll see it shortly. Plus this way we're not using SO comments as a chatroom lol – Chris W. Mar 14 '16 at 18:34