How to change style for a single LayoutDocument? - c#

Suppose I have this xaml:
<avalonDock:DockingManager>
<avalonDock:LayoutRoot>
<avalonDock:LayoutPanel Orientation="Horizontal">
<avalonDock:LayoutDocumentPaneGroup>
<avalonDock:LayoutDocumentPane>
<avalonDock:LayoutDocument Title="Main Panel">
</avalonDock:LayoutDocument>
</avalonDock:LayoutDocumentPane>
<avalonDock:LayoutDocumentPane>
<avalonDock:LayoutDocument Title="Panel 02">
</avalonDock:LayoutDocument>
</avalonDock:LayoutDocumentPane>
<avalonDock:LayoutDocumentPane>
<avalonDock:LayoutDocument Title="Panel 03">
</avalonDock:LayoutDocument>
</avalonDock:LayoutDocumentPane>
<!--
Other LayoutDocumentPane's here...
-->
</avalonDock:LayoutDocumentPaneGroup>
</avalonDock:LayoutPanel>
</avalonDock:LayoutRoot>
</avalonDock:DockingManager>
Now I need put a different style only for "Main Panel", by example, a red background. All other panels ("Panel 02", "Panel 03", etc...) must be unchanged. All samples I found are to change the entire theme, but I need change only one LayoutDocument element.

You need to use DataTemplates, TemplateSelector, or Converters and you need to give them something that can differantiate between the items you want to change and those you do not want to change.
A WPF Converter on the style property could, for example, use the Title (if its unique across your app) to return a corresponding style for each document. But this would be a very poor implementation - use an enumeration property in the class to make this one more robust.
An even better solution is the usage of a TemplateSelector based on a class hierarchy of inherating classes over your document viewmodel - but this is more involved - but there are some samples to look at: Here is one that does the same for LayoutAnchorables.

You might simply change the Style of LayoutDocument adding a DataTrigger that would change background color basing on a property set on your ViewModel.
That property should be set to true (if the logic behind is binary but should be more complex if needed) just on the ViewModel of your MainPanel.
Please have a look to the Theme.xaml of AvalonDock and search for <Style TargetType="{x:Type avalonDockControls:LayoutDocumentTabItem}">. Inside that style you can easily access The ViewModel binded to any TabItem by simply access {Binding LayoutItem.Model.<my_property>

Related

Do I need dependency properties for all basic properties on my user control?

I am currently writing my first user control which would consist of a label and a text box in a stack panel like follows:
<Grid>
<StackPanel Orientation="Horizontal" DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Label Content="{Binding Label}" Width="60"></Label>
<TextBox Text="{Binding TextBoxContent}" Width="60"/>
</StackPanel>
</Grid>
This will be most useful to be in a settings page, as it will be reused for several different settings. With each of these settings, I will want to set (at a minimum) the width, height, validation rule and error template properties. As for the text itself, I have already created a dependency property both for the label and the text box (as you can see in my snippet above).
My question is this: Do I need to create a dependency property for all of the properties I just mentioned that I would like to set when I actually use my user control? This seems like redundant work (since they already exist on the text box, basically they would just redirect my user control's property to the text box's property of the same name)? This is even more work if I want to use even more properties on my text box (for example, AcceptsReturn, etc).
The redundant work can be saved if you decide to derive from TextBox rather than UserControl - just think of your control as a "labeled textbox" and all you need to do is derive from TextBox and add the needed dependency properties to accommodate for the label. This of course would not be the case for more complex user controls, but it seems OK in your case.
The downside to this though is that you'll have to take the default control template for TextBox and work with it to add your label, which may be a bit trickier.
Either way, I recommend having a look at the Control Authoring Overview page on MSDN, which is extremely useful when writing your first controls in WPF.

Set an existing control template as Content Property in WPF Code Behind

I have a very simple XAML
Visibility="Collapsed" X1="1" Margin="-35 0 0 0" Y1="0.4">
<Label.Content>
<Slider Grid.Column="0"
Width="20"
Height="65"
IsDirectionReversed="True"
Maximum="0.1"
Minimum="-4"
Orientation="Vertical"
x:Name="Slider1"
Value="{Binding Source={x:Reference scaleFactorModifier},
Path=ZoomScaleFactor, Mode=TwoWay}" />
</Label.Content>
</Label>
</SciChart:CustomAnnotation.Content>
</SciChart:CustomAnnotation>
Now for some reason I need to set the CustomControl.Content property from code behind. Is there any possibility I move all the label control to some style and template and set the CustomControl content property at runtime with that particular style or template.
Update
Reason for using Code behind
Actually I have Annotations property in my control which could have any control in it as we required. Previously I had used hard coded annotations in my control and placed the controls manually. Now I want to bind the Annotations property. I could create a property of this type and add CustomAnnotation objects in it. But customAnnotation objects need to have labels and other controls in them, how could I do that?
If I have understood your problem correctly, I believe that you can do what you want by using a DataTemplate and a ContentControl. First, define a DataTemplate with your Label in:
<DataTemplate DataType="{x:Type YourPrefix:YourDataType}">
<!-- define your Label here -->
</DataTemplate>
Then you can set the Content property of your CustomControl to a ContentControl that has its own Content property set to an instance of an object of type YourDataType:
<ContentControl Content="{Binding InstanceOfYourDataType}" />
I'm aware that you want to do this programmatically, but that's easy enough to work out:
ContentControl contentControl = new ContentControl();
contentControl.Content = instanceOfYourDataType;
yourCustomControl.Content = contentControl;
I'm wondering if you even really need to use your CustomControl at all, but I'll leave that up to you.
I create a user control from that xaml and then set the CustomControl.Content as new instance of user control. This might not be the best solution, but this is all that I have for now.

DataContext in WPF

I am trying the following in my WPF application:
Structure of XAML elements.
DataTemplate[Data Type 'A']
Grid
Broder
TextBlock
I want to bind the text block's text property to a "string" which is derived from my "Users" class which is referenced in the resource dictionary of the XAML.
So in the above structure since the DataTemplate gets the feed from data type 'A'.
I want to assign the datacontext(Users) to the grid and bind the string to the textblock.
Is there a way i can achieve this ,since all my trials which include assigning the datacontext to the Grid or Border or TextBlock doesn't work.
Can any one suggest me or correct me if my approach is wrong here ?
This markup should suffice:
<DataTemplate DataType="{x:Type local:A}">
<Grid DataContext="{Binding Path=Users}">
<Border>
<TextBlock Text="{Binding Path=PropertyOnUsers}"/>
</Border>
</Grid>
</DataTemplate>
Make sure you have the namespace declared at the top of your Xaml. For whatever reason, WPF doesn't always automatically infer the template from the type if you don't use {x:Type ...}.
From there it should be straight forward.
If Users is a collection, you will have to drill into the collection to get a specific instance of User.
By the way, if you are using Visual Studio, you can use the Output window to debug binding issues.

Accessing inner controls of UserControl

I am building a custom UserControl which would allow me to place text inside a ProgressBar. The problem is, none of the ProgressBar's DependencyProperties get transferred over. Here is the XAML for my custom UserControl.
<UserControl
x:Class = "MyProgram.MyCustomProgressBar"
xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml" >
<Grid>
<ProgressBar Name="uiProgressBar" />
<Label Name="uiLabel" />
</Grid>
</UserControl>
How can I access and set the Minimum, Maximum, Value, etc. from XAML when I start using this UseControl.
<local:MyCustomProgressBar x:Name="uiLoadTime" ??.uiProgressBar.Maximum="50" />
I am hoping I don't need to redefine a bunch of DependencyProperties in order to get this functionality.
The usual way is to use a DependencyProperty... it's not so bad once you got used to it really.
Use the "propdp" built in snippet in the code-behind of your usercontrol.
Let's take the ProgressBar.Maximum example:
Make an integer dependencyproperty with a default value of 100 (or whatever you like), name it InnerProgressBarMax.
In your UserControl's XAML, you bind it this way:
<ProgressBar Maximum="{Binding InnerProgressBarMax, ElementName=myUsrCtrl}" />
When you use the control in another part of your application, simply enter a value like this:
<local:MyCustomProgressBar x:Name="uiLoadTime" InnerProgressBarMax="50" />
Rinse & repeat for each property you want to expose.
Edit:
If you really need to have 50+ DP exposed, you could bring down the hastle by specifying smart default values for your DPs.
To do that, when you create a DP, set the parameter of new PropertyMetadata(YOUR_DEFAULT_VALUE)
Once that is done, your control may expose many DPs, but you'll only have to set a few manually in the XAML code that uses the control.
The alternative to wrapping everything in DependencyProperties is to let the UserControl's consumer provide the ProgressBar. It could look like this:
<local:MyCustomProgressBar x:Name="uiLoadTime">
<local:MyCustomProgressBar.ProgressBar>
<ProgressBar Maximum="50" />
</local:MyCustomProgressBar.ProgressBar>
</local:MyCustomProgressBar>
Then in MyCustomProgressBar.xaml.cs, you would expose a public property for a ProgressBar. In its setter, modify the properties however you see fit, then add it to the UserControl's root Grid.

Binding in DynamicResource ResourceKey wpf mvvm

I want to bind the style of button on the basis of if else condition. I have created one string property in the viewmodel and bind to the button's style attribute like this:
<Button x:Name="copd" Content="COPD"
Command="{Binding COPDReadingsCommand}"
Style="{DynamicResource ResourceKey={Binding CheckCopd}}"
HorizontalAlignment="Center" VerticalAlignment="Center"
Margin="20" FontWeight="Bold" />
I am looping through the resourceDictionary and getting all the keys. Using if else i am changing the string property value(CheckCopd) in if else.
I am getting the desired values in if else but style is not getting applied to the button when I execute my application. It only displays the generic button style.
How to bind the DynamicResource ?
Kindly Suggest?
Thank You.
You cannot use bindings on the DynamicResource properties, as it does not derive from DependencyObject. You would either need to set the Style property directly from code-behind, or just use a Binding.
You could use a Style for the Button type, which has a DataTrigger based on a custom property that dynamically changes the look. But in this case, you need a single Style, which changes it's setters based on your condition. It would not allow you to change the Style property itself dynamically.
You can try this... I came up with a way to create a DynamicResourceBinding on which you can use a converter to achieve the results you want. (You theoretically could also just use styles and triggers, but I digress...)
How do you create a DynamicResourceBinding that supports Converters, StringFormat?

Categories

Resources