I have a User Control that I'm using to control the content of all the pages I have in a project. It allows me to easily control the header and footers of the page and have matching styles etc etc. I designed this all in Visual Studio 2010 and used the XAML Designer built in to layout all my pages. I used to be able to click on objects on the design surface that were inside the MainContent dependency property and have it highlight the XAML definition of that control. After I upgraded to VS2012, something broke and now it will only highlight flxv:MasterPageCustomControl when I click on any of the content inside my MainContent Grid. I've tried to fix it several times and lived with it for over a year now... can anyone help me? I'm not sure how much more information to provide.
<flxv:MasterPageCustomControl HeaderTitle="Display Menu"
HeaderDescription="Modify the properties and content of this display"
HeaderIcon="/SFD.Client;component/Images/32x32/plasma-tv.png"
FooterContentTemplate="{StaticResource FooterContentTemplate}">
<flxv:MasterPageCustomControl.MainContent>
<Grid>
<Button/>
</Grid>
</flxv:MasterPageCustomControl.MainContent>
</flxv:MasterPageCustomControl>
User Control Code:
public partial class MasterPageCustomControl : System.Windows.Controls.UserControl
{
#region Fields
public static readonly DependencyProperty FooterContentTemplateProperty;
public static readonly DependencyProperty HeaderDescriptionProperty;
public static readonly DependencyProperty HeaderIconProperty;
public static readonly DependencyProperty HeaderTitleProperty;
public static readonly DependencyProperty MainContentProperty;
#endregion Fields
#region Properties
public DataTemplate FooterContentTemplate
{
get { return (DataTemplate)GetValue(FooterContentTemplateProperty); }
set { SetValue(FooterContentTemplateProperty, value); }
}
public string HeaderDescription
{
get { return (string)GetValue(HeaderDescriptionProperty); }
set { SetValue(HeaderDescriptionProperty, value); }
}
public string HeaderIcon
{
get { return (string)GetValue(HeaderIconProperty); }
set { SetValue(HeaderIconProperty, value); }
}
public string HeaderTitle
{
get { return (string)GetValue(HeaderTitleProperty); }
set { SetValue(HeaderTitleProperty, value); }
}
public object MainContent
{
get { return (object)GetValue(MainContentProperty); }
set { SetValue(MainContentProperty, value); }
}
#endregion Properties
#region Constructors
static MasterPageCustomControl()
{
FooterContentTemplateProperty = DependencyProperty.Register(
"FooterContentTemplate",
typeof(DataTemplate),
typeof(MasterPageCustomControl));
HeaderDescriptionProperty = DependencyProperty.Register(
"HeaderDescription",
typeof(string),
typeof(MasterPageCustomControl));
HeaderIconProperty = DependencyProperty.Register(
"HeaderIcon",
typeof(string),
typeof(MasterPageCustomControl));
HeaderTitleProperty = DependencyProperty.Register(
"HeaderTitle",
typeof(string),
typeof(MasterPageCustomControl));
HeaderWorkstationVisiblity = DependencyProperty.Register(
"HeaderWorkstationVisiblity",
typeof(Visibility),
typeof(MasterPageCustomControl),
new PropertyMetadata(Visibility.Visible));
MainContentProperty = DependencyProperty.Register(
"MainContent",
typeof(object),
typeof(MasterPageCustomControl));
// ---------------------------------------
DefaultStyleKeyProperty.OverrideMetadata(typeof(MasterPageCustomControl), new FrameworkPropertyMetadata(typeof(MasterPageCustomControl)));
}
Related
I have the problem, that I have a existing model object which i canĀ“t extend. The actual problem is a bit more complex, so i try to break it down.
I want to extend a TextBox with a dependency property to indicate the text has changed. So i came up with following solution:
public class MyTextField : TextBox
{
public MyTextField()
{
this.TextChanged += new TextChangedEventHandler(MyTextField_TextChanged);
}
private void MyTextField_TextChanged(object sender, TextChangedEventArgs e)
{
IsDirty = true;
}
public static DependencyProperty IsDirtyProperty = DependencyProperty.Register(
"IsDirtyProperty",
typeof(bool),
typeof(MyTextField),
new PropertyMetadata(false));
public bool IsDirty
{
get { return (bool)GetValue(IsDirtyProperty); }
set { SetValue(IsDirtyProperty, value); }
}
}
XAML:
<my:MiaTextField Text="{Binding Barcode}" IsDirty="{Binding IsDirty}"/>
So if I change the text in the TextBox, the isDirty Property should change to true.
But I got a System.Windows.Markup.XamlParseException: Binding can only set for a "DependencyProperty" of "DependencyObject".
Pass "IsDirty", i.e. the name of the CLR wrapper for the dependency property, to the DependencyProperty.Register method:
public static DependencyProperty IsDirtyProperty = DependencyProperty.Register(
"IsDirty",
typeof(bool),
typeof(MyTextField),
new PropertyMetadata(false));
If you are using C#6 / Visual Studio 2015 or later, you could use the nameof operator:
public static DependencyProperty IsDirtyProperty = DependencyProperty.Register(
nameof(IsDirty),
typeof(bool),
typeof(MyTextField),
new PropertyMetadata(false));
Alternatively you could override the PropertyMetadata of the TextProperty:
public class MyTextBox : TextBox
{
static MyTextBox()
{
TextProperty.OverrideMetadata(typeof(MyTextBox), new FrameworkPropertyMetadata("", IsDirtyUpdateCallback));
}
private static void IsDirtyUpdateCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is MyTextBox tb && e.NewValue != e.OldValue && e.Property == TextProperty)
{
tb.IsDirty = (string)e.OldValue != (string)e.NewValue;
}
}
public bool IsDirty
{
get { return (bool)GetValue(IsDirtyProperty); }
set { SetValue(IsDirtyProperty, value); }
}
public static readonly DependencyProperty IsDirtyProperty =
DependencyProperty.Register("IsDirty", typeof(bool), typeof(MyTextBox), new PropertyMetadata(true));
}
to automatically set your IsDirty :o) more then one way to rome. But for your proplem thats kinda Shooting small birds with cannons (German proverb)
I have problem with binding in code.
I have Control with X, Y double properties and dependency properties.
public double X
{
get { return (double)GetValue(XProperty); }
set
{
SetValue(XProperty, value);
}
}
public double Y
{
get { return (double)GetValue(YProperty); }
set
{
SetValue(YProperty, value);
}
}
public static readonly DependencyProperty XProperty = DependencyProperty.Register("X", typeof(double), typeof(VisualPin));
public static readonly DependencyProperty YProperty = DependencyProperty.Register("Y", typeof(double), typeof(VisualPin));
In other control I have Line and I try to use binding to Line end point like this:
var xBinding = new Binding("XProperty") {Source = _startPin};
var yBinding = new Binding("YProperty") {Source = _startPin};
Line.SetBinding(Line.X1Property, xBinding);
Line.SetBinding(Line.Y1Property, yBinding);
All data in all properties are OK, I checked that, but binding doesn't work. I don't have idea why... (All controls are on one Canvas)
Thank you very much!
To debug this kind of situation you should look at the XAML by using a tool like snoop WPF. This will show what the actual bindings are.
It might be your binding is there, but not updating. To fix this your class should implement INotifyPropertyChanged. Whenever you want to update the value, like after setting the value, call the following function with the name of the property:
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
I am sorry, my fault. Problem was in first parameter in register dependency property.
public static readonly DependencyProperty XProperty = DependencyProperty.Register("X", typeof(double), typeof(VisualPin));
public static readonly DependencyProperty YProperty = DependencyProperty.Register("Y", typeof(double), typeof(VisualPin));
Instead of:
public static readonly DependencyProperty XProperty = DependencyProperty.Register("XProperty", typeof(double), typeof(VisualPin));
public static readonly DependencyProperty YProperty = DependencyProperty.Register("YProperty", typeof(double), typeof(VisualPin));
I'm creating a simple User Control with three properties. For simplicity let's assume these are A, B and C. Moreover C = A + B. I want to display all of them in TextBoxes (A, B - User Editable, C - read only). Whenever a user modifies A or B, the value of C should be updated.
I've already created Dependency Properties for A and B in MyControl.xaml.cs file.
public static readonly DependencyProperty AProperty =
DependencyProperty.Register("A", typeof(double),
typeof(MyControl), new FrameworkPropertyMetadata(0.0));
public double A
{
get { return (double)GetValue(AProperty); }
set { SetValue(AProperty, value); }
}
public static readonly DependencyProperty BProperty =
DependencyProperty.Register("B", typeof(double),
typeof(MyControl), new FrameworkPropertyMetadata(0.0));
public double B
{
get { return (double)GetValue(BProperty); }
set { SetValue(BProperty, value); }
}
My question is: what shall I do with C and where its definition should be kept ? Should the logic be coded inside a control or maybe it's a user's responsibility to remember about the relationship between the properties ?
You should declare another DependencyProperty for C in the UserControl and add property change handlers to your A and B properties to update the value of C when their values change. This should do the job:
public static readonly DependencyProperty AProperty =
DependencyProperty.Register("A", typeof(double),
typeof(MyControl), new UIPropertyMetadata(0.0, OnAOrBPropertyChanged));
public static readonly DependencyProperty BProperty =
DependencyProperty.Register("B", typeof(double),
typeof(MyControl), new UIPropertyMetadata(0.0, OnAOrBPropertyChanged));
public static void OnAOrBPropertyChanged(DependencyObject dependencyObject,
DependencyPropertyChangedEventArgs e)
{
dependencyObject.SetValue(CProperty, (double)dependencyObject.GetValue(AProperty) +
(double)dependencyObject.GetValue(BProperty));
}
You might like to view the Read-Only Dependency Properties page on MSDN for help with declaring a read-only DependencyProperty.
You need to make another dependency property for C also
You can try this:
public static readonly DependencyProperty AProperty =
DependencyProperty.Register("A", typeof(double),
typeof(MyControl), new FrameworkPropertyMetadata(OnAorBChange));
public double A
{
get { return (double)GetValue(AProperty); }
set { SetValue(AProperty, value); }
}
public static readonly DependencyProperty BProperty =
DependencyProperty.Register("B", typeof(double),
typeof(MyControl), new FrameworkPropertyMetadata(OnAorBChange));
public double B
{
get { return (double)GetValue(BProperty); }
set { SetValue(BProperty, value); }
}
public static readonly DependencyProperty CProperty =
DependencyProperty.Register("C", typeof(double),
typeof(MyControl), new FrameworkPropertyMetadata(null));
public double C
{
get { return (double)GetValue(CProperty); }
set { SetValue(CProperty, value); }
}
private static void OnAorBChange(DependencyObject obj,
DependencyPropertyChangedEventArgs args)
{
var obj1 = obj as MyControl;
obj1.C = obj1.A + obj1.B;
}
I assume you did the proper binding :)
I have created a custom attached behaviour:
public static class CustomItemsBehaviour
{
public static readonly DependencyProperty MyTestProperty =
DependencyProperty.RegisterAttached(
"MyTest",
typeof(string),
typeof(ItemsControl),
new UIPropertyMetadata(""));
public static string GetMyTest(ItemsControl itemsControl)
{
return (string)itemsControl.GetValue(MyTestProperty);
}
public static void SetMyTest(ItemsControl itemsControl, string value)
{
itemsControl.SetValue(MyTestProperty, value);
}
}
I am trying to use it like so:
<ListBox
ItemsSource="{Binding Path=Items}"
AttachedBehaviours:CustomItemsBehaviour.MyTest="{Binding TestValue}">
But it fails with:
{"A 'Binding' cannot be set on the 'SetMyTest' property of type 'ListBox'. A 'Binding' can only be set on a DependencyProperty of a DependencyObject."}
I want to bind some value in my view model to the value of MyTest. Is this possible to do?
The problem is in your registration code. You should pass typeof(CustomItemsBehaviour) as owner type:
public static readonly DependencyProperty MyTestProperty =
DependencyProperty.RegisterAttached(
"MyTest",
typeof(string),
typeof(CustomItemsBehaviour),
new UIPropertyMetadata(""));
I'm not sure what you are trying to acheive, but i think there is some mistakes in the declaration of your attached property. Try this :
public static class CustomItemsBehaviour
{
public static readonly DependencyProperty MyTestProperty =
DependencyProperty.RegisterAttached(
"MyTest",
typeof(string),
typeof(CustomItemsBehaviour),
new UIPropertyMetadata(""));
public static string GetMyTest(DependencyObject itemsControl)
{
return (string)itemsControl.GetValue(MyTestProperty);
}
public static void SetMyTest(DependencyObject itemsControl, string value)
{
itemsControl.SetValue(MyTestProperty, value);
}
}
See here DependencyProperty.RegisterAttached
Is it possible to store a reference to a Page in a Custom Control so that when the control is clicked that page loads (like a custom menu item)?
My code so far:
public class ccMenuItem : Button
{
public static readonly DependencyProperty TitleProperty = DependencyProperty.Register("Title", typeof(string), typeof(Control));
public static readonly DependencyProperty BackColorProperty = DependencyProperty.Register("BackColor", typeof(SolidColorBrush), typeof(Control), new UIPropertyMetadata(Brushes.White));
public static readonly DependencyProperty PageProperty = DependencyProperty.Register("Page", typeof(Page), typeof(Control));
public Page Page
{
get { return (Page)GetValue(PageProperty); }
set { SetValue(PageProperty, value); }
}
public string Title
{
get { return GetValue(TitleProperty).ToString(); }
set { SetValue(TitleProperty, value); }
}
static ccMenuItem()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(ccMenuItem), new FrameworkPropertyMetadata(typeof(ccMenuItem)));
}
}
The code compiles OK, however how do I assing a page (say the class is called vpn) to the Page property in XAML?
If your "application" is using a NavigationWindow instead of Window, then you can get to the NavigationService and tell it to change the page.
protected override void OnClick()
{
NavigationService ns = NavigationService.GetNavigationService(this);
ns.Navigate( Page );
}