In Wpf I inherit from the Button class:
public class MenuButton : Button
{
public MenuButton()
{
this.Style = FindResource("MenuButton") as Style;
}
public MenuButton(string caption, ICommand command)
: this()
{
SetValue(ContentProperty, caption);
this.command = command;
}
}
In a window I added a control
<c:MenuButtons x:Name="MenuProject" c:MenuItems="{x:Static d:MenuItems.Project}" />
Where c: en d: are my namespaces.
MenuItems is a dependencyproperty of usercontrol MenuButtons and is declared in a class like:
public readonly static MenuButton[] Project = new MenuButton[] { new MenuButton("Open", new Command()), ..etc };
The resource is defined like:
<Style x:Key="MenuButton"
BasedOn="{StaticResource {x:Static ToolBar.ButtonStyleKey}}"
TargetType="{x:Type c:MenuButton}">
The visual studio designer says: 'MenuButton' TargetType does not match type of element 'MenuButton'. The code runs fine, but the designer has trouble invoking the constructor of my MenuButton class. When commenting out that line the error disappears, but then the style is not applied and vice versa.
this.Style = FindResource("MenuButton") as Style; should not appear in the constructor.
You can apply it in the OnApplyTemplate method
public overrride OnApplyTemplate()
{
this.Style = FindResource("MenuButton") as Style;
base.OnApplyTemplate();
}
Hope this helps
Related
I have a class "Application" which has a static member(MainWindow, inherits from DXWindow) like the following:
public static MainWindow MainWindowInstance
I instantiate and display it:
MainWindowInstance = new MainWindow();
MainWindowInstance.ShowDialog();
MainWindow has a property:
private Thickness _localAttachmentsButtonsMargin = new Thickness(0, 0, 5, 0);
public Thickness LocalAttachmentsButtonsMargin {
get {
return _localAttachmentsButtonsMargin;
}
set {
_localAttachmentsButtonsMargin = value;
NotifyPropertyChanged("LocalAttachmentsButtonsMargin");
}
}
I need to access the LocalAttachmentsButtonsMargin property from many other controls (like UserControls) in xaml.
What I tried so far is:
--> Access it with x:Static:
Margin="{Binding Path=MainWindowInstance.LocalAttachmentsButtonsMargin, Source={x:Static Application.Current}}"
--> Giving the UserControl a x:Name ("UcTmp"), provide a getter in the UserControl and access the property from code behind
Margin="{Binding ElementName=UcTmp, Path=LocalAttachmentsButtonsMargin}}"
public Thickness LocalAttachmentsButtonsMargin {
get {
Application.MainWindowInstance.LocalAttachmentsButtonsMargin;
}
}
But none of them both seems to work. I think I need the xaml equivalent to the one line of code in the getter given above.
An additional requirement is that the property in MainWindow needs to be updatable. Ideally the solution is able to update the view which is represented throught the UserControl if the property will be updated though some code.
Since you can only bind to properties, you should define MainWindowInstance as such:
public static MainWindow MainWindowInstance { get; set; }
It cannot be a field:
public static MainWindow MainWindowInstance;
In my WPF appp, I created a custom control by subclassing TextBox. I then added a DependencyProperty called BorderWhenRequired (the border to use when the TextBox represents a required field), like so:
public class TextBoxEx : TextBox
{
public static readonly DependencyProperty BorderWhenRequiredProperty = DependencyProperty.Register(
"BorderWhenRequired", typeof(Brush), typeof(TextBoxEx),
new FrameworkPropertyMetadata(default(Brush), FrameworkPropertyMetadataOptions.AffectsRender)
);
public Brush BorderWhenRequired
{
get { return (Brush)GetValue(BorderWhenRequiredProperty); }
set { SetValue(BorderWhenRequiredProperty, value); }
}
}
I then created a resource that holds the brush value for the border, and a style for the control:
<SolidColorBrush x:Key="RequiredControlBorderBrush">Purple</SolidColorBrush>
<Style TargetType="{x:Type implementations:TextBoxEx}">
<Setter Property="BorderWhenRequired" Value="{StaticResource RequiredControlBorderBrush}" />
</Style>
but the designer is showing me:
ArgumentException: '#FF800080' is not a valid value for the 'MyNs.Common.Controls.Implementations.TextBoxEx.BorderWhenRequired' property on a Setter.
I tried defining the resource RequiredControlBorderBrush as a Brush, Color and SolidColorBrush, but I keep getting the same error.
Solved my own problem. In case anyone comes across this: I made a careless mistake. All Color properties in my custom class where defined as System.Drawing.Brush, when they should have been System.Window.Media.Brush.
I have a custom class:
class CustomClass
{
public string Test { get; set; }
CustomClass()
{
this.Test = "";
}
}
I'm declaring this custom class on a Application.Resources like that:
<Application.Resources>
<local:CustomClass x:Key="myobj"/>
</Application.Resources>
This resource is the DataContext of a grid and the TextBox binds the Test property, like that:
<Grid DataContext="{DynamicResource myobj}">
<TextBox Text="{Binding Path=Test, Mode=TwoWay}"></TextBox>
</Grid>
Suddenly at run-time, I change the value of the resource
this.Resources["myobj"] = new CustomClass() { Test = "12456" };
I want the value referenced on TextBox be always the value of the object that is currently on "myobj" resource, and I want change automatically the value of the current object when the value of Text property of the TextBox is changed, because of this, I used the Mode=TwoWay, but it's not happening.
I used WPF Inspector and I saw when the resource value is changed, binds a new cleared object and not my created object
I'm new in WPF sorry my english and my unknowledge;
Regards,
EDIT 1
It works implementing the code posted by ethicallogics, thanks! But sorry if I wasn't clear before, when binds a new resource as below
this.Resources["myobj"] = new instance;
it works fine when it is called inside the same window that this resource was declared, unlike when I call this line inside a UserControl, it seems that the UserControl doesn't inherit the MainWindow Resources, how that really works ?
class CustomClass:INotifyPropertyChanged
{
private string _test;
public string Test
{
get
{
return _test;
}
set
{
_test = value;
Notify("Test");
}
}
CustomClass()
{
this.Test = "";
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
#endregion
private void Notify(string propName)
{
if(PropertyChanged!=null)
PropertyChanged(this,new PropertyChangedEventArgs(propName);
}
}
Use this class .I hope this will help.
In my application i need to change the properties related to a datagrid header like ColumnHeader Font, fontsize etc. As there is no single property for the same currently, i am updating this through Style setters. But the problem is for a single property change(like FontSize) i have to create an entire collection of the SetterBase and update the single property along with the other propertied in the setterbase collection. Is there any other way to update a property as in this scenario.
Code snippet:
set
{
Style m_ColumnHeaderStyle = new Style(typeof(DataGridColumnHeader));
m_ColumnHeaderStyle.Setters.Add(m_ColumnFontWeightProperty);
m_ColumnHeaderStyle.Setters.Add(m_ColumnFontSizeProperty);
m_ColumnHeaderStyle.Setters.Add(m_ColumnFontItalicProperty);
m_ColumnFont = new Setter(DataGridColumnHeader.FontFamilyProperty, new FontFamily(value));
m_ColumnHeaderStyle.Setters.Add(m_ColumnFont);
this.MyDataGrid.ColumnHeaderStyle = m_ColumnHeaderStyle;
}
Styles in wpf have the ability to update attached values so you can declare styles in xaml once:
<DataGrid >
<DataGrid.ColumnHeaderStyle>
<Style TargetType="DataGridColumnHeader">
<Setter Property="FontFamily" Value="{Binding HeaderFont}"/>
</Style>
</DataGrid.ColumnHeaderStyle>
</DataGrid>
The magic happens in Binding and there are few kinds of it.
public partial class MainWindow : Window, INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private FontFamily _headerFont;
public FontFamily HeaderFont
{
get
{
return _headerFont;
}
set
{
_headerFont = value;
PropertyChanged(this, new PropertyChangedEventArgs("HeaderFont"));
}
}
public MainWindow()
{
InitializeComponent();
DataContext = this;
}
}
It is imperative that PropertyChanged event is fired when property changes.
I have a usercontrol that expose a public property like this :
public Double ButtonImageHeight
{
get { return imgButtonImage.Height; }
set { imgButtonImage.Height = value; }
}
when I use that control, I want to be able to set that property throught a Style like that :
<Style x:Key="MyButtonStyle" TargetType="my:CustomButtonUserControl" >
<Setter Property="ButtonImageHeight" Value="100" />
</Style>
What am I doing wrong?
Thanks
thanks Matt, I just found it myself but you were absolutely right... here's the exact code I used in case it can help someone else (all the examples I found were on WPF, silverlight is just slightly different) :
public static readonly DependencyProperty ButtonImageHeightProperty = DependencyProperty.Register("ButtonImageHeight", typeof(Double), typeof(CustomButtonUserControl),new PropertyMetadata(ButtonImageHeight_PropertyChanged ));
public Double ButtonImageHeight
{
get { return (Double)GetValue(ButtonImageHeightProperty); }
set { SetValue(ButtonImageHeightProperty, value); }
}
private static void ButtonImageHeight_PropertyChanged(DependencyObject source, DependencyPropertyChangedEventArgs e)
{
((CustomButtonUserControl)source).imgButtonImage.Height = (Double)e.NewValue;
}
The property needs to be a dependency property in order to support styles.
You can make it even more generic and nice by passing through a Style for your imgButtonImage, that way you can set multiple properties. So within your user control add the dependency property, but make it a Style:
public static readonly DependencyProperty UseStyleProperty =
DependencyProperty.Register("UseStyle", typeof(Style), typeof(CustomButtonUserControl), new PropertyMetadata(UseStyle_PropertyChanged));
public Style UseStyle
{
get { return (Style)GetValue(UseStyleProperty); }
set { SetValue(UseStyleProperty, value); }
}
private static void UseStyle_PropertyChanged(DependencyObject source, DependencyPropertyChangedEventArgs e)
{
((CustomButtonUserControl)source).imgButtonImage.Style = (Style)e.NewValue;
}
Notice how within the PropertyChanged function I set the style of the control to the new style.
Then when I host the UserControl I can pass through the style:
<Style x:Name="MyFancyStyle" TargetType="Button" >
<Setter Property="FontSize" Value="24" />
</Style>
<controls:MyUserControl UseStyle="{StaticResource MyFancyStyle}" />
works in VS design mode too! (It's a miracle)