Changing ellipse fill color inside a button - c#

I want to change the ellipse fill color to green when the button is enabled.
<Button x:Name="btn_Kaart2" Grid.Column="1" Grid.Row="2" IsEnabled="False">
<Button.Template>
<ControlTemplate>
<Ellipse x:Name="ellipse_2"
Height="35"
Stroke="Black"
Fill="Red"
Margin="-300,440,0,0"/>
</ControlTemplate>
</Button.Template>
</Button>
Normally I would use ellipse_2.Fill = "Color" but that doesn't work, program can't find ellipse_2

You can use a databinding with RelativeSource to get this without any additional code
<Button x:Name="btn_Kaart2" Grid.Column="1" Grid.Row="2" IsEnabled="False">
<Button.Template>
<ControlTemplate>
<Ellipse x:Name="ellipse_2"
Height="35"
Margin="-300,440,0,0"
Stroke="Black">
<Ellipse.Style>
<Style TargetType="Ellipse">
<Style.Triggers>
<DataTrigger Binding="{Binding IsEnabled, RelativeSource={RelativeSource AncestorType=Button}}" Value="false">
<Setter Property="Fill" Value="red"></Setter>
</DataTrigger>
<DataTrigger Binding="{Binding IsEnabled, RelativeSource={RelativeSource AncestorType=Button}}" Value="true">
<Setter Property="Fill" Value="green"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</Ellipse.Style>
</Ellipse>
</ControlTemplate>
</Button.Template>
</Button>
It's important that the Ellipse itself has no Fill attribute.
You can try this by changing the IsEnabled value in the *.xaml and the color should change immediately in the designer.

Related

Different Content (System.Windows.DataTemplates) displayed by ContentControl rather than required Icon

I am working on a combo box with icons.This combo box consist of items which have a name and an icon with the respective type it belongs to.
While my attempt has been successful to a certain extent I am getting a string which says "System.Windows.DataTemplate" to where it's supposed to show the respective icon.
I feel like there is something wrong in the way that I am calling the content controller.
you should use DataTemplate resources to set ContentTemplate property, not Content
<ContentControl Content="{Binding}">
<ContentControl.Style>
<Style TargetType="{x:Type ContentControl}">
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType={x:Type dc:ComboBoxItem}}, Path=DataContext, Converter={StaticResource FormBuilderClient_TypeOfConverter}}" Value="{x:Type models:FileSettingsModel}" >
<Setter Property="ContentTemplate" Value="{StaticResource FileIcon}" />
</DataTrigger>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType={x:Type dc:ComboBoxItem}}, Path=DataContext, Converter={StaticResource FormBuilderClient_TypeOfConverter}}" Value="{x:Type models:ServerSettingsModel}" >
<Setter Property="ContentTemplate" Value="{StaticResource ServerIcon}" />
</DataTrigger>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType={x:Type dc:ComboBoxItem}}, Path=DataContext, Converter={StaticResource FormBuilderClient_TypeOfConverter}}" Value="{x:Type models:HomeSettingsModel}" >
<Setter Property="ContentTemplate" Value="{StaticResource HomeIcon}" />
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
however it should be simpler to use DataTemplates for specific type, rather than x:Key. also define them in ComboBox resources.
<ComboBox.Resources >
<DataTemplate DataType="{x:Type models:FileSettingsModel}">
<Path Stretch="Uniform" Stroke="Black" Fill="Blue" Height="15" Width="25" Data="..."/>
</DataTemplate>
<DataTemplate DataType="{x:Type models:ServerSettingsModel}" >
<Path Stretch="Uniform" Stroke="Black" Fill="OrangeRed" Height="15" Width="25" Data="..."/>
</DataTemplate>
<DataTemplate DataType="{x:Type models:HomeSettingsModel}">
<Canvas>
<Path Canvas.Top="0" Canvas.Left="-2" Height="15" Width="25"
Stretch="Uniform" Stroke="Black" Fill="Green" Data="..."/>
<Path Canvas.Top="7" Canvas.Left="9" Height="16" Width="23"
Stretch="Uniform" Stroke="Black" Fill="Yellow" Data="..."/>
</Canvas>
</DataTemplate>
</ComboBox.Resources>
this way ContentControl should pick correct template without any triggers:
<ContentControl Content="{Binding}"/>

MVVM WPF images on canvas

I have a code that allows you to create objects on the screen, there is a panel of buttons, clicking on the button you create an image / object on canvas, I can not get another image to be placed in Canvas so that several images can be displayed, link to a previously created question: WPF C # Display objects (2d Map)
<Thumb.Template>
<ControlTemplate TargetType="Thumb">
<Canvas>
<Image x:Name="injWell" Source="/Resources/injectionWell.png"
HorizontalAlignment="Center" VerticalAlignment="Center"
Width="40" Height="40"
Stretch="Fill" StretchDirection="Both" IsHitTestVisible="False"/>
<Image x:Name="injWellNot" Source="/Resources/injectionWellNot.png"
HorizontalAlignment="Center" VerticalAlignment="Center"
Width="40" Height="40"
Stretch="Fill" StretchDirection="Both" IsHitTestVisible="False"/>
<TextBlock Canvas.Top="-20" Canvas.Left="-40" Width="100"
TextAlignment="Center" Text="{Binding Name}" FontWeight="Bold"
IsHitTestVisible="False"
Visibility="{Binding DataContext.ShowNames,
RelativeSource={RelativeSource FindAncestor, AncestorType=Window},
Converter={StaticResource BoolToVisibilityConverter}}"/>
<TextBlock Canvas.Left="30" Canvas.Top="10"
Text="{Binding X, StringFormat='{}X = {0}'}"
IsHitTestVisible="False"
Visibility="Collapsed" x:Name="XText"/>
<TextBlock Canvas.Left="30" Canvas.Top="25"
Text="{Binding Y, StringFormat='{}Y = {0}'}"
IsHitTestVisible="False"
Visibility="Collapsed" x:Name="YText"/>
</Canvas>
<ControlTemplate.Triggers>
<Trigger Property="IsDragging" Value="True">
<Setter TargetName="injWell" Property="Source" Value="/Resources/injectionWell.png"/>
<Setter TargetName="injWellNot" Property="Source" Value="/Resources/injectionWellNot.png"/>
</Trigger>
<DataTrigger Binding="{Binding DataContext.ShowAllCoordinates, RelativeSource={RelativeSource FindAncestor, AncestorType=Window}}" Value="True">
<Setter TargetName="XText" Property="Visibility" Value="Visible"/>
<Setter TargetName="YText" Property="Visibility" Value="Visible"/>
</DataTrigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding IsSelected, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBoxItem}}}" Value="True"/>
<Condition Binding="{Binding DataContext.ShowCurrentCoordinates, RelativeSource={RelativeSource FindAncestor, AncestorType=Window}}" Value="True"/>
</MultiDataTrigger.Conditions>
<Setter TargetName="XText" Property="Visibility" Value="Visible"/>
<Setter TargetName="YText" Property="Visibility" Value="Visible"/>
</MultiDataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Thumb.Template>
</Thumb>
</DataTemplate>
The key thing to realize here is that you need to render a list of items, and in MVVM you do that with an ItemsControl. (You could also use a ListView, but they implement additional functionality that you almost certainly wont want, like item selection etc). Ultimately you want all of your graphics objects to be displayed on a Canvas, so you need to override the ItemsPanel property and put one there inside a ItemsPanelTemplate. Each element then needs to be positioned on the Canvas, so you'll need to set the ItemContainerStyle and set the Canvas.Left and Canvas.Top properties there (a common mistake is to do it on the elements themselves, but they get placed into a container so you have to do it on that instead). Put all this together and you'll have something that looks like this:
<ItemsControl ItemsSource="{Binding MyGraphicsViewModels}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style TargetType="{x:Type ContentPresenter}">
<Setter Property="Canvas.Left" Value="{Binding X}" />
<Setter Property="Canvas.Top" Value="{Binding Y}" />
</Style>
</ItemsControl.ItemContainerStyle>
</ItemsControl>
So MyGraphicsViewModels will typical be a list in your view model of some base class you've created (e.g. BaseGraphicsViewModel) and then you'll subclass that into all the different types of graphics items you want to draw. The final piece of the puzzle is to then add DataTemplates to specify how you want each of your view model types to be represented in the view:
<DataTemplate DataType="{x:Type vm:DerivedGraphicsObjectViewModel}">
<Rectangle Fill="Blue" Width="64" Height="64" />
</DataTemplate>
For a more comprehensive example, which uses Triggers instead of DataTemplates, check out my answer to this SO question from the past.

How to change the image of a button when a textbox is empty in WPF?

I want to create a SearchBox and currently my code looks like below. I tried to change the ImageSource of the ImageBrush tag when the text box is empty but I don't know to bind the Text property from the Textbox properly. I want my SearchBox to look like this:
When the SearchBox is empty the button must to show the search image and when the SearchBox is not empty the button must to show the clear search image. Can anyone hepl me with this?
<TextBox Name="SearchTextBox" />
<Button Grid.Column="0" Style="{DynamicResource NoChromeButton}" BorderThickness="1"
VerticalAlignment="Center" HorizontalAlignment="Right" Width="25" Height="25" Click="Search_Click" Panel.ZIndex="1">
<Button.Template>
<ControlTemplate TargetType="{x:Type Button}">
<Border>
<Grid>
<ContentPresenter />
<Grid x:Name="StatusPanel" Background="Black" Opacity="0"/>
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter TargetName="StatusPanel" Property="Opacity" Value="0.1"/>
</Trigger>
<Trigger Property="IsPressed" Value="true">
<Setter TargetName="StatusPanel" Property="Opacity" Value="0.3"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Button.Template>
<Button.Content>
<Rectangle x:Name="aaa" >
<Rectangle.Fill>
<ImageBrush ImageSource="pack://application:,,,/AssemblyName;component/Resources/Img1.png" />
</Rectangle.Fill>
<Rectangle.Style>
<Style TargetType="{x:Type Rectangle}" >
<Style.Triggers>
<DataTrigger Binding="{Binding Text.Length, ElementName=SearchTextBox, UpdateSourceTrigger=PropertyChanged}" Value="0" >
<DataTrigger.Setters>
<Setter Property="Fill">
<Setter.Value>
<ImageBrush ImageSource="pack://application:,,,/AssemblyName;component/Resources/Img2.png" />
</Setter.Value>
</Setter>
</DataTrigger.Setters>
</DataTrigger>
</Style.Triggers>
</Style>
</Rectangle.Style>
</Rectangle>
</Button.Content>
</Button>
you are close. instead of setting <Rectangle.Fill> locally, use Style setter:
<Rectangle x:Name="aaa" >
<Rectangle.Style>
<Style TargetType="{x:Type Rectangle}" >
<Setter Property="Fill">
<Setter.Value>
<ImageBrush ImageSource="pack://application:,,,/AssemblyName;component/Resources/Img1.png" />
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding Text.Length, ElementName=SearchTextBox}" Value="0" >
<DataTrigger.Setters>
<Setter Property="Fill">
<Setter.Value>
<ImageBrush ImageSource="pack://application:,,,/AssemblyName;component/Resources/Img2.png" />
</Setter.Value>
</Setter>
</DataTrigger.Setters>
</DataTrigger>
</Style.Triggers>
</Style>
</Rectangle.Style>
</Rectangle>
it is necessary because Trigger cannot override local value

Hid parts of user control based on data source in wpf

I have a user control which contains 2 shapes, an ellipse and rectangle. What I want to do is hide the rectangle if the data source I'm binding to is set to false, and visible if true. The same for the ellipse.
So in my case how can I set the visibility of the ellipse based on the ismale bool. Also set the rectangle visibility based on isFemale bool?
User Control
<UserControl>
<Grid HorizontalAlignment="Center" VerticalAlignment="Center"
MinWidth="200" MinHeight="120">
<Rectangle Fill="Gray" Margin="5" />
<Ellipse Fill="Red" Margin="5" />
</Grid>
</UserControl>
Pseudo code for class object I'm data binding to in my mvvm setup.
class Person
{
public bool IsMale {get;set;}
public bool IsFemale {get;set;}
public string Name {get;set;}
}
You can simply use DataTrigger for each Style of the shape.
<UserControl>
<Grid HorizontalAlignment="Center"
VerticalAlignment="Center"
MinWidth="200"
MinHeight="120">
<Rectangle Fill="Gray" Margin="5">
<Rectangle.Style>
<Style TargetType="Rectangle">
<Setter Property="Visibility" Value="Collpased"/>
<Style.Triggers>
<DataTrigger Binding="{Binding IsFemale}" Value="True">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Rectangle.Style>
</Rectangle>
<Ellipse Fill="Red" Margin="5">
<Ellipse.Style>
<Style TargetType="Ellipse">
<Setter Property="Visibility" Value="Collpased"/>
<Style.Triggers>
<DataTrigger Binding="{Binding IsMale}" Value="True">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Ellipse.Style>
</Ellipse>
</Grid>
</UserControl>
Also, note that the DataContext of the UserControl must of of type Person object.

WPF Button change Rectangle.OpacityMask when disable

I am not able to manage a solution for my problem.
Here is my Button
<Button BorderBrush="Black" IsDefault="True" IsEnabled="{Binding ContentManager.CanPreview}" x:Name="Preview" Grid.Column="1" Style="{DynamicResource MetroCircleButtonStyle}">
<Button.ToolTip>
<ToolTip>
<StackPanel>
<TextBlock FontWeight="Bold">Preview</TextBlock>
<TextBlock>Preview the selected document</TextBlock>
</StackPanel>
</ToolTip>
</Button.ToolTip>
<Rectangle Margin="1,0,0,0" Width="17" Height="12" Fill="Black">
<Rectangle.OpacityMask>
<VisualBrush Stretch="Fill" Visual="{StaticResource appbar_eye}" />
</Rectangle.OpacityMask>
<Rectangle.Style>
<Style>
<Style.Triggers>
</Style.Triggers>
</Style>
</Rectangle.Style>
</Rectangle>
</Button>
My question is how can I set my trigger to change the <VisualBrush Stretch="Fill" Visual="{StaticResource appbar_eye}" /> when the button is not enable.
Create a Style that targets Rectangle class, move OpacityMask to Style as Setter, otherwise Style.Trigger won't be able to change local value, and create a Trigger on IsEnabled property being false to change OpacityMask to a different Brush
<Rectangle Margin="1,0,0,0" Width="17" Height="12" Fill="Black">
<Rectangle.Style>
<Style TargetType="{x:Type Rectangle}">
<Setter Property="OpacityMask">
<Setter.Value>
<VisualBrush Stretch="Fill" Visual="{StaticResource appbar_eye}" />
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="OpacityMask">
<Setter.Value>
<!-- other brush -->
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
</Rectangle.Style>
</Rectangle>
Maybe add the other visual brush as resource to your usercontrol/window/app
<Style.Resources>
<VisualBrush x:Key="otherBrush" Stretch="Fill" Visual="{StaticResource other_appbar_eye}" ></VisualBrush>
and use it in the trigger like this
<Rectangle.Style>
<Style TargetType="Rectangle">
<Style.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="OpacityMask" Value="{StaticResource otherBrush}"/>
</Trigger>
</Style.Triggers>
</Style>
</Rectangle.Style>
and move the default value to the style as well, since you´re not able to change it via trigger otherwise.

Categories