How to use lambda statements to initialize UIPropertyMetaData in WPF - c#

I know this is basic, but I'm not getting it. I simply wish to initialize the dependency property Dashes as a double collection using the lambda operator.
What is the proper syntax?
Thank you.
public static readonly DependencyProperty DashesProperty =
DependencyProperty.Register("Dashes", typeof(DoubleCollection), typeof(CustomTextBlock),
new UIPropertyMetadata(
() =>
{
DoubleCollection d = new DoubleCollection();
d.Add(4);
d.Add(4);
return d;
}
));

First of all you should avoid passing default value for reference types in DP metadata because that will be shared across all instances of containing class which you didn't intend to.
Say, you declared two instances of CustomTextBlock, then both instances will refer to same list and any modification in list will be transparent to both instances. Unless you explicitly setting it from constructor or somewhere else.
Be careful with default values of DP for reference types.
Anyhow, if you still want it, here how it is done:
new UIPropertyMetadata(new DoubleCollection() { 4, 5 })
UPDATE:
If you pass default value in metadata, then DoubleCollection's gets freezed automatically i.e. you can't add/delete from the collection in that case.
var dashesCollection = new CustomTextBlock().Dashes.Add(5); // Will throw exception.
However, if you set it explicitly from constructor, it's not marked as Frozen and items can be added/deleted from the collection.
var dashesCollection = new CustomTextBlock().Dashes.Add(5); // Works fine.
So, essence is to set the value in constructor and not in metadata of DP identifier.

Unfortunately, that's not possible. You can only provide a value, not a value factory. The workaround is to initialize the property in the constructor:
public CustomTextBlock()
{
Dashes = new DoubleCollection {4, 4};
}
Actually, I just realized that since DoubleCollection is Freezable, passing an instance of DoubleCollection as the default value (as suggested by Rohit Vats) could work, as long as you call Freeze on it. You could do it like this:
public static readonly DependencyProperty DashesProperty =
DependencyProperty.Register("Dashes", typeof(DoubleCollection), typeof(CustomTextBlock),
new UIPropertyMetadata(CreateDefaultDashes()));
private static DoubleCollection CreateDefaultDashes()
{
var dashes = new DoubleCollection { 4, 4 };
dashes.Freeze();
return dashes;
}
This makes the collection immutable, which means it can safely be shared among instances of CustomTextBlock.
OK, actually it seems that the default value is automatically frozen, so you don't need to do anything special. It is safe as a default value, because it becomes immutable when it's frozen.

Related

List of properties not changing when set

In a class constructor I have a instantiate a list containing properties:
public MDInstrument() : base()
{
// bidss = new TickData[] {Bid0};
Bids = new List<TickData> { Bid0, Bid1, Bid2, Bid3, Bid4, Bid5, Bid6, Bid7, Bid8, Bid9, Bid10, Bid0, Bid11, Bid13, Bid14, Bid15, Bid6, Bid17, Bid18, Bid19};
Offers = new List<TickData> { Ask0, Ask1, Ask2, Ask3, Ask4, Ask5, Ask6, Ask7, Ask8, Ask9, Ask10, Ask0, Ask11, Ask13, Ask14, Ask15, Ask6, Ask17, Ask18, Ask19};
}
A method in the class updates the object in the list but why is the object always null ?
I must be missing something
Your problem is that to begin with Bid{x} and Ask{x} have not been instantiated, i.e. they're null, and then you store a reference to those values, and of course the reference is null. When you then later on update Bid0 (for example), then that reference is updated, but nothing can know that this is intended to be stored within your set.
Suggest that you change your list to be an array of a fixed known size (here, 20) which will be all nulls to begin with. Then change your getter/setter accessors for the individual Bid items to actually the array internally. Then you also don't need all of those separate Bid{x}/Ask{x} variables.

Creating a grab-bag (collection) of original references to objects

I'm looking for a type/method of collection where I can add an object to a group of objects, then separately change the attributes of that object, and have those changes reflected in the object within the collection.
I've heard that List<T> adds values by reference, so I figured that the reference would be to the same object. In other words, I assumed:
List<string> valuesList = new List<string>();
string initialValue = "Alpha";
valuesList.Add(initialValue);
initialValue = "Bravo";
bool incorrectAssumption = (valuesList[0] == "Bravo");
I had hoped that 'valuesList' would then contain the new value, "Bravo." Tried it out and I realized that the List copies the reference, it doesn't absorb it, so valueList still only has the "Alpha" value. Are there any ways to use a collection as a legitimate handful of the objects they contain?
And in case it helps to see the actual business need....
List<BaseWidget> widgets = new List<BaseWidget>();
DerivedWidget specialWidget = new DerivedWidget();
DerivedWidget extraSpecialWidget = new DerivedWidget();
widgets.Add(specialWidget);
widgets.Add(extraSpecialWidget);
specialWidget.Run();
extraSpecialWidget.Run();
if (!widgets.Any(x => x.RunSuccessfully)) return false;
(Where the Run() method sets the RunSuccessfully property, which I'd like to have reflected in the 'widgets' list.)
============================================================================
UPDATE
As it's been pointed out in the answers and comments, there's a bit of a discrepancy between the business need mock-up and the dry-run example. I'll condense the life-lesson into this: it seems List<objects> have their changes tracked, whereas List<values> don't.
Well. It seems that you don't understand what happens really. Here is great article about .net type internals.
Shortly, what happens in your example with strings:
You create list
You create variable initialValue of string type. Value of this variable stores in special local variables container. Because string is reference type, in container of local variables it contained as a pointer to object.
You create new string "Alpha", storing it in heap, and assign pointer (to this string) to your local variable.
Then you are adding object to list. In your List this object stored as pointer to somewhere.
Then you are changing content of local variable 'initialValue' by assign it to pointer to another string. So, now in local variable 'initialValue' is one pointer, in list is another pointer.
Well, what about solutions?
Wrap your string to some another class. Like this:
class Wrapper<T> {
public T Content {get;set;}
public Wrapper(T content) {
Content = content;
}
}
Usage:
void Main()
{
var valuesList = new List<Wrapper<string>>();
var initialValue = new Wrapper<string>("Alpha");
valuesList.Add(initialValue);
initialValue.Content = "Bravo";
Console.WriteLine(valuesList[0].Content);
}
A bit ugly syntax.
Use clojures:
void Main()
{
List<Func<string>> valuesList = new List<Func<string>>();
string initialValue = "Alpha";
valuesList.Add(() => initialValue);
initialValue = "Bravo";
Console.WriteLine(valuesList[0]() == "Bravo");
}
All references to non-value types will be passed by reference, List<T> or not. String is a value type, however, and will always be passed by value. They are also immutable, so any time you change one you're actually creating a new String.
For your example, you could create a wrapper type to contain your string, and store this in your List<T>.
It seems that your actual business case should work properly, unless they are declared as structs.

C# Syntax explanation

I saw a few days ago this syntax and wondered if someone could tell me how it is called, how does it work and where is it useful.
When I ask how does it work I mean that the Setters property is readonly(get),
And the second is what do this braces mean: "Setters = {".
http://msdn.microsoft.com/en-us/library/ms601374.aspx
Thanks
datagrid.CellStyle = new Style(typeof(DataGridCell))
{
// Cancel the black border which appears when the user presses on a cell
Setters = { new Setter(Control.BorderThicknessProperty, new Thickness(0)) } // End of Setters
} // End of Style
It is call object initializer and collection initializer and it allows you to set properties in the { .. } block when calling a constructor. Inside the block, you're using Setters = { ... } which is a collection initializer - it allows you to specify elements of a collection (here, you don't have to create a new instance of the collection - it just adds elements in curly braces). For more information see this MSDN page.
In general, the syntax of object initializers has a few options:
// Without explicitly mentioning parameter-less constructor:
new A { Prop1 = ..., Prop2 = ... }
// Specifying constructor arguments:
new A(...) { Prop1 = ..., Prop2 = ... }
The syntax for collection initializers looks like this:
// Creating new instance
new List<int> { 1, 2, 3 }
// Adding to existing instance inside object initializer:
SomeList = { 1, 2, 3 }
It is worth mentioning that this is closely related to anonymous types (where you don't give a type name - the compiler generates some hidden type and you can work with it using var):
// Create anonymous type with some properties
new { Prop1 = ..., Prop2 = ... }
All of these features are new in C# 3.0. See also this SO post which explains some tricky aspect of collection initializers (in the style you're using them).
instantiated the new object Style, and than setting its property Setters It's a c# 3.0 feature.
It seems to be setting default values when the object is being made. This is kind of like passing values to the constructor, but you aren't limited to just the options the constructor gives you.

Format for Passing a Collection to a Method

I'm using an API that has a method that requires this type of argument:
System.Collections.ObjectModel.Collection<GenericTickType> genericTickList
How do I instantiate an object for that argument? Here's what I've tried but it keeps saying that the method call has some invalid arguments.
List<TickType> ticks_to_get = new List<TickType> { TickType.Price };
I've tried instantiating a Collection directly instead of a List and that doesn't seem to work.
"I've tried instantiating a Collection directly instead of a List and that doesn't seem to work."
What error do you get? You can definitely create an instance of Collection<T> directly, it is not an abstract class and it has several public constructors, including one that's parameter-less. You can do this, for example:
var values = new System.Collections.ObjectModel.Collection<int> { 1,2,3,4 };
I noticed your sample code has a GenericTickType and a TickType. Is this a mistake or do you actually have two classes? You said it's an enum (which one?), so one cannot possibly derive from the other. If they are two enum types, Collection<GenericTickType> and Collection<TickType> are two different classes and one is not assignable to the other.
Now, if TickType is castable to GenericTickType (and they probably are if they are both enums, and assuming they share the same numeric values), you still cannot cast Collection<TickType> to Collection<GenericTickType>. There's no contra/co-variance in C# for most classes yet (coming in C# 4). But you could cast each TickType by doing something like this:
List<GenericTickType> list = new List<GenericTickType> { (GenericTickType)TickType.Price };
list.Add((GenericTickType)TickType.Price); // add more...
Collection<GenericTickType>genericTicks = new Collection<GenericTickType>(list);
If you already have a List<TickType> and have access to C# 3.0 and LINQ, you can do this:
List<TickType> ticks = new List<TickType> { TickType.Price };
list.Add(TickType.Price); // add more...
List<GenericTickType> castedList = ticks.Cast<GenericTickType>().ToList();
Collection<GenericTickType>genericTicks = new Collection<GenericTickType>(castedList);
This uses the LINQ Cast<T>() and ToList<T>() extension methods to cast each TickType in the original list to GenericTickType and creating a new List<GenericTickType> which is used to instantiate the Collecion<GenericTickType>. (I avoided using var so you could see the types in each step).
You can't pass a List<> as a Collection<>
Maybe you have problems with covariance/contravariance? You have to do the cast on your own:
List<TickType> ticks_to_get = new Collection<TickType> { TickType.Price };
genericTickList = (Collection<GenericTickType>) ticks_to_get;
Look at Dave Bauman's answer ... unless TickType.Price doesn't return an object of type TickType it will not work
EDIT: Since GenericTickType is an enum - which API are you using? Is it of your company - can you change it? It seems to be strange that you are asked to pass a collection of enum values. See, if you can change the enum to a flagged enum ... and then pass the required values by combining them with the or-operator.
What is the type of GenericTickType? Is it an enum or class? I am assuming enum. If that is the case, modify your code as such:
Collection<GenericTickType> ticks_to_get = new Collection<GenericTickType>() { GenericTickType.Price };
The above works on 3.5 framework.
You can't use {} to initialize a Collection. You can do something like this, however:
List<TickType> ticks_to_get =
new List<TickType>( new TickType[] { TickType.Price });
or
List<TickType> ticks_to_get = new List<TickType>();
ticks_to_get.Add(TickType.Price);

Is there a way to get a property value of an object using PropertyPath class?

I want to get a value of a nested property of an object (something like Person.FullName.FirstName). I saw that in .Net there is a class named PropertyPath, which WPF uses for a similar purpose in Binding.
Is there a way to reuse WPF's mechanism, or should I write one on my own.
Reusing the PropertyPath is tempting as it supports traversing nested properties as you point out and indexes. You could write similar functionality yourself, I have myself in the past but it involves semi-complicated text parsing and lots of reflection work.
As Andrew points out you can simply reuse the PropertyPath from WPF. I'm assuming you just want to evaluate that path against an object that you have in which case the code is a little involved. To evaluate the PropertyPath it has to be used in a Binding against a DependencyObject. To demonstrate this I've just created a simple DependencyObject called BindingEvaluator which has a single DependencyProperty. The real magic then happens by calling BindingOperations.SetBinding which applies the binding so we can read the evaluated value.
var path = new PropertyPath("FullName.FirstName");
var binding = new Binding();
binding.Source = new Person { FullName = new FullName { FirstName = "David"}}; // Just an example object similar to your question
binding.Path = path;
binding.Mode = BindingMode.TwoWay;
var evaluator = new BindingEvaluator();
BindingOperations.SetBinding(evaluator, BindingEvaluator.TargetProperty, binding);
var value = evaluator.Target;
// value will now be set to "David"
public class BindingEvaluator : DependencyObject
{
public static readonly DependencyProperty TargetProperty =
DependencyProperty.Register(
"Target",
typeof (object),
typeof (BindingEvaluator));
public object Target
{
get { return GetValue(TargetProperty); }
set { SetValue(TargetProperty, value); }
}
}
If you wanted to extend this you could wire up the PropertyChanged events to support reading values that change. I hope this helps!
I don't see any reason why you couldn't reuse it.
See PropertyPath:
Implements a data structure for
describing a property as a path below
another property, or below an owning
type. Property paths are used in data
binding to objects, and in storyboards
and timelines for animations.

Categories

Resources