I'm a beginner at WPF and I try to write a WPF part with DataTrigger.
Here the needed logic:
If the variable "iBottleCount" >= 10 then make the background of a label green.
If the variable "iBottleCount" < 10 then make the background of a label yellow.
If the variable "iBottleCount" = 0 then make the background of a label red.
But he can'f find my label with the targed name "StatusColor".
Find the code below:
<DataGridTemplateColumn Header="Status" Width="80" >
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="20" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<TextBlock x:Name="StatusText" Height="15" HorizontalAlignment="Left" Margin="2,2,2,2" Text="" VerticalAlignment="Top" Grid.Row="0" Grid.Column="1"/>
<Label x:Name="StatusColor" Content="" Background="green" HorizontalAlignment="Center" Margin="5,5,5,5" VerticalAlignment="Top" Height="10" Width="20" Grid.Row="0" Grid.Column="0"/>
</Grid>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellStyle>
<Style TargetType="{x:Type DataGridCell}">
<Style.Triggers>
<DataTrigger Binding="{Binding iBottleCount}" Value="=>10">
<!-- PROBLEM IS IN THIS LINE -->
<Setter TargetName="StatusColor" Property="Background" Value="Green" />
</DataTrigger>
</Style.Triggers>
</Style>
</DataGridTemplateColumn.CellStyle>
</DataGridTemplateColumn>
So what's the problem? The label is defined some lines higher.
The template has its own scope that cannot be accessed from outside. You cannot use TargetName in Style triggers anyway, if you need to change the Label, add a trigger to its Style.
Without a good Minimal, Complete, and Verifiable code example that shows clearly what you're trying to do, it's impossible to know for sure what the best fix is. That said…
First off, the comment in H.B.'s answer is correct: you're trying to access a named element where that name is not in scope at the point where you are trying to access it, and even if you could, the Style trigger can't use the TargetName property.
Certainly one option is to move the trigger to the template. This, however, will require that the template be tied to the view model you're using. This might actually be okay in your case. There's not enough context in the question to know.
If you'd rather stay closer to the design you've got now, where the trigger is in the DataGridCell style, you can use TemplateBinding to accomplish what you want. For example…
In the template:
<Label Content="" Background="{TemplateBinding Background}" HorizontalAlignment="Center"
Margin="5,5,5,5" VerticalAlignment="Top" Height="10" Width="20"
Grid.Row="0" Grid.Column="0"/>
And then, setting the Background property of the DataGridCell will propagate down into the template. I.e. in your style's trigger:
<Setter Property="Background" Value="Green"/>
I.e. just remove the TargetName attribute from your existing code.
Obviously, this works only if you have a single Background value you want to set in the template. You'll need something more elaborate if you have a more complex scenario. Also, of course don't forget that if you want to provide a default value for the Background property, you need to include a non-trigger <Setter .../> element in the style to set that default value.
Related
so for example i have this xaml code
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Grid Width="50" Height="50" VerticalAlignment="Center" HorizontalAlignment="Center">
<Button x:Name="PlayButton" Style="{DynamicResource MetroCircleButtonStyle}" Visibility="Visible"
Width="50" Height="50" HorizontalAlignment="Center"
VerticalAlignment="Center" Click="OnPlayButtonClicked"
d:DataContext="{d:DesignInstance local:MainWindow}">
<Rectangle Width="20"
Height="20">
<!--<Image Width="50" Height="50" Source="Resources/playIcon.png" Name="Image"></Image>-->
<Rectangle.Fill>
<VisualBrush Stretch="Fill"
Visual="{StaticResource appbar_control_play}" />
</Rectangle.Fill>
</Rectangle>
<!--<Image Width="50" Height="50" Source="Resources/playIcon.png" Name="Image"></Image>-->
</Button>
<Button x:Name="PauseButton" Style="{DynamicResource MetroCircleButtonStyle}" Visibility="Hidden"
Width="50" Height="50" HorizontalAlignment="Center"
VerticalAlignment="Center" Click="OnPauseButtonClicked"
d:DataContext="{d:DesignInstance local:MainWindow}">
<Rectangle Width="20"
Height="20">
<!--<Image Width="50" Height="50" Source="Resources/playIcon.png" Name="Image"></Image>-->
<Rectangle.Fill>
<VisualBrush Stretch="Fill"
Visual="{StaticResource appbar_control_pause}" />
</Rectangle.Fill>
</Rectangle>
<!--<Image Width="50" Height="50" Source="Resources/playIcon.png" Name="Image"></Image>-->
</Button>
</Grid>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
and inside my MainWindow.xaml.cs file i would like to edit the 'PlayButton' Visibility, but i can't seem to access it?
What is the correct way of accessing components like this?
Kind Regards - Corey.
The "PlayButton" resides inside a DataTemplate for the DataGridTemplateColumn.CellTemplate, which means that you will see one "PlayButton" for each row of the table.
So, the window can't have a "PlayButton" property to access the button, since there are many instances of it.
Usually if you have to control the Visibility of that button, you will have to do it by Binding.
In addition, since the DataGrid uses by default EnableColumnVirtualization and EnableRowVirtualization, a single instance of the button can be reused when you scroll the grid elements, so the button has to be able to match the cell content only by using the data present in that row.
For example if the grid displays 10 rows, when you scroll down by one row, the visual components used to show the first row, which goes out of sight, will be reused to show the eleventh row. So any change you could have made to the PlayButton of the first row, will remain in the eleventh one, unless you change it again.
Another advice I can give you is to not use a Grid, if you can, inside a celltemplate of a column because the Grid is quite heavy to render, and assuming that the grid could show at the same time dozens of rows, the redering could be very slow.
I think that in this case it could be better to use a CellTemplateSelector to show only a PlayButton or a PauseButton, each one on its own DataTemplate, basing on the content of the row, or to use a single button with a Style responding to DataTriggers that changes the appearance of the button itself.
You'd use a DataTrigger to toggle visibility :
<Button x:Name="PauseButton" ...>
<Button.Style>
<Style TargetType="{x:Type Button}">
<!-- Set Default Value here, not in Button Tag -->
<Setter Property="Visibility" Value="Collapsed" />
<!-- Use Trigger to update value based on a conditional statement -->
<Style.Triggers>
<DataTrigger Binding="{Binding IsVisible}" Value="True">
<Setter Property="Visibility" Value="Visible" />
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
...
</Button>
Formentz's answer is correct that the actual Button object is hard to use because it is not individually created for each row. Instead, only the visible rows are created, and the .DataContext behind each row changes as you scroll through. If you want to toggle the Visibility of the button, it needs to be based off a databound property so it updates as users scroll through the rows.
I am using this outlined textBlock that with the solution proposed by Javier G. works like a charm. I put it in a library so now it's HelperLib:OutlinedTextBlock.
Now I would like to put it in a TextBox.
So what I tried is:
Put the OutlinedTextBox as a child of a TextBlock but that didn't work since it's not accepting it as a child.
Use a RichTextBox and the put it inside a FlowDocument but something went wrong since a got a Runtime error
Use a template but again Runtime error.
If the fact of putting the outlinedTextBox makes it too peculiar I think that this can be rethought as putting anyother control inside a textbox.
I think the solution is close but somehow it still escapes me...
--EDIT--
There is an additiona problem which I have never encountered:
I have named my control otbQuery but it doesn't show up in the code!!! Why???
<TextBox Name="tbxQuery" VerticalAlignment="Center" Grid.Column="3" Width="200" Background="Transparent" CaretBrush="White" HorizontalAlignment="Center" Foreground="White" TextChanged="TextBox_TextChanged" BorderBrush="Gainsboro" BorderThickness="3">
<TextBox.Template>
<ControlTemplate>
<Border BorderBrush="Gainsboro" BorderThickness="3">
<Grid>
-----> <HelperLib:OutlinedTextBlock Name="otbQuery" Margin="1" Fill ="White" Stroke="Red" Text="{Binding Path=Content, ElementName=cp, Mode=OneWay}" VerticalAlignment="Center"/>
<ContentPresenter x:Name="cp" Content="{Binding Text, RelativeSource={RelativeSource TemplatedParent}}" TextBlock.Foreground="Transparent"/>
</Grid>
</Border>
</ControlTemplate>
</TextBox.Template>
</TextBox>
you can see the error here and no valid quick fix is proposed
You will need to override the ControlTemplate of the TextBox control in order to make that happen. Below is a simple example of how to do that, and still have the TextBox.Text property bound to the Text property of the TexBlock.
<TextBox>
<TextBox.Template>
<ControlTemplate>
<Border BorderBrush="Black"
BorderThickness="1">
<Grid>
<TextBlock Margin="1"
Foreground="Red"
Text="{Binding Path=Content, ElementName=cp, Mode=OneWay}"/>
<ContentPresenter x:Name="cp"
Content="{Binding Text, RelativeSource={RelativeSource TemplatedParent}}"
TextBlock.Foreground="Transparent"/>
</Grid>
</Border>
</ControlTemplate>
</TextBox.Template>
</TextBox>
Where I have put a standard TextBlock inside the ControlTemplate, you would put your custom TextBlock control.
EDIT
The above solution works, but it's a serious kludge. Basically, it puts a transparent ContentPresenter on top of the TextBlock . The TextBlock display the text in the manner you want and the ContentPresenter allows you to type in the TextBox.
One problem that still exists is that the cursor bar does not show up when clicking on, or typing in the TextBox. I suspect that problem could be overcome with some more styling done to the template of the TextBox.
Is it possible to create a style for ToolTip that would place an image next to the Item on which the tool tip resides and then show the tool tip text when the user hovers over the image? Something like this:
Currently I am doing a StackPanel to add the image with the tool tip like so:
<StackPanel Orientation="Horizontal">
<CheckBox Content="Reload Employee Data"
IsChecked="{Binding AdjustmentSettings.ReloadEmployeeData}"
Grid.Row="0"
Grid.Column="0">
</CheckBox>
<Image Source="/DelphiaLibrary;Component/Resources/info.ico"
ToolTip="Check if you want to re-upload ...."/>
</StackPanel>
EDIT
Just to clarify, I am looking for a way to style ToolTip such that if I define ToolTip on any object (i.e., Button, CheckBox, etc.) the info image is shown and the tool tip text is placed on this info image.
I would like to be able to do something like this and still get the same as the stack panel above:
<CheckBox Content="Reload Employee Data"
IsChecked="{Binding AdjustmentSettings.ReloadEmployeeData}"
Grid.Row="0"
Grid.Column="0"
ToolTip="Blah blah blah..."
Style="{StaticResource ToolTipImageStyle}">
</CheckBox>
And be able to apply this ToolTipImageStyle to any control (i.e., Button, CheckBox, TextBox, etc.). If that isn't possible can I style an individual control and just create different styles for different controls (one for buttons, another for TextBlock, etc.)?
This should do it. I couldn't figure out the color so just change that.
Source 1
Source 2
<Image Source="/DelphiaLibrary;Component/Resources/info.ico" Width="25" Height="25">
<Image.ToolTip>
<ToolTip Background="LightBlue">
<TextBlock Width="200" TextWrapping="WrapWithOverflow">
Check if you want to re-upload table foxpro.hrpersnl from the source. <LineBreak />
Leave unchecked to use existing data that has been previously uplaoded.
</TextBlock>
</ToolTip>
</Image.ToolTip>
</Image>
Update 1:
Source 1
In the App.xaml add this:
<Application.Resources>
<Style TargetType="{x:Type ToolTip}">
<Setter Property="OverridesDefaultStyle" Value="True" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ToolTip}" >
<TextBox Background="LightBlue" Width="200" TextWrapping="WrapWithOverflow" Text="{TemplateBinding ToolTip.Content}" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Application.Resources>
Then in your XAML file change to:
Note: This will work with all object's tool tips.
<Image Source="Images/MenuImageZoomOut.png" Width="25" Height="25"
ToolTip="Check if you want to re-upload table foxpro.hrpersnl from the source. Leave unchecked to use existing data that has been previously uplaoded." />
The image:
If this doesn't work, try this: Source
Any advice how to fault find to work out why the Grid.Resources styles in this XAML is not making any difference it seems to the end result?
Note I'm using Charting from the WPFToolkit so to adjust how a chart looks it seems one has to apply the style areas (suggested by someone on the forum).
So my question is generically, noting I'm trying to adjust the look of a 3rd party graph, how can I debug/fault-find to understand what's going wrong? Is there a debugging trick? For example when I increased the BorderThickness to 30 I couldn't see a difference. What I'm really after is the equivalent of FireBug for HTML/CSS, which lets you understand/view what CSS is being applied to what elements.
EDIT: So I really (I think) want to be able to walk the object tree of the graph, and referring back to the template changes put in the Grid.Resources area, see why they didn't occur.
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:chartingToolkit="clr-namespace:System.Windows.Controls.DataVisualization.Charting;assembly=System.Windows.Controls.DataVisualization.Toolkit" mc:Ignorable="d" x:Name="Splash" x:Class="MyInternetUsage.SplashWindow"
Title="SplashWindow" Height="421" Width="570">
<DockPanel>
<StackPanel VerticalAlignment="Top" DockPanel.Dock="Top" Orientation="Horizontal">
<Button Content="Configure" HorizontalAlignment="Left" Margin="0" Width="78" VerticalAlignment="Center" Name="ConfigureButton" Click="ConfigureButton_Click" />
<Button Content="Start" Name="StartButton" Width="78" Click="StartButton_Click" />
<Button Content="Stop" Name="StopButton" Width="78" Click="StopButton_Click" />
</StackPanel>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="150"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Content="Summary" Grid.Column="0"/>
<GridSplitter HorizontalAlignment="Right"
VerticalAlignment="Stretch" Grid.Column="1" ResizeBehavior="PreviousAndNext"
Width="5" Background="#FFBCBCBC"/>
<Grid Grid.Column="2">
<Grid.Resources>
<Style x:Key="GooglePolylineStyle" TargetType="Polyline">
<Setter Property="StrokeThickness" Value="30"/>
</Style>
<Style x:Key="GoogleLineDataPointStyle" TargetType="chartingToolkit:LineDataPoint">
<Setter Property="Background" Value="#0077CC" />
<Setter Property="BorderBrush" Value="White"/>
<Setter Property="BorderThickness" Value="30"/>
<Setter Property="IsTabStop" Value="False"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="chartingToolkit:LineDataPoint">
<Grid x:Name="Root" Opacity="1">
<ToolTipService.ToolTip>
<StackPanel Margin="2,2,2,2">
<ContentControl Content="{TemplateBinding IndependentValue}"
ContentStringFormat="{}{0:MMMM d, yyyy}"/>
<ContentControl Content="{TemplateBinding DependentValue}"
ContentStringFormat="Visits {0:###,###,###}"/>
</StackPanel>
</ToolTipService.ToolTip>
<Ellipse StrokeThickness="{TemplateBinding BorderThickness}"
Stroke="{TemplateBinding BorderBrush}"
Fill="{TemplateBinding Background}"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Grid.Resources>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>
<Label Content="Real Time Graph" VerticalAlignment="Top" Grid.Row="0" />
<chartingToolkit:Chart Grid.Row="1"
Name="RTGraph"
BorderThickness="0" >
</chartingToolkit:Chart>
</Grid>
</Grid>
</DockPanel>
</Window>
As SeeSharp says, Snoop allows you to view the object tree at runtime (and change values and see results etc). However, I think your problem here might be that you're not explicitly applying the style on the <chartingToolkit:Chart /> object.
Try one of the following to see if it makes a difference:
Apply style on object:
<chartingToolkit:Chart
...
Style="{DynamicResource GoogleLineDataPointStyle}"
...
>
Or remove the key from the style so that it only has a TargetType attribute (should make it the default style for all objects of that type:
<Style TargetType="chartingToolkit:LineDataPoint">
...
</Style>
Since you've given the styles an x:Key. you need to explicitly set the style property of your items to use that style as a resource.
Have you tried removing the x:Key properties from your style, and moving your style declaration from the grid and into the chart?
See output window in VS. All binding errors logged in this window. Also, tool Snoop alow to see bindings with errors.
If this is a WPF application, i would like to suggest one silly thing. Excuse me for that. Please copy and paste the same code into a silverlight application and then inspect the element using Firebug.
Also, in your code snippet, i think you need to give :
TargetType="{x:Type Polyline}"
TargetType="{x:Type chartingToolkit:LineDataPoint}"
If you want these styles to be applied on the target type automatically, then remove the x:Key.
Also, you can find a list of useful WPF utilities # http://www.simple-talk.com/dotnet/.net-tools/essential-tools-for-the-wpf-novice/
I have a converter that returns a background colour based on a binding value on a DataGrid. This is working great in WPF but when i put this code into silverlight it is not happy.
Reading some posts on here it seems i can not use TargetType="{x:Type my:DataGridCell}"
The answer suggested was to use simply TargetType="my:DataGridCell" but again this did not work.
Another suggestion was to give the style a Key but as my style is set on my DataGrid i can not move this to Page.Resources (and thus give it a key) as i need to bind to it. Like so:
<data:DataGrid x:Name="gridResults" CanUserReorderColumns="True" HorizontalAlignment="Left" IsReadOnly="True" AutoGenerateColumns="False" SelectionChanged="gridResults_SelectionChanged" ItemsSource="{Binding}">
<data:DataGrid.CellStyle>
<Style TargetType="{x:Type data:DataGridCell}">
<Setter Property="Background" Value="{Binding SoldIn, Converter={StaticResource conFor}}" />
</Style>
</data:DataGrid.CellStyle>
<data:DataGrid.Columns>
<data:DataGridTextColumn
Header="Outlet"
Width="Auto"
Binding="{Binding Outlet}" />
....
....
How can i keep my binding in tact and make silverlight be happy?
Thanks,
Kohan
Not the perfect solution but i got my desired results though using data:DataGridTemplateColumns instead.
<data:DataGridTemplateColumn Header="Outlet">
<data:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Border Background="{Binding SoldIn, Converter={StaticResource conFor}}">
<ContentControl Content="{Binding Outlet}" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch" />
</Border>
</DataTemplate>
</data:DataGridTemplateColumn.CellTemplate>
</data:DataGridTemplateColumn>