c# uwp tooltip placement property not updating - c#

In C# UWP I am creating custom tooltip style.
I have changed the default style of tooltip as below.
<Style TargetType="ToolTip">
<Setter Property="Foreground" Value="White" />
<Setter Property="Background" Value="{ThemeResource SystemControlBackgroundChromeMediumLowBrush}" />
<Setter Property="BorderBrush" Value="{ThemeResource SystemControlForegroundChromeHighBrush}" />
<Setter Property="BorderThickness" Value="{ThemeResource ToolTipBorderThemeThickness}" />
<Setter Property="FontSize" Value="{ThemeResource ToolTipContentThemeFontSize}" />
<Setter Property="Padding" Value="40,40,40,35"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToolTip">
<Grid Background="Transparent">
<Grid
MinWidth="100"
MinHeight="90"
Height="{TemplateBinding Height}"
Width="{TemplateBinding Width}"
Padding="15"
Background="Transparent">
<local:ArrowDown x:Name="arrowDown" TooltipPlacement="{TemplateBinding Placement}"/>
And my custom control ArrowDown is getting information of ToolTip placement, so I can show it depends if tooltip is under or above control.
In the ArrowDown control I have added a DependencyProperty as below:
public PlacementMode TooltipPlacement
{
get { return (PlacementMode)GetValue(TooltipPlacementProperty); }
set { SetValue(TooltipPlacementProperty, value); }
}
public static readonly DependencyProperty TooltipPlacementProperty =
DependencyProperty.Register("TooltipPlacement", typeof(PlacementMode), typeof(ArrowDown), new PropertyMetadata(null, TooltipPlacementChangedCallback));
private static void TooltipPlacementChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var self = (ArrowDown)d;
self.CalculateArrowVisibility();
}
// Method to show or hide arrow
private void CalculateArrowVisibility()
{
}
And the problem is that the CalculateArrowVisibility is fire only the first time when tooltip is shown, and it always returns Top for TooltipPlacement, no matter if tooltip is shown below or above control.
I need CalculateArrowVisibility to be fired whenever the tooltip is shown, and I need TooltipPlacement property to show if tooltip is Under or Above control.
Anyone have the idea about this?

The fact is that you cannot use the ToolTipService attached properties (e.g. <Button ToolTipService.Placement="Bottom" ToolTipService.ToolTip="!!!" />) to define the tooltip and it placement. This way the Placement is not set on the actual ToolTip control itself, and that's why it will always return Top.
In order to have the ToolTip pass down its Placement value to your custom dependency property, you will have to attach it like the following -
<Button>
<ToolTipService.ToolTip>
<ToolTip Placement="Bottom" Content="Hahaha..." />
</ToolTipService.ToolTip>
</Button>
Update
Turns out that even though the app Window pushes the tooltip above or below its parent, its Placement value is never changed, what's changed is its horizontal & vertical offsets.
So, in your case, if we could work out its exact vertical offset, we would be able to determine whether the tooltip is above or below (its parent).
Given we have a ToolTip Style in place, we can create an attached property of type ToolTip and attach it to the Grid that contains the ArrowDown control.
<Grid MinWidth="100"
MinHeight="90"
Height="{TemplateBinding Height}"
Width="{TemplateBinding Width}"
Padding="15"
Background="Transparent"
local:ToolTipHelper.ToolTip="{Binding RelativeSource={RelativeSource TemplatedParent}}">
Because the TemplatedParent of the Grid is the ToolTip, we can use RelativeSource binding to link the ToolTip on the screen with our attached property, as shown above.
Now, we have a reference to the actual ToolTip, let's find its offsets. After some digging, I've found that the offsets of the ToolTip are always 0, they are useless; however, the offsets of its parent - a Popup, sometimes gives me the correct values, but not always. This is because I was using the Opened event where those values weren't yet populated; as soon as I changed it to SizeChanged, they have been giving me the expected values.
public static class ToolTipHelper
{
public static ToolTip GetToolTip(DependencyObject obj)
{
return (ToolTip)obj.GetValue(ToolTipProperty);
}
public static void SetToolTip(DependencyObject obj, ToolTip value)
{
obj.SetValue(ToolTipProperty, value);
}
public static readonly DependencyProperty ToolTipProperty =
DependencyProperty.RegisterAttached("ToolTip", typeof(ToolTip), typeof(ToolTipHelper),
new PropertyMetadata(null, (s, e) =>
{
var panel = (Panel)s; // The Grid that contains the ArrowDown control.
var toolTip = (ToolTip)e.NewValue;
// We need to monitor SizeChanged instead of Opened 'cause the offsets
// are yet to be properly set in the latter event.
toolTip.SizeChanged += (sender, args) =>
{
var popup = (Popup)toolTip.Parent; // The Popup that contains the ToolTip.
// Note we have to use the Popup's offset here as the ToolTip's are always 0.
var arrowDown = (ArrowDown)panel.FindName("arrowDown");
arrowDown.TooltipPlacement = popup.VerticalOffset > 0
? PlacementMode.Bottom
: PlacementMode.Top;
};
}));
}
Now, with this approach, you should be able to use the ToolTipService attached properties too. So the following XAML would work.
<Button ToolTipService.ToolTip="!!!" Content="Hover Me" />
Hope this helps!

Related

TextBlock Style to always use Run Tag

In WPF Arabic Mode (FlowDirection="RightToLeft").
When i give a number like -24.7% it will print this as %24.7-
Following code will fix the above mentioned issues.
<Window.Resources>
<Style TargetType="Run">
<Setter Property="FlowDirection" Value="LeftToRight" />
</Style>
</Window.Resources>
<Grid FlowDirection="RightToLeft" >
<Grid HorizontalAlignment="Left" Margin="114,127,0,0" VerticalAlignment="Top" Width="279" Height="97">
<TextBlock x:Name="textBlock" Text="-24.7%" ><Run></Run></TextBlock>
</Grid>
</Grid>
Now i want to put the <run><run> tag to all of my Text Blocks Contents, How can i achieve this, So i don't have to replace all of my TextBlocks in the code.
How to do this by creating a Style...??
note: I can't go to the TextAlign=Right solution as i can't edit all the textblockes in the application
Can't say I like your approach, but I don't know Arabic gotchas and your situation, so won't argue about that. You can achieve what you want using attached properties (or blend behaviors). Like this:
public static class StrangeAttachedProperty {
public static bool GetAddRunByDefault(DependencyObject obj) {
return (bool) obj.GetValue(AddRunByDefaultProperty);
}
public static void SetAddRunByDefault(DependencyObject obj, bool value) {
obj.SetValue(AddRunByDefaultProperty, value);
}
public static readonly DependencyProperty AddRunByDefaultProperty =
DependencyProperty.RegisterAttached("AddRunByDefault", typeof (bool), typeof (StrangeAttachedProperty), new PropertyMetadata(AddRunByDefaultChanged));
private static void AddRunByDefaultChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
var element = d as TextBlock;
if (element != null) {
// here is the main point - you can do whatever with your textblock here
// for example you can check some conditions and not add runs in some cases
element.Inlines.Add(new Run());
}
}
}
And in your resources set this property for all text blocks:
<Window.Resources>
<Style TargetType="TextBlock">
<Setter Property="local:StrangeAttachedProperty.AddRunByDefault" Value="True" />
</Style>
<Style TargetType="Run">
<Setter Property="FlowDirection" Value="LeftToRight" />
</Style>
</Window.Resources>

Refresh template custom control after clearing and re-adding MergedDictionaries

The situation
I made a custom control MessageBar that has a style defined in a resource dictionary. This control has a dependency property Message that, like the name says, will contain a message.
public class MessageBar : Control
{
public static readonly DependencyProperty MessageProperty =
DependencyProperty.Register("Message", typeof(string), typeof(MessageBar),
new FrameworkPropertyMetadata(string.Empty, OnMessageChanged));
static MessageBar()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(MessageBar), new FrameworkPropertyMetadata(typeof(MessageBar)));
}
public string Message
{
get { return (string)GetValue(MessageProperty); }
set { SetValue(MessageProperty, value); }
}
private static void OnMessageChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
MessageBar messageBar = (MessageBar)d;
if (e.NewValue != null && !string.IsNullOrWhiteSpace(e.NewValue.ToString()))
{
messageBar.Visibility = Visibility.Visible;
if (messageBar.textBlock == null)
messageBar.textBlock = messageBar.GetChildOfType<TextBlock>();
// Lots of unnecessary code
}
}
Style
<Style TargetType="{x:Type controls:MessageBar}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type controls:MessageBar}">
<Border Background="LightYellow"
BorderBrush="Black"
BorderThickness="1,0,1,1"
CornerRadius="0,0,10,10">
<StackPanel VerticalAlignment="Center"
Orientation="Horizontal"
Margin="10,0,10,0">
<!-- Actual text -->
<TextBlock Padding="4,2,4,2"
Margin="5,0,0,0"
x:Name="tbText"
Text="{TemplateBinding Message}"
FontSize="16"
FontWeight="ExtraBold" />
</StackPanel>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
When the application starts, the default style is loaded in the merged dictionaries. After the user logs in, the style that the user chose (this can be different of the default style) is loaded in the merged dictionaries. Reloading the style happens by clearing the merged dictionaries and re-adding the correct resource dictionaries to the merged dictionaries.
Application.Current.Resources.MergedDictionaries.Clear();
Application.Current.Resources.MergedDictionaries.Add(new ResourceDictionary()
{
Source = ...
});
// Adding happens a few times.
The new style is correctly loaded and this is also visible in the UI. The UI changes correctly.
The problem
The problem happens when after clearing and re-adding the merged dictionaries, I try to find the child of type TextBlock in the OnMessageChanged method.
messageBar.textBlock = messageBar.GetChildOfType<TextBlock>();
I am 100% sure that there is nothing wrong with my GetChildOfType<>() method. It works correctly when used somewhere else.
When I execute this after re-adding, there are no child elements of MessageBar. ChildrenCount is 0.
When the merged dictionaries aren't cleared and re-added, there is a child element of type TextBlock found. This is what I want.
My guess is that after clearing and re-adding, the MessageBar doesn't have a correct reference to the style. And because of that, the template isn't applied.
What I already tried
I already tried overriding the ApplyTemplate() and OnStyleChanged() methods of the MessageBar control. But nothing works.
Question
How can I reload the style so that I (the GetChildOfType<TextBlock>() method) can find the TextBlock to set my message in the OnMessageChanged method.
Thanks in advance!
Greetings Loetn.
Try messageBar.ApplyTemplate() before calling GetChildOfType

WPF Dependency Property Issue

I am wondering if anyone could explain me the difference between
binding a selected value of a Collection to a comboBox.
Or Binding the value to a Button Content.
Like that
<ComboBox x:Name="_culturedTitleViewModelSelector" Visibility="Hidden" Style="{StaticResource ResourceKey=_culturedTitleViewModelSelectorStyle}"
ItemsSource="{Binding Path=AvailableCultures, Source={x:Static Localized:ResourcesManager.Current}}"
SelectedValue="{Binding Path=CurrentCulture, Source={x:Static Localized:ResourcesManager.Current}}"
<Button x:Name="LanguageBtn" Content="{Binding Path=CurrentCulture, Source={x:StaticLocalized:ResourcesManager.Current}}"
The issue is If i Don't use the ComboBox up there, the DependencyProperty I Have in another class is not being called.
But if I Use the comboBox everything works...
Altought the comboBox doesnt do anything it's just a "workarround"
In my CS code when i CLick on my button I DO that :
ResourcesManager.Current.SwitchToNextCulture();
//We use a dummy comboBox to make sure the LanguageBehavior Property is being notified.
_culturedTitleViewModelSelector.SelectedItem = ResourcesManager.Current.CurrentCulture;
And if I Dont set the SelectedItem of the combobox to another culture. My languageBehavior class is not notified.
:
public class LanguageBehavior
{
public static DependencyProperty LanguageProperty =
DependencyProperty.RegisterAttached("Language",
typeof(string),
typeof(LanguageBehavior),
new UIPropertyMetadata(OnLanguageChanged));
public static void SetLanguage(FrameworkElement target, string value)
{
target.SetValue(LanguageProperty, value);
}
public static string GetLanguage(FrameworkElement target)
{
return (string)target.GetValue(LanguageProperty);
}
private static void OnLanguageChanged(DependencyObject target, DependencyPropertyChangedEventArgs e)
{
var element = target as FrameworkElement;
if (e.NewValue!=null)
element.Language = XmlLanguage.GetLanguage(e.NewValue.ToString());
}
}
I'd expect ComboBox Content to work the same as Button Content.
In my Generic.Xaml i do that :
<Style TargetType="{x:Type TextBlock}" x:Key="_textBlockLanguageProperty">
<Setter Property="WpfServices:LanguageBehavior.Language" Value="{Binding Path=CurrentCulture, Source={x:Static Localized:ResourcesManager.Current}}"
/>
</Style>
And that is CurrentCulture
public CultureInfo CurrentCulture
{
get { return CultureProvider.Current; }
set
{
if (value != CultureProvider.Current)
{
CultureProvider.Current = value;
OnCultureChanged();
}
}
}
Current :
public static ResourcesManager Current
{
get
{
if (_resourcesManager == null)
{
var cultureProvider = new BaseCultureProvider();
_resourcesManager = new ResourcesManager(cultureProvider);
_resourcesManager.Init();
}
return _resourcesManager;
}
}
EDIT :
My _culturedTitelViewModelSelectorStyle is
<Style TargetType="{x:Type ComboBox}" x:Key="_culturedTitleViewModelSelectorStyle">
<Setter Property="DisplayMemberPath" Value="DisplayName" />
<Setter Property="SelectedValuePath" Value="." />
<Setter Property="HorizontalAlignment" Value="Right" />
<Setter Property="MaxHeight" Value="40" />
<Setter Property="FontSize" Value="20" />
<Setter Property="Margin" Value="5" />
<Setter Property="SelectedIndex" Value="0" />
<Setter Property="IsSynchronizedWithCurrentItem" Value="True" />
</Style>
In the ComboBox you are binding the SelectedValue to a specific culture. This will select that culture from the list of available cultures, and therefor, trigger a set on the CurrentCulture property.
The Content property of a Button is merely displaying something to the user, it is not doing any assigning. It reads the property value and then displays it. That is why you need to manually change the Culture in the Click event to get it to do anything.
If you want the user to be able to select a value from a list of available values, a ComboBox or ListBox is the way to go. A Button is for triggering a specific action, not for selecting from a list.

Add Items to ListBox and Style

I have a simple class:
public class Foo
{
public string Text { get; set; }
public bool AppleStyle { get; set; }
public Foo(string text, bool applyStyle)
{
Text = text;
ApplyStyle = applyStyle;
}
public override string ToString()
{
return Text;
}
}
Which is then used to add items to a ListBox:
var one = new Foo("Some Text", false);
var two = new Foo("More Text", true);
MyListBox.Items.Add(one);
MyListBox.Items.Add(two);
I then loop through the items in the ListBox to figure out how to style them. This is where I get stuck. I tried inheriting from ListBoxItem for the class, but no items get added if I do that.
for (int i = 0; i < MyListBox.Items.Count; i++)
{
if(((Foo)MyListBox.Items[i]).ApplyStyle)
{
((ListBoxItem)MyListBox.Items[i]).Style = Resources["MyStyle"] as Style;
}
}
Update:
In MainWindow.xaml:
<Window.Resources>
<Style x:Key="MyStyle" TargetType="ListBoxItem">
<Setter Property="Background" Value="Bisque"></Setter>
<Setter Property="FontWeight" Value="Bold"></Setter>
</Style>
</Window.Resources>
Update 3:
Making some progress, just need to know how to refresh the styles (after clicking on a button). Plus if Resource is not in MainWindow.xaml, would it then look in App.xaml before returning null?
MainWindow.xaml
<Window...>
<Window.Resources>
<Style x:Key="MyClass" TargetType="ListBoxItem">
<Setter Property="Background" Value="Bisque"></Setter>
<Setter Property="FontWeight" Value="Bold"></Setter>
</Style>
<myapp:MyListItemStyleSelector x:Key="MyListItemStyleSelector" />
</Window.Resources>
<Grid>
...
<ListBox .... ItemContainerStyleSelector="{StaticResource: MyListItemStyleSelector}" />
...
</Grid>
</Window>
MyListItemStyleSelector.cs
public class MyListItemStyleSelector : StyleSelector
{
public override Style SelectStyle(object item, DependencyObject container)
{
ItemsControl ic = ItemsControl.ItemsControlFromItemContainer(container);
int index = ic.ItemContainerGenerator.IndexFromContainer(container);
Style applyStyle = null;
var data = item as Foo;
if (data != null && data.ApplyStyle)
{
applyStyle = ic.TryFindResource("MyStyle") as Style;
}
return applyStyle;
}
}
I think you have some sort of mixup here, i try to explain as good as i can.
First of all You usually never need to change the Style in code, like your last code block.
One thing that is difficult to understand in the beginning is the use of a ItemContainerStyle and DataTemplate.
I would suggest that you do the following.
Instead of changing the style off your ListBoxItem see if it is sufficient to use a DataTemplate. The DataTemplate defines how the Content of your ListBoxItem is shown.
<DataTemplate TargetType="{x:Type Foo}">
<!-- your visuals and controls here -->
</DataTemplate>
Now if you want to use different datatemplates you could use different classes and create different DataTemplates for them, or you use a DataTemplateSelector
public class FooTemplateSelector : DataTemplateSelector
{
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
FrameworkElement element = container as FrameworkElement;
var mdl = item as Foo;
if( mdl.AppleStyle )
return element.FindResource("appleTemplate") as DataTemplate;
return element.FindResource("normalTemplate") as DataTemplate;
}
}
Create that templateselector in xaml and reference it in your listbox
<myNs:FooTemplateSelector x:Key="fooTemplateSelector"/>
<Listbox DataTemplateSelector="{StaticResource fooTemplateSelector}"/>
now you need to create 2 DataTemplates appleTemplate *normalTemplate* and you can easyl distinguish which data template to use vial the selector. Which is done automatically in the ListBox for you.
If you really want to change the Style of the ItemContainer you can use ItemContainerStyleSelector which works similar to the DataTemplateSelector. But i would not suggest it. You should supply the content and leave the ListBoxItem as it is, only if you want to modify the design(in this case, the selection color etc.), otherwise it might confuse the user or break functionality.
If you add data-objects directly to the ListBox the container-items will be generated automatically, you cannot get them this way.
Use the ItemContainerGenerator:
((ListBoxItem)MyListBox.ItemContainerGenerator.ContainerFromIndex(i)).Style = Resources["MyStyle"] as Style;
Why not do this in the XAML?
<ListBox Name="MyListBox">
<ListBox.Resources>
<Style TargetType="{x:Type ListBoxItem}">
<Style.Triggers>
<DataTrigger Binding="{Binding ApplyStyle}" Value="True">
<Setter Property="Background" Value="Bisque" />
<Setter Property="FontWeight" Value="Bold" />
</DataTrigger>
</Style.Triggers>
</Style>
</ListBox.Resources>
</ListBox>
But your overall problem is that ListBox.Items returns a collection of data objects, not XAML Controls. To get the XAML control that contains the Data Object you have to do as H.B. suggested and use MyListBox.ItemContainerGenerator.ContainerFromItem(dataObject) to get the XAML Container for the data object. Just be sure you wait until after the ItemContainerGenerator has finished rendering items to get the container (I believe it has a Status property or StatusChanged event you can use... it's been a while and I can't remember the exact syntax)

Silverlight with using of DependencyProperty and ControlTemplate

I'm starting to study Silverlight 3 and Visual Studio 2008. I've been trying to create Windows sidebar gadget with button controls that look like circles (I have couple of "roundish" png images). The behavior, I want, is the following: when the mouse hovers over the image it gets larger a bit. When we click on it, then it goes down and up. When we leave the button's image it becomes normal sized again.
Cause I'm going to have couple of such controls I decided to implement custom control: like a button but with image and no content text.
My problem is that I'm not able to set my custom properties in my template and style.
What am I doing wrong?
My teamplate control with three additional properties:
namespace SilverlightGadgetDocked {
public class ActionButton : Button {
/// <summary>
/// Gets or sets the image source of the button.
/// </summary>
public String ImageSource {
get { return (String)GetValue(ImageSourceProperty); }
set { SetValue(ImageSourceProperty, value); }
}
/// <summary>
/// Gets or sets the ratio that is applied to the button's size
/// when the mouse control is over the control.
/// </summary>
public Double ActiveRatio {
get { return (Double)GetValue(ActiveRatioProperty); }
set { SetValue(ActiveRatioProperty, value); }
}
/// <summary>
/// Gets or sets the offset - the amount of pixels the button
/// is shifted when the the mouse control is over the control.
/// </summary>
public Double ActiveOffset {
get { return (Double)GetValue(ActiveOffsetProperty); }
set { SetValue(ActiveOffsetProperty, value); }
}
public static readonly DependencyProperty ImageSourceProperty =
DependencyProperty.Register("ImageSource",
typeof(String),
typeof(ActionButton),
new PropertyMetadata(String.Empty));
public static readonly DependencyProperty ActiveRatioProperty =
DependencyProperty.Register("ActiveRatio",
typeof(Double),
typeof(ActionButton),
new PropertyMetadata(1.0));
public static readonly DependencyProperty ActiveOffsetProperty =
DependencyProperty.Register("ActiveOffset",
typeof(Double),
typeof(ActionButton),
new PropertyMetadata(0));
public ActionButton() {
this.DefaultStyleKey = typeof(ActionButton);
}
}
}
And XAML with styles:
<UserControl x:Class="SilverlightGadgetDocked.Page"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:SilverlightGadgetDocked="clr-namespace:SilverlightGadgetDocked"
Width="130" Height="150" SizeChanged="UserControl_SizeChanged" MouseEnter="UserControl_MouseEnter" MouseLeave="UserControl_MouseLeave">
<Canvas>
<Canvas.Resources>
<Style x:Name="ActionButtonStyle" TargetType="SilverlightGadgetDocked:ActionButton">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="SilverlightGadgetDocked:ActionButton">
<Grid>
<Image Source="{TemplateBinding ImageSource}"
Width="{TemplateBinding Width}"
Height="{TemplateBinding Height}"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="DockedActionButtonStyle" TargetType="SilverlightGadgetDocked:ActionButton"
BasedOn="{StaticResource ActionButtonStyle}">
<Setter Property="Canvas.ZIndex" Value="2"/>
<Setter Property="Canvas.Top" Value="10"/>
<Setter Property="Width" Value="30"/>
<Setter Property="Height" Value="30"/>
<Setter Property="ActiveRatio" Value="1.15"/>
<Setter Property="ActiveOffset" Value="5"/>
</Style>
<Style x:Key="InfoActionButtonStyle" TargetType="SilverlightGadgetDocked:ActionButton"
BasedOn="{StaticResource DockedActionButtonStyle}">
<Setter Property="ImageSource" Value="images/action_button_info.png"/>
</Style>
<Style x:Key="ReadActionButtonStyle" TargetType="SilverlightGadgetDocked:ActionButton"
BasedOn="{StaticResource DockedActionButtonStyle}">
<Setter Property="ImageSource" Value="images/action_button_read.png"/>
</Style>
<Style x:Key="WriteActionButtonStyle" TargetType="SilverlightGadgetDocked:ActionButton"
BasedOn="{StaticResource DockedActionButtonStyle}">
<Setter Property="ImageSource" Value="images/action_button_write.png"/>
</Style>
</Canvas.Resources>
<StackPanel>
<Image Source="images/background_docked.png" Stretch="None"/>
<TextBlock Foreground="White" MaxWidth="130" HorizontalAlignment="Right" VerticalAlignment="Top" Padding="0,0,5,0" Text="Name" FontSize="13"/>
</StackPanel>
<SilverlightGadgetDocked:ActionButton Canvas.Left="15" Style="{StaticResource InfoActionButtonStyle}" MouseLeftButtonDown="imgActionInfo_MouseLeftButtonDown"/>
<SilverlightGadgetDocked:ActionButton Canvas.Left="45" Style="{StaticResource ReadActionButtonStyle}" MouseLeftButtonDown="imgActionRead_MouseLeftButtonDown"/>
<SilverlightGadgetDocked:ActionButton Canvas.Left="75" Style="{StaticResource WriteAtionButtonStyle}" MouseLeftButtonDown="imgActionWrite_MouseLeftButtonDown"/>
</Canvas>
</UserControl>
And Visual Studio reports that "Invalid attribute value ActiveRatio for property Property" in line 27
<Setter Property="ActiveRatio" Value="1.15"/>
VERY BIG THANKS!!!
To be honest I can't see anything wrong with the code you've posted. Perhaps an explanation of exactly what causes the error you are seeing might give you some clues you can use.
The registration of the Dependancy property is what is important here:-
public static readonly DependencyProperty ActiveRatioProperty =
DependencyProperty.Register("ActiveRatio",
typeof(Double),
typeof(ActionButton),
new PropertyMetadata(1.0));
This creates and registers an instance of a dependency property against the combination of the string "ActiveRatio" and the Type ActionButton. When Silverlight comes to put the following Xaml into action:-
<Style x:Key="Stuff" TargetType="local:ActionButton">
<Setter Property="ActiveRatio" Value="1.15" />
</Style>
it combines the type specified in the TargetType attribute of the style with the string in the setters Property attribute to find the dependancy property instance. * It can then use the type indicated by the dependency property to convert the string in the setters Value attribute. Finally it can call SetValue on the FrameworkElement on which the style is set passing the DependencyProperty found and the converted value.
Now return the * in the previous paragraph. Its at this point that the code has failed. It is failing to find a dependency property registration for the string "ActiveRatio" and the type ActionButton.
I can't tell you why its failing, your code clearly registers this name and the type in the style matches the type passed in the registration. I've even written small repro of your code and it works fine.
All I can suggest is that you try a complete Rebuild and then run the code.
Assuming what you have posted is fairly complete the only other suggestion I have is such a "clutching at straws" exercise I'm not even going to explain my reason. Try adding this to you ActionButton class:-
public static ActionButton() { }

Categories