I have WPF application with a couple of buttons on which there's no text, only a vector-based image (using a Path object), the ControlTemplate looks like this:
<ControlTemplate x:Key="IconButtonContentTemplate" TargetType="{x:Type ButtonBase}">
<Grid Background="{Binding Background, RelativeSource={RelativeSource AncestorType={x:Type ButtonBase}, Mode=FindAncestor}}">
<Path HorizontalAlignment="Center" VerticalAlignment="Center"
Width="{Binding ActualWidth, RelativeSource={RelativeSource AncestorType={x:Type ButtonBase}, Mode=FindAncestor}}"
Height="{Binding ActualHeight, RelativeSource={RelativeSource AncestorType={x:Type ButtonBase}, Mode=FindAncestor}}"
Data="{Binding (components:ImageButtonAttachedProperties.ImagePathData), RelativeSource={RelativeSource AncestorType={x:Type ButtonBase}, Mode=FindAncestor}}"
Stretch="Uniform" Fill="{Binding Foreground, RelativeSource={RelativeSource AncestorType={x:Type ButtonBase}, Mode=FindAncestor}}" />
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Foreground" Value="LightGray" />
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Foreground" Value="LightGray" />
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Foreground" Value="Gray" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<Style TargetType="{x:Type Button}" x:Key="ClockButtonStyle" BasedOn="{StaticResource IconButtonStyle}">
<Setter Property="Template" Value="{StaticResource IconButtonContentTemplate}" />
<Setter Property="Foreground" Value="White" />
<Setter Property="components:ImageButtonAttachedProperties.ImagePathData" Value="M69.349,65.092C68.714,65.092,68.072,64.925,67.487,64.577L46.294,51.946 46.294,21.239C46.294,19.227 47.925,17.595 49.938,17.595 51.949,17.595 53.581,19.227 53.581,21.239L53.581,47.807 71.217,58.317C72.945,59.348 73.512,61.585 72.483,63.312 71.799,64.457 70.589,65.092 69.349,65.092z M49.938,3.877C24.573,3.877 3.938,24.513 3.938,49.877 3.938,75.241 24.573,95.877 49.938,95.877 75.302,95.877 95.938,75.241 95.938,49.877 95.938,24.513 75.302,3.877 49.938,3.877z M52.876,88.467C52.882,88.395 52.897,88.324 52.897,88.25 52.897,86.615 51.572,85.29 49.937,85.29 48.302,85.29 46.977,86.615 46.977,88.25 46.977,88.324 46.994,88.395 46.999,88.467 27.994,87.032 12.783,71.822 11.349,52.817 11.423,52.822 11.492,52.838 11.567,52.838 13.202,52.838 14.527,51.513 14.527,49.878 14.527,48.243 13.201,46.918 11.567,46.918 11.492,46.918 11.422,46.935 11.349,46.94 12.783,27.933 27.994,12.722 47,11.287 46.995,11.36 46.978,11.43 46.978,11.504 46.978,13.139 48.304,14.464 49.938,14.464 51.572,14.464 52.897,13.138 52.897,11.504 52.897,11.429 52.881,11.36 52.876,11.287 71.882,12.722 87.093,27.932 88.528,46.938 88.455,46.933 88.385,46.916 88.311,46.916 86.676,46.916 85.35,48.242 85.35,49.876 85.35,51.51 86.676,52.836 88.311,52.836 88.385,52.836 88.455,52.82 88.528,52.815 87.094,71.822 71.883,87.032 52.876,88.467z" />
</Style>
My issue is that on very rare occasions the button image is not shown (99% of the time it does). The button can still be clicked, but the image on it is not shown.
I'm not sure what's causing this. The data binding on the vector image? Or the data binding on the fill color?
ImageButtonAttachedProperties.ImagePathData is System.Windows.Media.Geometry object, which describes the vector-image.
public static class ImageButtonAttachedProperties
{
public static readonly DependencyProperty ImagePathDataProperty =
DependencyProperty.RegisterAttached("ImagePathData", typeof(Geometry), typeof(ImageButtonAttachedProperties), new UIPropertyMetadata(null));
public static Geometry GetImagePathData(DependencyObject obj)
{
return (Geometry)obj.GetValue(ImagePathDataProperty);
}
public static void SetImagePathData(DependencyObject obj, Geometry value)
{
obj.SetValue(ImagePathDataProperty, value);
}
}
Any idea what I'm doing wrong here?
You're binding the desired dimensions of a template element to the final dimensions of the templated parent; this creates a circular dependency. Don't do that.
The size of the templated control (e.g., your Button) depends on the desired size of its template content (e.g., your Path). If you make the size of the content dependent on the size of the templated parent, you're just asking for trouble.
If I had to guess, you may be getting caught in a layout loop, where one layout update triggers another to occur on the next tick. These aren't always obvious (except, perhaps, by looking at CPU usage), because of the way layout updates are scheduled. I've seen this happen before, e.g., when the 'Arrange' pass invalidates the results of the 'Measure' pass. The visible effects can be rather unpredictable: sometimes things appear to be working fine, until they don't.
Get rid of the Width and Height bindings on your Path, and set the horizontal and vertical alignments to Stretch.
You should:
1) Remove the databinding on the fill color to determine if you can still re-produce the problem.
I you cannot, try it the other way around:
2) Remove the databinding on the Path (use a constant Path for testing) and test with the databinding on the fill color.
If 1) and 2) could not reproduce your problem then try:
3) Use constant values on the fill color and the databinding on the Path
If you were able to re-produce the problem in 1) or 2) you now know at least the source of the problem. The same is true for 3) but it is more complicated because 3) implies that both databindings somehow influence each other ...
4) Its also possible that your problem is burried deeper in your themes defintion - so switching custom themes off and using only Generics themes is also a way to test in order to learn the source of the issue.
5) I would also try to layout the Path on the Background of the Button to see if this behaves better with regard to your problem - see my last comment in this post:
Image fill the space on the button in WPF
You really need to post a small demo app to get a deterministic answer, otherwise, I am afraid that it is impossible to tell the exact source given only the snippets shown
I'm not sure what's causing this.
At some point the values of either ActualWidth or ActualHeight (on any control) are actually zero and those properties are read only type dependency properties. That happens when the control is Loaded, Measured, Arranged, or Rendered.
As per the FrameworkElement.ActualWidth Property
Because ActualWidth is a calculated value, you should be aware that
there could be multiple or incremental reported changes to it as a
result of various operations by the layout system. The layout system
may be calculating required measure space for child elements,
constraints by the parent element, and so on.
The question is that something is jiggering your button and causing a resize and you win the lottery by catching a zero value.
As a course of something to try, I provided an answer about housing a vector image Best way to use a vector image in WPF in two different ways, and the example I used had 3 vectors in a resizable window and to my knowledge they didn't flash except to redraw. But I had the height/width set to stretch.
Maybe change how the vector is held?
There's a custom touchscreen keyboard in my app built according to this: https://www.codeproject.com/Articles/32568/A-Touch-Screen-Keyboard-Control-in-WPF.
I also have a ResourceDictionary containing all styles and templates. In the TextBox style, I can set the keyboard ON/OFF:
<Style TargetType="{x:Type TextBox}">
<Setter Property="FontSize" Value="14" />
<Setter Property="Padding" Value="4" />
<Setter Property="k:TouchScreenKeyboard.TouchScreenKeyboard" Value="True"/>
</Style>
I would like the user to be able to turn it on or off from the UI, but can't figure out how to reach this property from code behind. I would like to make it without naming the style, since it's pretty commonly used throughout the app.
I tried this, but (no surprise) get ArgumentNotFoundException:
Style s = Application.Current.FindResource("defTextBox") as Style;
s.RegisterName("Keyboard.TouchScreenKeyboard.TouchScreenKeyBoard",false);
Any help would be appreciated!
You shoud be able to set the TouchScreenKeyboard attached property for an individual TextBox like this:
TouchScreenKeyboard.SetTouchScreenKeyboard(textBox1, false);
Changing the defintion of the implicit Style itself after it has already been applied to all TextBox elements doesn't make much sense though. You should define the default value in XAML and then change the value for individual TextBoxes dynamically at runtime if you need to.
I want to create a custom styled header for WPF DataGrid, but I don't know if it is possible to do what I want, and if it is how exactly should I do.
The sketch of the DataGrid is on the linked picture. The Purple header extends beyond the edge of the DataGrid and it has a little 3D bending.
DataGrid
Can I do something like this with WPF DataGrind and if yes how do I start?
Thanks!
DataGrid allows for ColumnHeaderStyle, CellStyle and many more styles to bet set. Right click DataGrid control in designer view > View Additional Templates will show you the complete list.
You have to use the following :
<Style x:Key="DataGridColumnHeaderStyle1" TargetType="{x:Type DataGridColumnHeader}">
<Setter Property="Background" Value="Orange"/>
<Setter Property="FontSize" Value="20"/>
<Setter Property="Padding" Value="5"/>
<Setter Property="BorderBrush" Value="Red"/>
<Setter Property="BorderThickness" Value="0 0 3 0"/>
</Style>
This will change the column headers. And if you want to change cells too, you can provide styles for DataGridCell too.
Use Snoop tool to peek inside a DataGrid first and peek into it to see what it looks like at runtime. This will clear many of your concepts.
It is possible, but it is a lot of work and requires very good knowledge of writing WPF templates. What you essentially want to do is replace the templates for DataGrid, and all other DataGrid related conotrols such as the DataGridRow, etc
Microsoft provide a full example of how to do this here: https://msdn.microsoft.com/en-us/library/vstudio/ff506248(v=vs.100).aspx
One can edit Foreground and Background etc... for a Button's default state without Blend using just the properties pane or code, but it is it possible to edit the colors for the other states without Blend?
For example, all I want is a button to turn gray on "Mouse Over". Anything I have seen on Stack Overflow or on the Intertubes uses Blend. I want to do it without it. Is it possible?
An easy way to do this is using Style Triggers.
<Style x:Key="HoverButtonStyle" TargetType="{x:Type Button}">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="Gray"/>
</Trigger>
</Style.Triggers>
</Style>
The style is defined in your Resources. And then when you define your button in XAML, you assign the style, like this:
<Button x:Name="MyButton" Style="{DynamicResource HoverButtonStyle}"/>
This style will change the Background brush of your Button when the mouse is over it. There are many more advanced things you can do with triggers, but this is a very simple example. If you google WPF Style Triggers, you'll find many examples, including this one which is pretty thorough.
There are other ways to do this, for example using the VisualStateManager, as described here, however if you're just trying to change the Background on hover, a style trigger is probably the simplest way.
I want my WPF application to be skinnable, by applying a certain XAML template, and the changes to be application wide, even for dynamic controls or controls that aren't even in the visual/logical tree.
What can I use to accomplish this type of functionality? Are there any good resources or tutorials that show how this specific task can be done?
The basic approach to take is using resources all through your application and dynamically replacing the resources at runtime.
See http://www.nablasoft.com/alkampfer/index.php/2008/05/22/simple-skinnable-and-theme-management-in-wpf-user-interface/ for the basic approach
The replacing of resource will work but I found "structural skinning" to be more powerfull! Read more about it on CodeProject...
http://www.codeproject.com/KB/WPF/podder1.aspx
I have found the way to apply generic templates to all controls without using template keys. The solution is to use the type of the control as the Style key.
Example:
<Application.Resources>
<Style x:Key="{x:Type Button}" TargetType="{x:Type Button}">
<Setter Property="Button.Background" Value="CornflowerBlue"/>
<Setter Property="Button.Template">
<Setter.Value>
<ControlTemplate x:Name="MyTemplate">
...
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Application.Resources>
here the Style key is x:Key="{x:Type Button}", so the style will be applied to all controls of type button without the control declaring the Style property to be a static or dynamic resource.