Accessing elements in a xaml defined style - c#

I have followed the DiagramDesigner example on Codeproject for learning how to use Adorners in WPF as it fits quite a few of my needs relatively closely.
I have adapted the implementation a little, and also added my own adorner, for controlling the opacity of a control via a slider (slider on the adorner).
Following the same methods as the author, I placed the slider and other feature in a xaml style definition file as below. I am just now struggling A) to figure out how to access the slider at any level, B) how best to start hooking this up with an underlying Viewmodel that will be used for various settings (on adorners).
<Style x:Key="OpacityAdorner" TargetType="{x:Type adorners:OpacityChrome}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type adorners:OpacityChrome}">
<Grid>
<Slider x:Name="OpacitySlider" Style="{StaticResource OpacityControl}" ToolTip="Alter the opacity of the image to overlay with other images" Visibility="Collapsed"/>
<Ellipse x:Name="OpacitySliderEnable" Style="{StaticResource OpacityIcon}" ToolTip="Alter the visual opacity of the image" Visibility="Visible"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
The codeproject example is here http://www.codeproject.com/Articles/22952/WPF-Diagram-Designer-Part

A) Use something like the following snippet to get the slider from the applied template.
var slider = opacityAdorner.Template.FindName("OpacitySlider", opacityAdorner) as Slider;
there are cases where the template has not yet been applied, in that case you need to preceed the previous call with the following:
opacityAdorner.ApplyTemplate();
B) The best approach for hooking up with the view model (in my opinion) is to expose the required properties as dependency properties on the OpacityChrome adorner. You then use normal Binding to hook up the new properties to the view-model, and TemplateBinding to hook them up to the template elements.

Related

WPF Override Style Value

I'm using MaterialDesignInXaml for WPF which provides 3rd party controls and styles. I need to edit one of these styles by changing one property.
I am using an Expander control which has a template creating a bunch of child controls. I've discovered the child 'Border' control (4 layers deep) has the property (padding) which I need to set to zero.
See this output from Snoop showing the property I need to change:
Link to image
My question is how can I do this? I've tried extending the style used by the control as follows, but it isn't changing anything so I assume I'm doing something wrong?
<Style TargetType="{x:Type Expander}"
x:Key="MaterialDesignExpanderHeadless"
BasedOn="{StaticResource MaterialDesignExpander}">
<Style.Resources>
<Style TargetType="{x:Type Border}">
<Setter Property="Padding" Value="0"></Setter>
</Style>
</Style.Resources>
</Style>
I am able to use the style like this. And I know this is working for sure:
<Expander Header="Header Content" Style="{StaticResource MaterialDesignExpanderHeadless}">
Some Content
</Expander>
You're right, this method should work. Something else is setting the border's padding.
Snoop is telling you the padding is defined by the parent template, which could be the HeaderSite (ToggleButton).
You could try to extend the ToggleButton style (BasedOn) or redefine it locally.

Update custom control Width and Height property using AdaptiveTriggers

I try to find how I can update the Width and Height properties of my custom control.
I have used the RadialProgressBar implementation found in UWP Community Toolkit pull request #828 for 1.5 milestone.
I can set the Width and Height on the custom control and it will work but I need to set different Width and Height values depending on the display resolution.
RadialProgressBar.xaml
RadialProgressBar.cs
Page.xaml
I'm doing something wrong I think but I can't find what.
Any idea?
I found the solution in the answer to this question UWP XAML Change Style of a target with VisualStateManager.
I need to put the VisualStateManager in the Template of the control.
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:RadialProgressBar">
<Grid x:Name="Grid">
<!-- Put the VisualStateManager definition here -->
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
I have updated RadialProgressBar.xaml file in my gist.

WPF Template Binding with more than 1 content

So, I have this Window. On it, I'm creating a list of TextBlocks and TextBoxes in pairs. When you click on either, they will put a number in the corresponding TextBox, and set some values in the background. This all works well now.
I have the following XAML to create a custom Checkbox (as it has the behavior I'd like to use for this). My problem is that I want to bind different content into both the TextBlock and TextBox. For the TextBlock, I bound to the Content property, but I can't find a suitable option to satisfy the second binding. I considered placing it in the tag, but this didn't feel right, and in any case, I'm already binding an index value I require into there.
<Style x:Key="CustomCHK" TargetType="{x:Type CheckBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type CheckBox}">
<DockPanel LastChildFill="True">
<TextBox DockPanel.Dock="Right" Width="50" Height="30" />
<TextBlock Text="{TemplateBinding Content}" TextWrapping="Wrap" />
</DockPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Feels like there should a simple solution to this, but I'm just trying to decide what's best. Do I create a custom checkbox class and just add a couple properties?
As always, I appreciate any direction you can offer me.
Unfortunately, there is no straightforward way to do this. I can see just two (somewhat flawed) workarounds:
Subclass CheckBox to suit your needs, and add the additional content properties that you need. The advantage is that this will fully enable your IDE's programming help for setting the content properties, and those properties will be typesafe. The downside is that your will need to add C# code for the sole purpose of declaring the additional content properties (i.e. without adding any "behavioral logic"), which somehow seems to conflict with a "clean" XAML-only for presentation approach.
You could try passing an array to the Content property, and then place several ContentPresenter instances in your control template, each of which bind to another item in the array. Binding property paths should support indexed access, though your code may become a bit verbose, as arrays in XAML have to be written explicitly by using the x:Array markup extension.

FindResource not working in Custom Control DLL

While I am still learning WPF I have yet run into another problem. I have a DLL which is of type Custom Control. I've implemented my base control and I have several controls which derive from this base; the base control is never used. The problem is whenever I call FindResource or TryFindResource it always fails. I have a separate dictionary that I merged in my Themes/Generic.xaml file:
Gernieric.xaml
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/DllProject;component/Themes/NewResource.xaml" />
<!-- I've tried several other ways for the Source format, i.e. pack:... -->
</ResourceDictionary.MergedDictionaries>
Now I am trying to set the Style of my derived controls in the derived controls constructor without the control being on a visible canvas or panel at the time. I also want to export a VisualBrush of the control as a BitmapSource. All of the code was working when I put my NewResource.xaml in the EXE project (where it doesn't belong). I've read articles on adding a dummy tag to the resource dictionary as well as put all of my code in the Generic.xaml file. Like I said all of this works fin if move the xaml file to the main EXE. Its as if the DLL isn't even loading the xaml file or even aware there is anything declared in it until the control is on a visible window.
I have a style for my base control (NewResource.xaml):
<Style TargetType="{x:Type local:MyDerivedControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:MyDerivedControl}">
<Grid>
<Path x:Name="MyPath" Style="{TemplateBinding DepProp}" />
<TextBlock x:Name="Text" HorizontalAlignment="Center" VerticalAlignment="Center" Text="{TemplateBinding Text}"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
After doing a lot of research on the internet it seems WPF dropped the ball on DLLs and resources.
I found the answer that worked. Basically change the x:Key to contain a ComponentResourceKey. A full description can be viewed here that is straight forward to understand.

Template for basic reusable button

In WPF (VS2013), I'm creating a button like so:
<Button>
<Label>1</Label>
</Button>
Each of these buttons will have more to it, such as increased font size of the Label, grid row/column assignment, and I might use a binding for the label so that I can change the number. I'm creating a calculator app so I need to reuse this button 10 times (one for each number 0-9). Instead of copying/pasting this button XML 10 times, I wanted to see if I could templatize it.
I've read a little about ControlTemplate and DataTemplate, but I'm not sure if either of these are the correct thing to use. It's also not clear to me what should be a style or what should be a template.
So if someone could help me understand how to "templatize" the button and its styles (e.g. width, height, font size, etc) so that they can be easily reused, that would help a ton. Guidance is appreciated!
Use a ControlTemplate when you want to overwrite the entire template for a control, use a DataTemplate when you want to tell WPF how to draw a data object (usually the DataContext), and use ContentTemplate when you want to tell WPF how to draw the Content property of an object.
Creating a whole new ControlTemplate is quite complex. To demonstrate, check out this MSDN example for an example ControlTemplate for a Button.
In your case, I would recommend creating a Style for your button with setters for common properties such as Height, Width, Font, etc. If you want to draw your button's Content property in a custom way without completely overwriting the button template, include a ContentTemplate style setter to tell WPF how to draw the Button.Content property.
<Button Style="{StaticResource CalculatorButton}" Content="1" />
and
<Style x:Key="CalculatorButton" TargetType="{x:Type Button}">
<Setter Property="Height" Value="50"/>
<Setter Property="Width" Value="50"/>
<Setter Property="FontSize" Value="14" />
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock Text="{Binding }" FontFamily="Wingdings 3" FontWeight="Bold" FontSize="18" Foreground="Navy" />
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
The ControlTemplate defines how the button looks, the ContentTemplate defines how the Button.Content looks, and the DataTemplate used for the ContentTemplate is defining how the data object of "1" will be drawn.
You can start with a copy of the style of the button. Use Blend (part of VS) to create that: open the context menu of the button inside the object tree, then select "Edit template" (or similar, don't have an english version at hand), then "Copy of template" (or alike).
Now you may change properties (in designer or XAML). Every button that shall have this style needs to reference this new ressource.
You need to create a new Style of a button. Learning curve is not too steep, but the benefits are enormous. You can start learning about it here: http://msdn.microsoft.com/en-us/library/ms745683(v=vs.110).aspx
Long story short: Open your project with Blend, right-click on your button, "Edit Style", "Edit a copy". If you choose to define it in Application, you can reuse it among other pages (it will be then in you App.xaml file)
Once you have the base style, edit it as much as you need.

Categories

Resources