I have a string dependency property (SearchText), when updated, needs to update a collection dependency property (Results).
My collection dp:
public IEnumerable<string> Results{
get { return (IEnumerable<string>) GetValue(ResultsProperty); }
set { SetValue(ResultsProperty, value); }
}
public static readonly DependencyProperty ResultsProperty=
DependencyProperty.Register("Results", typeof(IEnumerable<string>), typeof(MainWindowVM), new UIPropertyMetadata(new List<string>()));
I tried this with no luck. i put a breakpoint at the Results = .... line and it never got hit.
public string SearchText{
get { return (string) GetValue(SearchTextProperty); }
set {
Results =
from T in Tree.GetPeople(value)
select T.FullName;
SetValue(SearchTextProperty, value);
}
}
public static readonly DependencyProperty SearchTextProperty=
DependencyProperty.Register("SearchText", typeof(string), typeof(MainWindowVM), new UIPropertyMetadata(""));
XAML:
<TextBox DockPanel.Dock="Top" Text="{Binding SearchValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
<ListBox DockPanel.Dock="Top" ItemsSource="{Binding NameResults}" SelectedItem="{Binding Search}" />
When setting a dependency property in XAML or through a binding, the runtime will always bypass the instance property alias and directly call GetValue and SetValue. It is because of this that your instance setter isn't being invoked.
What you may wish to consider doing is registering a method with the dependency property which will be invoked when the property changes. This is most easily done when creating the PropertyMetadata for the dependency property.
I believe the following example does what you're looking to do. In the example, my class has two depencency properties aliased as First and Second. When I set the value for First, my change handler is invoked and I set the value of Second.
public class DependencyPropertyTest : DependencyObject
{
public static readonly DependencyProperty FirstProperty;
public static readonly DependencyProperty SecondProperty;
static DependencyPropertyTest()
{
FirstProperty = DependencyProperty.Register("FirstProperty",
typeof(bool),
typeof(DependencyPropertyTest),
new PropertyMetadata(false, FirstPropertyChanged));
SecondProperty = DependencyProperty.Register("SecondProperty",
typeof(string),
typeof(DependencyPropertyTest),
new PropertyMetadata(null));
} // End constructor
private bool First
{
get { return (bool)this.GetValue(FirstProperty); }
set { this.SetValue(FirstProperty, value); }
} // End property First
private string Second
{
get { return (string)this.GetValue(SecondProperty); }
set { this.SetValue(SecondProperty, value); }
} // End property Second
private static void FirstPropertyChanged(DependencyObject dependencyObject,
DependencyPropertyChangedEventArgs ea)
{
DependencyPropertyTest instance = dependencyObject as DependencyPropertyTest;
if (instance == null)
{
return;
}
instance.Second = String.Format("First is {0}.", ((bool)ea.NewValue).ToString());
} // End method FirstPropertyChanged
} // End class DependencyPropertyTest
I hope that helps.
As I commented, the currently accepted answer is correct in the principle, except that it MUST use the SetCurrentValue method instead of doing a simple assignment. See this answer for more explanation about it.
Here is the same code with this fix:
public class DependencyPropertyTest : DependencyObject
{
public static readonly DependencyProperty FirstProperty;
public static readonly DependencyProperty SecondProperty;
static DependencyPropertyTest()
{
FirstProperty = DependencyProperty.Register("FirstProperty",
typeof(bool),
typeof(DependencyPropertyTest),
new PropertyMetadata(false, FirstPropertyChanged));
SecondProperty = DependencyProperty.Register("SecondProperty",
typeof(string),
typeof(DependencyPropertyTest),
new PropertyMetadata(null));
} // End constructor
private bool First
{
get { return (bool)this.GetValue(FirstProperty); }
set { this.SetValue(FirstProperty, value); }
} // End property First
private string Second
{
get { return (string)this.GetValue(SecondProperty); }
set { this.SetValue(SecondProperty, value); }
} // End property Second
private static void FirstPropertyChanged(DependencyObject dependencyObject,
DependencyPropertyChangedEventArgs ea)
{
DependencyPropertyTest instance = dependencyObject as DependencyPropertyTest;
if (instance == null)
{
return;
}
// SetCurrentValue should be used here!
instance.SetCurrentValue(SecondProperty,
String.Format("First is {0}.", ((bool)ea.NewValue).ToString());
} // End method FirstPropertyChanged
} // End class DependencyPropertyTest
The Order that you put on it your dependency property is very important
the fist one put in the class file, will be executed fist then the one down to it
class A {
dependecy 1
dependecy 2
dependecy 3
}
it will be called in the order set on the class, so just order your dependency on the order you want
if 1 depend on 2 -> put 2 first, then 1 like this
class A {
dependecy 2
dependecy 1
dependecy 3
}
Related
I am writing two dependency properties and I keep getting the "[Property] was already registered by 'FrameworkElement'" error in the design window of VS11. Here is a snippet of my code
public static readonly DependencyProperty IsEditingNumberProperty =
DependencyProperty.Register("IsEditingNumbers", typeof(bool), typeof(FrameworkElement),
new FrameworkPropertyMetadata(true, FrameworkPropertyMetadataOptions.AffectsRender));
the problem seems to be the 3rd parameter (owner parameter typeof(FrameworkElement)). If I set the 3rd parameter to the class the contains two dependency properties, the error goes away, but I cannot use the properties directly from xaml. I would have to add ownership for each dependency property before I use it.
Actually, It does render correctly, but only when I first open it. Immediately after the first render it will give me an exception. At runtime, it seems to work perfectly.
Am I doing something wrong and is there a way to get rid of this annoying error?
---- Edit -----
Here is my custom class (includes 2 of the Dependency Properties):
public partial class EditableTextBox : UserControl
{
#region Dependency Properties
public static readonly DependencyProperty IsEditingNumberProperty =
DependencyProperty.Register("IsEditingNumber", typeof(bool), typeof(FrameworkElement),
new FrameworkPropertyMetadata(true, FrameworkPropertyMetadataOptions.AffectsRender));
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register("Text", typeof(string), typeof(FrameworkElement),
new FrameworkPropertyMetadata("0", FrameworkPropertyMetadataOptions.AffectsRender)
{
CoerceValueCallback = new CoerceValueCallback((sender,value) =>
{
return expressionRestaraint.Match((string)value).Value;
})
});
#endregion
public static Regex expressionRestaraint = new Regex("[-a-zA-z0-9+*.\\(\\)\\[\\]\\{\\}]*");
public string Text
{
get { (string)GetValue(TextProperty); }
set
{
SetValue(TextProperty, value);
tbxValue.Text = (string)GetValue(TextProperty);
}
}
public bool IsEditingNumber
{
get
{
return (bool)GetValue(IsEditingNumberProperty);
}
set
{
bool old = (bool)GetValue(IsEditingNumberProperty);
if (old != value)
{
if (!value)
stopEditing();
else
startEditing();
SetValue(IsEditingNumberProperty, value);
}
}
} . . .
Use in Main Class:
<Window x:Class="VisualMathExpression.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:edit="clr-namespace:VisualMathExpression.EditableTextBox"
xmlns:all="clr-namespace:VisualMathExpression"
Title="MainWindow" Height="350" Width="525">
<StackPanel>
<edit:EditableTextBox HorizontalAlignment="Center" VerticalAlignment="Center"
Text="af" IsEditingNumber="True" /> . . .
--- Edit ---
Wrapper fixed (problem that cause xaml property not to change when ownership belonged to the declared class)
public partial class EditableTextBox : UserControl
{
#region Dependency Properties
public static readonly DependencyProperty IsEditingNumberProperty =
DependencyProperty.Register("IsEditingNumber", typeof(bool), typeof(EditableTextBox),
new FrameworkPropertyMetadata(true, FrameworkPropertyMetadataOptions.AffectsRender)
{
PropertyChangedCallback = new PropertyChangedCallback((sender, arg) =>
{
EditableTextBox ed = sender as EditableTextBox;
if (!(bool)arg.NewValue)
ed.stopEditing();
else
ed.startEditing();
}),
});
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register("Text", typeof(string), typeof(EditableTextBox),
new FrameworkPropertyMetadata("0", FrameworkPropertyMetadataOptions.AffectsRender)
{
PropertyChangedCallback = new PropertyChangedCallback((sender,arg) =>
{
EditableTextBox ed = sender as EditableTextBox;
ed.tbxValue.Text = arg.NewValue as string;
}),
CoerceValueCallback = new CoerceValueCallback((sender,value) =>
{
return expressionRestaraint.Match((string)value).Value;
})
});
#endregion
public static Regex expressionRestaraint = new Regex("[-a-zA-z0-9+*.\\(\\)\\[\\]\\{\\}]*");
public string Text
{
get { return (string)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
public bool IsEditingNumber
{
get { return (bool)GetValue(IsEditingNumberProperty); }
set { SetValue(IsEditingNumberProperty, value); }
}
The third parameter ownerType of the DependencyProperty.Register method must be the class that declares the property.
If your class is MyClass the declaration would have to look like this:
public class MyClass : DependencyObject
{
public static readonly DependencyProperty IsEditingNumberProperty =
DependencyProperty.Register(
"IsEditingNumber", typeof(bool), typeof(MyClass), ...);
// CLR wrapper
public bool IsEditingNumber
{
get { return (bool)GetValue(IsEditingNumberProperty); }
set { SetValue(IsEditingNumberProperty, value); }
}
}
I have a user control in WPF which I want to pass a list of items to when I use the user control in another window (the user control contains a ComboBox and label and has some important functionality). This works fine if I have a single control on my page, but if I have two I get the values listed from both my user controls, presumably because the DependencyProperty is static. I can't remove the static as it throws an error when registering the dependency property.
public static readonly DependencyProperty ComboBoxValuesProperty =
DependencyProperty.Register("ComboBoxValues", typeof(ObservableCollection<ComboBoxValue>), typeof(SystemConfigComboBox),
new PropertyMetadata(new ObservableCollection<ComboBoxValue>()));
public ObservableCollection<ComboBoxValue> ComboBoxValues
{
get { return GetValue(ComboBoxValuesProperty) as ObservableCollection<ComboBoxValue>; }
set { SetValue(ComboBoxValuesProperty, value); }
}
Below shows both user controls ComboBoxes containing Value1 and Value2
<customEditors:SystemConfigComboBox SystemConfigEntry="Entry1" ComboBoxLabel="Combo 1" ComboBoxWidth="300">
<customEditors:SystemConfigComboBox.ComboBoxValues>
<customEditors:ComboBoxValue DisplayValue="Value1" ActualValue="VALUE1" />
</customEditors:SystemConfigComboBox.ComboBoxValues>
</customEditors:SystemConfigComboBox>
<customEditors:SystemConfigComboBox SystemConfigEntry="Entry2" ComboBoxLabel="Combo 2" ComboBoxWidth="300">
<customEditors:SystemConfigComboBox.ComboBoxValues>
<customEditors:ComboBoxValue DisplayValue="Value2" ActualValue="VALUE2" />
</customEditors:SystemConfigComboBox.ComboBoxValues>
</customEditors:SystemConfigComboBox>
and just for information the ComboBoxValue class:-
public class ComboBoxValue : FrameworkElement
{
public static readonly DependencyProperty DisplayValueProperty =
DependencyProperty.Register("DisplayValue", typeof(string), typeof(ComboBoxValue));
public static readonly DependencyProperty ActualValueProperty =
DependencyProperty.Register("ActualValue", typeof(string), typeof(ComboBoxValue));
public string DisplayValue
{
get { return (string)GetValue(DisplayValueProperty); }
set { SetValue(NameProperty, value); }
}
public string ActualValue
{
get { return (string)GetValue(ActualValueProperty); }
set { SetValue(ActualValueProperty, value); }
}
}
You should initialize the ObservableCollection in the constructor of the control class and not in the DependencyProperty.Register method:
public class SystemConfigComboBox
{
public SystemConfigComboBox()
{
ComboBoxValues = new ObservableCollection<ComboBoxValue>();
}
public static readonly DependencyProperty ComboBoxValuesProperty =
DependencyProperty.Register("ComboBoxValues", typeof(ObservableCollection<ComboBoxValue>), typeof(SystemConfigComboBox)));
...
}
Please refer to MSDN for more information about this: https://msdn.microsoft.com/en-us/library/aa970563(v=vs.110).aspx
I am writing two dependency properties and I keep getting the "[Property] was already registered by 'FrameworkElement'" error in the design window of VS11. Here is a snippet of my code
public static readonly DependencyProperty IsEditingNumberProperty =
DependencyProperty.Register("IsEditingNumbers", typeof(bool), typeof(FrameworkElement),
new FrameworkPropertyMetadata(true, FrameworkPropertyMetadataOptions.AffectsRender));
the problem seems to be the 3rd parameter (owner parameter typeof(FrameworkElement)). If I set the 3rd parameter to the class the contains two dependency properties, the error goes away, but I cannot use the properties directly from xaml. I would have to add ownership for each dependency property before I use it.
Actually, It does render correctly, but only when I first open it. Immediately after the first render it will give me an exception. At runtime, it seems to work perfectly.
Am I doing something wrong and is there a way to get rid of this annoying error?
---- Edit -----
Here is my custom class (includes 2 of the Dependency Properties):
public partial class EditableTextBox : UserControl
{
#region Dependency Properties
public static readonly DependencyProperty IsEditingNumberProperty =
DependencyProperty.Register("IsEditingNumber", typeof(bool), typeof(FrameworkElement),
new FrameworkPropertyMetadata(true, FrameworkPropertyMetadataOptions.AffectsRender));
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register("Text", typeof(string), typeof(FrameworkElement),
new FrameworkPropertyMetadata("0", FrameworkPropertyMetadataOptions.AffectsRender)
{
CoerceValueCallback = new CoerceValueCallback((sender,value) =>
{
return expressionRestaraint.Match((string)value).Value;
})
});
#endregion
public static Regex expressionRestaraint = new Regex("[-a-zA-z0-9+*.\\(\\)\\[\\]\\{\\}]*");
public string Text
{
get { (string)GetValue(TextProperty); }
set
{
SetValue(TextProperty, value);
tbxValue.Text = (string)GetValue(TextProperty);
}
}
public bool IsEditingNumber
{
get
{
return (bool)GetValue(IsEditingNumberProperty);
}
set
{
bool old = (bool)GetValue(IsEditingNumberProperty);
if (old != value)
{
if (!value)
stopEditing();
else
startEditing();
SetValue(IsEditingNumberProperty, value);
}
}
} . . .
Use in Main Class:
<Window x:Class="VisualMathExpression.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:edit="clr-namespace:VisualMathExpression.EditableTextBox"
xmlns:all="clr-namespace:VisualMathExpression"
Title="MainWindow" Height="350" Width="525">
<StackPanel>
<edit:EditableTextBox HorizontalAlignment="Center" VerticalAlignment="Center"
Text="af" IsEditingNumber="True" /> . . .
--- Edit ---
Wrapper fixed (problem that cause xaml property not to change when ownership belonged to the declared class)
public partial class EditableTextBox : UserControl
{
#region Dependency Properties
public static readonly DependencyProperty IsEditingNumberProperty =
DependencyProperty.Register("IsEditingNumber", typeof(bool), typeof(EditableTextBox),
new FrameworkPropertyMetadata(true, FrameworkPropertyMetadataOptions.AffectsRender)
{
PropertyChangedCallback = new PropertyChangedCallback((sender, arg) =>
{
EditableTextBox ed = sender as EditableTextBox;
if (!(bool)arg.NewValue)
ed.stopEditing();
else
ed.startEditing();
}),
});
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register("Text", typeof(string), typeof(EditableTextBox),
new FrameworkPropertyMetadata("0", FrameworkPropertyMetadataOptions.AffectsRender)
{
PropertyChangedCallback = new PropertyChangedCallback((sender,arg) =>
{
EditableTextBox ed = sender as EditableTextBox;
ed.tbxValue.Text = arg.NewValue as string;
}),
CoerceValueCallback = new CoerceValueCallback((sender,value) =>
{
return expressionRestaraint.Match((string)value).Value;
})
});
#endregion
public static Regex expressionRestaraint = new Regex("[-a-zA-z0-9+*.\\(\\)\\[\\]\\{\\}]*");
public string Text
{
get { return (string)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
public bool IsEditingNumber
{
get { return (bool)GetValue(IsEditingNumberProperty); }
set { SetValue(IsEditingNumberProperty, value); }
}
The third parameter ownerType of the DependencyProperty.Register method must be the class that declares the property.
If your class is MyClass the declaration would have to look like this:
public class MyClass : DependencyObject
{
public static readonly DependencyProperty IsEditingNumberProperty =
DependencyProperty.Register(
"IsEditingNumber", typeof(bool), typeof(MyClass), ...);
// CLR wrapper
public bool IsEditingNumber
{
get { return (bool)GetValue(IsEditingNumberProperty); }
set { SetValue(IsEditingNumberProperty, value); }
}
}
I have a custom UserControl, which contains collection of custom objects.
public class Question : FrameworkElement
{
public readonly static DependencyProperty FullNameProperty =
DependencyProperty.Register("FullName", typeof(string), typeof(Question));
public readonly static DependencyProperty ShortNameProperty =
DependencyProperty.Register("ShortName", typeof(string), typeof(Question));
public readonly static DependencyProperty RecOrderProperty =
DependencyProperty.Register("RecOrder", typeof(int), typeof(Question));
public readonly static DependencyProperty AnswerProperty =
DependencyProperty.Register("Answer", typeof(string), typeof(Question));
public string FullName
{
get { return (string)GetValue(FullNameProperty); }
set { SetValue(NameProperty, value); }
}
public string ShortName
{
get { return (string)GetValue(ShortNameProperty); }
set { SetValue(ShortNameProperty, value); }
}
public string Answer
{
get { return (string)GetValue(AnswerProperty); }
set { SetValue(AnswerProperty, value); }
}
public int RecOrder
{
get { return (int)GetValue(RecOrderProperty); }
set { SetValue(RecOrderProperty, value); }
}
}
In my Control code-behind I have
public readonly static DependencyProperty QuestionsProperty =
DependencyProperty.Register("Questions", typeof(ObservableCollection<Question>), typeof(FormQuestionReportViewer),
new PropertyMetadata(new ObservableCollection<Question>()));
public ObservableCollection<Question> Questions
{
get { return GetValue(QuestionsProperty) as ObservableCollection<Question>; }
set { SetValue(QuestionsProperty, value); }
}
And in xaml markup I can define my control like this
<custom:CustomControl>
<custom:CustomControl.Questions>
<custom:Question FullName="smth text" ShortName="smth text" RecOrder="1" Answer="Yes" />
<custom:Question FullName="smth text" ShortName="smth text" RecOrder="2" Answer="Yes" />
</custom:CustomControl.Questions>
</custom:CustomControl>
It's works well, but I want to make binding my collection property in xaml like this
<custom:CustomControl>
<custom:CustomControl.Questions Items="{binding Path=Questions}">
<custom:Question FullName="{binding Name}" ShortName="{binding ShortName}" RecOrder="{binding RecOrder}" Answer={binding Answer}" />
</custom:CustomControl.Questions>
</custom:CustomControl>
How I can make that binding?
You would have to expose two separate properties, much like an ItemsControl which has an Items and ItemsSource property. It looks like you want to be able to add items using a binding and explicitly by adding to your collection. This behavior would differ from an ItemsControl, which only allows you to use the Items or ItemsSource property, but not both at the same time.
There is nothing preventing you from adding support for both ways of specifying items though, but it would be more work on your part.
First, you'd need a DependencyProperty, such as IEnumerable QuestionsSource, which you could bind to:
public readonly static DependencyProperty QuestionsSourceProperty =
DependencyProperty.Register("QuestionsSource",
typeof(IEnumerable),
typeof(FormQuestionReportViewer),
new PropertyMetadata(null));
public IEnumerable QuestionsSource
{
get { return GetValue(QuestionsSourceProperty) as IEnumerable; }
set { SetValue(QuestionsSourceProperty, value); }
}
second, you would need a regular CLR property, such as ObservableCollection<Question> Questions, which you could add items to explicitly:
private ObservableCollection<Question> questions = new ObservableCollection<Question>();
public ObservableCollection<Question> Questions
{
get { return questions; }
}
Then you could use these properties like so:
<custom:CustomControl QuestionsSource="{Binding Path=Questions}">
<custom:CustomControl.Questions>
<custom:Question FullName="{Binding Name}" ShortName="{Binding ShortName}" RecOrder="{Binding RecOrder}" Answer={Binding Answer}" />
</custom:CustomControl.Questions>
</custom:CustomControl>
The extra work comes when you want to get the full list of items. You'd need to union the two collections into a single collection. This unified collection would be exposed as a third property, which returns a read-only collection.
I am new to WPF and this is my first post. I have created a class called 'Fruit' that descends from 'DependencyObject' and adds and extra property called 'Apple'. I have created a new custom control that includes a Dependency Property called 'MyFruit' of type 'Fruit'. My question is, how can i set the default value for the properties within 'MyFruit' object (i.e. the 'Apple' property? I would like to set this in XAML using the object.
public class Gauge : Control
{
.
.
.
//---------------------------------------------------------------------
#region MyFruit Dependency Property
public Fruit MyFruit
{
get { return (Fruit)GetValue(MyFruitProperty); }
set { SetValue(MyFruitProperty, value); }
}
public static readonly DependencyProperty MyFruitProperty =
DependencyProperty.Register("MyFruit", typeof(Fruit), typeof(CircularGauge), null);
#endregion
}
//-------------------------------------------------------------------------
#region Fruit class
public class Fruit : DependencyObject
{
private int apple;
public int Apple
{
get { return apple; }
set { apple = value; }
}
}
#endregion
Instead of null in your dependency property metadata insert
new UIPropertyMetadata("YOUR DEFAULT VALUE GOES HERE")
So now it becomes
public static readonly DependencyProperty MyFruitProperty =
DependencyProperty.Register("MyFruit", typeof(Fruit), typeof(CircularGauge), new UIPropertyMetadata("YOUR DEFAULT VALUE GOES HERE"));
You need to use PropertyMetaData like this:
class MyValidation
{
public bool status
{
get { return (bool)GetValue(statusProperty); }
set { SetValue(statusProperty, value); }
}
public static readonly DependencyProperty statusProperty = DependencyProperty.Register("status", typeof(bool), typeof(MyValidation),new PropertyMetadata(false));
}