How to trigger "IsRemoteSession" or "IsSoftwareRendering" in UserControl style? - wpf

We are developing usercontrols with .NET 4 - WPF.
We have a lot of customers who are running our application in a remote session (e.g. Terminal-Server, Citriy, etc.).
Many of the performance issues are already solved. At the moment I'm searching for a way to disable animations in styles and controltemplates depending on the condition of IsRemoteSession and/or IsSoftwareRendering. I will do that without writing a line of code.
I'm pretty sure that I read a blog article some months ago in which it described a way to do that using a trigger in xaml, but I can't find it anymore.
Anyone have any hints....?

The way I would do this is by putting the animations inside the triggers. The code would look something like this:
<Window.Resources>
<Style TargetType="{x:Type WhateverYourTypeIs}">
<Style.Triggers>
<!-- Here I assume your whatever holds your IsRemoteSession property is your DataContext -->
<!-- Otherwise, change your binding -->
<DataTrigger Binding="{Binding Path=IsRemoteSession}"
Value="False">
<!-- Here you use Setters to add your animations -->
</DataTrigger>
</Style.Triggers>
</Window.Resources>

Related

How do I access the styled object from the value of a setter?

I am attempting to style every DataRecordPresenter in a XamDataGrid according to a VisualBrush that should flex according to the presenter in question. Specifically I'm aiming to highlight some rows, where the highlighting pattern is potentially complex (i.e. arbitrarily large, albeit in practice probably not more than 5-6 colours).
The solution I'm hoping to use looks something like this:
<!-- idp bound to namespace for Infragistics DataPresenters -->
<idp:XamDataGrid>
<idp:XamDataGrid.Resources>
<Style TargetType={x:Type idp:DataRecordPresenter>
<Style.Setters>
<!-- THE RELATIVESOURCE FAILS HERE -->
<Setter Property="Tag">
<Grid DataContext={Binding RelativeSource={RelativeSource Mode=FindAncestor,TargetType={x:Type idp:DataRecordPresenter}}}>
<!-- Content that relies on properties of the DataRecordPresenter -->
</Grid>
</Setter>
<Setter Property="Background">
<!-- THE RELATIVESOURCE WORKS HERE -->
<VisualBrush
ViewPort="12,12,12,12"
Visual="{Binding Tag,RelativeSource={RelativeSource Mode=FindAncestor,TargetType={x:Type idp:DataRecordPresenter}}"
>
</VisualBrush>
</Setter>
</Style.Setters>
</Style>
</idp:XamDataGrid.Resources>
</idp:XamDataGrid>
The issue is that whilst I am able to identify the DataRecordPresenter when constructing the actual VisualBrush (tested using Snoop - as intended the result is the contents of the Tag property), whilst trying to find the same object via the same mechanism from the context of the setter for the Tag property, I fail to identify any such ancestor.
I suspect this is because the Tag property is not associated with the visual (or logical) trees, whereas Background is, but I haven't managed to come up with a solution as yet that addresses the issue. I'd equally be happy to move the Grid into the VisualBrush, but I believe a VisualBrush is also detached from the relevant trees, so I don't think that'll work, or at least not with a simple inline definition.

WPF style in Application resources

I have a style in application resources which I want to apply to many different pie charts. The style looks like this:
<Style x:Key="aaa" TargetType="{x:Type nm:CustomChartControl}">
<Setter Property="..." Value="..." />
<!-- etc -->
<nm:CustomChartControl.Series>
<nm:PieSeries /> <!-- PROBLEM -->
</nm:CustomChartControl.Series>
</Style>
There is a lot more properties which I exluded for simplicity. This all works well. Now, some of my pies need to have a different "model" for paitning background for a slice (ex dashed), and this is were the problem occurs.
When I set a model (at runtime) for nm:PieSeries in a particular chart, then this model is also applied to all other pies that are shown in application. As if there is only one instance of that is used by all pies that applied the style.
Is there some way I can tell it to create a new instance of nm:PieSeries each time a Style is applied to new control?
You might try creating the PieSeries as a separate, non-shared resource:
<nm:PieSeries x:Shared="False" x:Key="NonSharedPieSeries" />
And then use that resource in the style:
Value="{Binding Source={StaticResource NonSharedPieSeries}}"
(...and thanks OP for correcting my error in how to bind it to Value).

Apply a style to multiple controls without using a key

In .NET WPF, I have the following XAML code:
<StackPanel>
<StackPanel.Resources>
<Style TargetType="FrameworkElement">
<Setter Property="Margin" Value="5" />
</Style>
</StackPanel.Resources>
<CheckBox>Check 1</CheckBox>
<TextBox>Some text...</TextBox>
</StackPanel>
The controls do not have any margins applied to them.
Is it possible to apply a style to multiple controls (of different types) without using a key to set the style explicitly on each control?
Styles are not inherited, you can base the subclasses' styles on that one though using BasedOn.
Another method in this case should be using an ItemsControl with an ItemContainerStyle set to this style.
There are examples for both methods in this answer.
Sorry, I misread the question before I wrote this out. My answer is useful if you want to style multiple checkboxes within the StackPanel.
Implicitly style the entire application by placing this into your app.xaml's merged dictionaries.
<Style TargetType="CheckBox" BasedOn="{DynamicResource YourBaseStyle}"/>
This also works on a much smaller scope. Reducing the scope to just that StackPanel simply requires that you add that same line of code to your StackPanel.Resources tag.

WPF Dynamic GUI elements

In WinForms it was relatively easy to swap out Panels at runtime for other panels. In WPF this seems to be rather more complex (especially from XAML).
Can anyone provide clear guidance on the 'best practice' way of swapping gui elements at runtime (think pages in a wizard type situation).
Many thanks.
This can be approached in XAML using datatemplates and/or triggers. For example, if each page in your wizard were represented in an underlying model as a separate class or object, you could use one of the following two options... Both use a ContentControl, which is the perfect control for when the content will vary greatly between different views of the same data.
Please note that the bindings are intended as pseudocode examples, just to convey intent!
DataTemplate-based, using different classes for each page:
<Grid>
<Grid.Resources>
<DataTemplate DataType="{x:Type WizardPageOne}">
<!-- page 1 layout here -->
</DataTemplate>
<DataTemplate DataType="{x:Type WizardPageTwo}">
<!-- page 2 layout here -->
</DataTemplate>
<!-- ... etc -->
</Grid.Resources>
<ContentControl Content="{Binding CurrentPageModel, Source=Wizardmodel}" />
</Grid>
Or Trigger based, using a property that indicates the current page:
<ContentControl Content="{Binding WizardModel}">
<ContentControl.Style>
<Style>
<Style.Triggers>
<DataTrigger Binding="{Binding CurrentPageIndex} Value="1">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<!-- page 1 layout here -->
</ControlTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
<DataTrigger Binding="{Binding CurrentPageIndex} Value="2">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<!-- page 2 layout here -->
</ControlTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
<!-- .... etc -->
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
Both options will only load the control for each page as it's required, so you don't have all of the controls "loaded but hidden" in the window.
The underlying concepts of WinFomrs and WPF is different. In WPF it is not advisable to play around with UIElements(Controls) directly. Make use of DataBinding/DataContexts and just operate on the data and then the UI will function accordingly. This concept is all about WPF MVVM pattern. You can look in to some MVVM samples and try it before doing more complex WPF projects.
A simple example, Suppose you need to dynamically disply a number of items in a ListBox, The typical winform way to do this is to create Items and add directly to the ListBox. But in WPF you create an ObservableCollection<Customer> and bind that to the ListBox.ItemsSource. then define a DataTemplate for Customer Data Type, this ensure the WPF system to understand how a Collection of Customers being displayed in the application. So when you add a new customer instance to the collection, magically your ListBox will get updated with one more item. Seems pretty straight forward and a very loosely coupled way of Data and View right?.
Best wishes on your WPF learning. -
http://www.bing.com/search?q=WPF+MVVM
So the high level clue to your question is, make the View appropriately for the Data and when Data/Property Change happens, WPF will take care of changing the Panels/Controls. So it is really simple than WinForms way when you approach from the Data and View perceptive.
A couple options come to mind. If you create your components as UserControls, and make use of Data Binding, then you should be able to do what you need with minimal fuss.
Option one is to load each component into your parent container (grid, canvas, whatever) with Visibility="Collapsed", and then show and hide them as needed. This has the advantage that you can do this declaratively in XAML.
The other option is to load the components as you need them, so in the event handler of a button, or some other UI element. In this case you would probably want to remove the current displaying item from the Children collection of your host component, and then instantiate your next control, set the DataContext (this is why binding is important), and add it to the Children collection.
(disclaimer: this is based on my experience doing basically what you are asking in Silverlight 3.0, so there may be some WPF quirks I am unaware of).
The MVVM suggestions here are all good. But if you're designing a page-oriented UI that needs to be navigable, you can use Structured Navigation, too.
I got no idea if this is considered good practice, but what we did on one of our project is quite simple. We defined panels that were all on top of each other and would simply set the visibility to either hidden or visible when it was needed.

How to use MultiDataTrigger to check a single condition to be true in Style.Triggers in WPF?

I have three grids in my UserControl of which one control is shown at time. In the last column I need to use a Style where I need to check the data and apply a ForeGround color. I can write style at each of the control in 3 grids using DataTriggers. But I want a concrete style in Resource which can be used anywhere. I tried MultiDataTrigger but it doesn't serve my purpose as it checks 2 or more Condintions to be true in MultiDataTrigger.Conditions whereas i need to check data in a single control. Are there any alternate solution to achieve this?
If you're using some kind of a grid, you're probably using CellTemplate or some other property like that to accomplish your task. I think you do need to use different styles in different columns.
But if those styles are the same except for the triggers, then you can make one style with everything that's common to both of them, and then create another style based on the first one. It's a bit similar to inheritance in OOP.
This is how it may look like:
<Style x:Key="BaseStyle" TargetType=".....">
<!-- Common setters and triggers -->
<Setter ... />
<Setter ... />
<Setter ... />
</Style>
<Style x:Key="InheritedStyle" BasedOn="{StaticResource BaseStyle}" TargetType=".....">
<!-- This style's specific setters and triggers -->
<Setter ... />
<Style.Triggers>
...
<Style.Triggers>
</Style>

Resources