4

I am trying to create button that locks and unlocks a textbox the button displays a locked icon when the textbox is disabled and an unlocked lock when the textbox is enabled.

I have done a bunch of reading and found the question on this site: WPF Change button background image when clicked

I took the answer and came up with this.

<Button Grid.Row="0" Command="{Binding ChangePnumTextState}" CommandParameter="{Binding ElementName=ButtonCanvas, Path=Source}">
    <Canvas Name="ButtonCanvas">
         <Canvas.Style>
              <Style TargetType="{x:Type Canvas}">
                   <Style.Triggers>
                        <DataTrigger Binding="{ Binding IsPNumLocked}" Value="True">
                            <Setter Property="Source" Value="{StaticResource appbar_lock}" />
                        </DataTrigger>
                        <DataTrigger Binding="{ Binding IsPNumLocked}" Value="False">
                            <Setter Property="Source" Value="{StaticResource appbar_unlock}" />
                        </DataTrigger>
                    </Style.Triggers>
                </Style>
          </Canvas.Style>
     </Canvas>
</Button>

I have imported this batch of icons http://modernuiicons.com/ into xaml file that gets drawn when I need one

I have looked around just cant find any examples of how to do this with SVG and not an image

EDIT

Ok it was pointed out that SVG doesnt work with wpf I am probably just confusing names up heres an example of the code I have in a resource library that I am using to get the icons

<Canvas x:Key="appbar_3d_obj" Width="76" Height="76" Clip="F1 M 0,0L 76,0L 76,76L 0,76L 0,0">
    <Path Width="40" Height="40" Canvas.Left="18" Canvas.Top="18" Stretch="Fill" Fill="{DynamicResource BlackBrush}" Data="F1 M 18,21.7037L 43.9259,18L 58,25.4074L 58,54.2963L 32.8148,58L 18,49.1111L 18,21.7037 Z "/>
</Canvas>

The error I am getting is the visual studio underline the Property in the Setters and states

"The member 'Source' is not recognized or is not accessible"

Community
  • 1
  • 1
Fresh
  • 183
  • 1
  • 10
  • Wpf does not have SVG support. There are Xaml icons though – Pikoh Apr 27 '16 at 15:20
  • ok thats probably what I mean I will update my question to reflect that. Thank you. – Fresh Apr 27 '16 at 15:22
  • Anyway, your code seems ok, what is your problem? – Pikoh Apr 27 '16 at 15:23
  • @Pikoh oops added that to my question too however the error I am getting is that in setters I am getting the error "The member 'Source' is not recognized or is not accessible" – Fresh Apr 27 '16 at 15:27

2 Answers2

3

There's a few problems with the XAML you've got now.

As others have pointed out, there's no Source property on a WPF canvas. If all you're trying to do is make the button content canvases you've got defined already, you could use the same technique to bind the Content property of your Button to the Canvases defined in your App.xaml (or wherever it may be)

Another issue you're likely running into is the binding within your data trigger. I haven't tested, but I presume you won't have the same datacontext within the style that you're expecting from your user control (or whatever contains the button) Doesn't look like the data context is an issue, I guess I was thinking of templating issues

Also, I'm not sure what your ChangePnumTextState command is doing, but is there a reason you're sending in the canvas as the parameter? If your command is simply changing a bool value on IsPnumLocked, you should be able to handle everything in XAML and keep your separation of concerns.

Here's an easy change to make the content of the button the Canvas you have defined:

<Button Command="{Binding ChangePnumTextState}">
        <Button.Style>
            <Style TargetType="{x:Type Button}">
                <Style.Triggers>
                    <DataTrigger Binding="{Binding IsPNumLocked}" Value="True">
                        <Setter Property="Content" Value="{StaticResource appbar_lock}"/>
                    </DataTrigger>
                    <DataTrigger Binding="{Binding IsPNumLocked}" Value="False">
                        <Setter Property="Content" Value="{StaticResource appbar_unlock}"/>
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </Button.Style>
    </Button>

Notice how rather than trying to set the source of the canvas, we simply set the content of the button to the canvas you already have defined.

Also the RelativeSource on the bindings should take care of the datacontext resolution (although you'll need to make sure that the relative source you search for has the datacontext you're after)

Edit: Another approach would be to make a converter for your canvas paths based on a bool value (which I assume IsPNumLocked is). You could then just have a canvas as a child of the button's content, and it would be much easier to include other content as well.

Example converter:

    public class IsPnumLockedToCanvasPathConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        bool val = (bool)value;
        return val 
            ? "F1 M 22.17,36.4216L 25.3369,36.4216L 25.3369,31.6711C 25.3369,24.6745 31.0087,19.0027 38.0053,19.0027C 45.0019,19.0027 50.6737,24.6745 50.6737,31.6711L 50.6737,36.4216L 53.841,36.4216L 53.8411,57.008L 22.17,57.008L 22.17,36.4216 Z M 45.9231,31.6711C 45.9231,27.2982 42.3782,23.7533 38.0053,23.7533C 33.6324,23.7533 30.0875,27.2982 30.0875,31.6711L 30.0875,36.4216L 45.923,36.4216L 45.9231,31.6711 Z "
            : "F1 M 22.1698,36.4215L 25.3366,36.4215L 25.3367,31.6711C 25.3367,24.6745 31.0085,19.0027 38.0051,19.0027C 45.0017,19.0027 50.6735,24.6745 50.6735,31.6711L 45.9228,31.6711C 45.9228,27.2982 42.3779,23.7533 38.0051,23.7533C 33.6322,23.7533 30.0873,27.2982 30.0873,31.6711L 30.0873,36.4216L 53.8408,36.4215L 53.8409,57.008L 22.1698,57.008L 22.1698,36.4215 Z ";
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

and your button could be set up like so:

<Button Command="{Binding ChangePnumTextState}">
        <Button.Resources>
            <converters:IsPnumLockedToCanvasPathConverter x:Key="IsPnumLockedToCanvasPathConverter"/>
        </Button.Resources>
        <StackPanel Orientation="Vertical">
            <Canvas Width="76" Height="76" Clip="F1 M 0,0L 76,0L 76,76L 0,76L 0,0">
                <Path Width="40" Height="40" Canvas.Left="18" Canvas.Top="18" Stretch="Fill" Fill="{DynamicResource BlackBrush}" Data="{Binding IsPNumLocked, Converter={StaticResource IsPnumLockedToCanvasPathConverter}}"></Path>
            </Canvas>
            <TextBlock Text="Other Content"/>
        </StackPanel>

    </Button>
McFixit
  • 437
  • 3
  • 15
1

You are trying to set the Source property on a Canvas object. There is no Source property for that control.

The Source property is commonly used with an Image control.

However, since you are using a Canvas, you can just add both of your Path objects to the Canvas, right on top of each other. Give each Path a name, and then use your DataTriggers to change the visibility of each Path object.

Something like:

<Button Grid.Row="0" Command="{Binding ChangePnumTextState}" CommandParameter="{Binding ElementName=ButtonCanvas, Path=Source}">
<Canvas Name="ButtonCanvas">
     <Path Name="appbar_lock" Data="...your data here..."/>
     <Path Name="appbar_unlock" Data="...your data here..."/>
     <Canvas.Style>
          <Style TargetType="{x:Type Canvas}">
               <Style.Triggers>
                    <DataTrigger Binding="{Binding IsPNumLocked}" Value="True">
                        <Setter TargetName="appbar_lock" Property="Visibility" Value="Visible" />
                        <Setter TargetName="appbar_unlock" Property="Visibility" Value="Hidden" />
                    </DataTrigger>
                    <DataTrigger Binding="{Binding IsPNumLocked}" Value="False">
                        <Setter TargetName="appbar_lock" Property="Visibility" Value="Hidden" />
                        <Setter TargetName="appbar_unlock" Property="Visibility" Value="Visible" />
                    </DataTrigger>
                </Style.Triggers>
            </Style>
      </Canvas.Style>
 </Canvas>
</Button>
Stewbob
  • 16,759
  • 9
  • 63
  • 107
  • ok I had a feeling it had something to with source most likely not being a property of canvas but wasnt sure what to replace it with.. I am not sure I follow what you mean with two paths.. Any chance you get write out a short example? – Fresh Apr 27 '16 at 16:14