Dynamic Setting of WPF Control Properties - wpf

I'd like to be able to set properties for various controls in my WPF application where I have the string name of a control and the string name of its type, but I don't know how to do it. So far I have this:
( (TabItem)this.FindName( "tabPatient" ) ).IsEnabled = false;
I can iterate through a list of control names and set properties with just the string name of the control, but what I want is to be able to do it without having to perform an explicit hard-coded cast of the object type.
Is there a way to do this?
Thanks.

The type does not really matter, right? All you need is a property, so you could do something like this:
var obj = FindName("name");
obj.GetType().GetProperty("IsEnabled").SetValue(obj, false);
Alternatively you could use dynamic, which does about the same thing:
dynamic dynObject = (dynamic)FindName("name");
dynObject.IsEnabled = false;

You can navigate WPF's VisualTree to find an element by name and set a property.
For example, using some helper classes found here you can say
foreach(var s in controlList)
{
var ctrl = VisualTreeHelpers.FindChild<UIElement>(this, s);
if (ctrl != null)
ctrl.IsEnabled = false;
}
You don't really need to know the control type. All controls with an IsEnabled property are based off of UIElement, so just cast the control as a UIElement to modify it's IsEnabled property

Related

How to store additional data in a listbox?

I have a wpf application using Caliburn.Micro. I need to bind a ListBox to a collection of objects, but I want to display one of the object's fields, and also somehow to attach a Guid (another field) to each item. Could you please tell me how I can do that? I don't know if Caliburn.Micro has something specific for it, or I just have to use WPF.
Thanks.
(sorry for my bad english)
If the Guid field is part of your object, you do not need to store it on another place. The listbox will show a field but it is still bounded to the original object, you can get it with ((MyObjectType)MyListBox.SelectedItem).Guid. With Caliburn it is even easier since you just need to bind a property on your VM to SelectedItem.
But if the Guid is not part of your object, you can use the Tag property, as Paul Sasik said. I do not like to use the Tag property so this is another easy (and more flexbible) way you can solve this, you need to encapsulate your object on another object:
public class GuidObject<T>
{
public T Instance {get;set;}
public Guid Guid {get;set;}
}
You can use it like this:
//this is your original guidless items list
var myObjectsList = new[] { new MyObject { Name = "Dostoyevsky" },
new MyObject { Name = "Ozzy" } };
var myObjectsWithGuidList = new ObservableCollection<GuidObject<MyObject>>();
//encapsulate each MyObject on a GuidObject and include a Guid
//if your myObjectsList is already a List, you do not need to call ToList()
myObjectsList.ToList().ForEach(o => myObjectsWithGuidList.Add(new GuidObject<MyObject>() { Instance = o, Guid = Guid.NewGuid() }));
//now myObjectsWithGuidList contains a list of your itens and a Guid field, you can bind it to your ListBox
Here you can see this running.
You can use the Tag property of each ListBox object to store arbitrary information.
From the link:
This property is analogous to Tag properties in other Microsoft
programming models, such as Microsoft Visual Basic for Applications
(VBA) or Windows Forms. Tag is intended to provide a pre-existing
property location where you can store some basic custom information
about any FrameworkElement without requiring you to subclass an
element.
Because this property takes an object, you would need to use the
property element usage in order to set the Tag property in Extensible
Application Markup Language (XAML) to anything other than an object
with a known and built-in type converter, such as a string. Objects
used in this manner are typically not within the standard Windows
Presentation Foundation (WPF) namespaces and therefore may require
namespace mapping to the external namespace in order to be introduced
as XAML elements.

WPF Reflection, Late Binding

I am trying to set properties on WPF controls (height, width, fontweight, margin and many others) from data that is read through an XML file. I am not going to know what properties are going to be set beforehand. I was wondering if anyone knows a way to do this through reflection?
At the moment I have managed to assign all of the primitive types and enum types using reflection but I am having a little bit of trouble with properties like FontWeight, Margin, Background and many others that require other objects in setting the property for instance: To set a FontWeight property of a button you have to do it like this.
button.FontWeight = Fontweights.Bold;
or a Margin
button.Margin = new Thickness(10, 10, 10, 10);
As there are a possible 150 + properties that could be set on the controls in WPF I just wanted to avoid this sort of code.
public void setProperties(String propertyName, string PropertyValue
{
if(propertyName = "Margin")
{
Set the margin.....
}
else if (propertyName = "FontWeight")
{
set the FontWeight....
}
}
and so on for each possible property that can be set on WPF controls.
Behind the scenes, XAML uses TypeConverters to convert from string to the specified type. You can use them yourself, since each of the types you mentioned has a default TypeConverter specified using the TypeConverterAttribute. You can use it like this (or alternatively, make the method generic):
object Convert(Type targetType, string value)
{
var converter = TypeDescriptor.GetConverter(targetType);
return converter.ConvertFromString(value);
}
Then each of the following works as expected:
Convert(typeof(Thickness), "0 5 0 0")
Convert(typeof(FontWeight), "Bold")
Convert(typeof(Brush), "Red")
It's actually really simple. You read your string values into properties on a ViewModel, set that view model to your DataContext, and in xaml bind up your properties. Binding uses TypeConverters automatically.
You can do something like this
typeof(Button).GetProperty("FontWeight").SetValue(button1,GetFontWeight("Bold"), null);
EDIT:
You can have a mapping function that convert string to property value
FontWeight GetFontWeight(string value)
{
swithc(value)
{
case "Bold" : return FontWeights.Bold; break;
...
}
}

how do I find out themed WinForms control's theme-based property values? for DevExpress or for WinForms in general

I am dealing with this issue in DevExpress.XtraEditors context, but maybe the answer would also apply to other situations where themes are used for WinForms controls.
Basically, how do I find out what collection of property settings does a themed control have? Is there a way for me to go look at the theme definition? Also, can I look at these settings dynamically, i.e. from within the app during execution (much like I can print out unthemed Appearance.BackColor during execution)?
I'm not certain what you're looking for, but if you're interested in finding all of a control's (or control Type's) 'Appearance' properties you can use the TypeDescriptor.GetProperties method. This method returns a PropertyDescriptorCollection from which you can pick out the properties with the CategoryAttribute.Appearance property.
You can use this method on an instance of the control:
PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(myButtonInstance);
Or, on a control Type:
PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(typeof(Button));
But once you get a PropertyDescriptorCollection you can test for the presence of CategoryAttribute.Appearance (which means the property appears in the control's 'Appearance' section - assuming Browsable == true) like this:
foreach (PropertyDescriptor property in properties) {
if (property.Attributes.Contains(CategoryAttribute.Appearance)) {
Console.WriteLine("{0} - {1}", property.Name, property.Description);
// Do whatever...
}
}

Find control from LayoutRoot in Silverlight

I have a multiple textblocks on my usercontrol Layoutroot the problem is how can I find a particular TextBlock by its name?
Thanx
var myElement =
((FrameworkElement)System.Windows.Application.Current.RootVisual)
.FindName("TextBlockName");
should work in this case, if the textblock has already been rendered.
To be able to easily traverse the visual tree more generally like #ColinE mentioned, you can also use the Silverlight toolkit.
// requires System.Windows.Controls.Toolkit.dll
using System.Windows.Controls.Primitives;
var myElement = myRoot.GetVisualDescendants().OfType<TextBlock>()
.Where(txb => txb.Name == "TextBlockName").FirstOrDefault();
If you are creating a UserControl, any element that you name via x:Name should be available to you as a field in your code-behind.
If you are not creating a UserControl, you can search the visual tree via Linq to VisualTree ...
TextBlock block = LayoutRoot.Descendants<TextBlock>()
.Cast<TextBlock>()
.SingleOrDefault(t => t.Name == "TextBlockName");
hey Masn i was write some code and similiar conditions in my case that all ok.
this is the case (have many listbox and named variables diferenciated by number in final the name Example: listAttachment1,listAttachment2,listAttachment3,..,etc). To best explication show my code:
public void refreshAttachmentList(ListlistOfControlsRequest, int identifier)
{
string valueName = "attachmentsField_"+identifier;
var mylistAttachment = ((FrameworkElement)System.Windows.Application.Current.RootVisual).FindName(valueName);
ListBox listAttachRequest = mylistAttachment as ListBox;
listAttachRequest.ClearValue(ItemsControl.ItemsSourceProperty);
listAttachRequest.ItemsSource = listOfAttachmentsControls;
listAttachRequest.....all properties
}

Rebinding all properties of all elements in the visual tree?

I know that I can rebind all instances of a specific property for a specific type of element, as in this method that rebinds the Text property of all Textblocks.
public void Rebind()
{
foreach (var textBlock in LayoutRoot.GetDescendents().OfType<TextBlock>())
{
BindingExpression bindExp = textBlock.GetBindingExpression(TextBlock.TextProperty);
if (bindExp != null)
{
Binding bind = bindExp.ParentBinding;
textBlock.SetBinding(TextBlock.TextProperty, bind);
}
}
}
What I want to be able to do though is rebind all properties that have bindings for all elements in the visual tree. More specifically I would like to rebind all bindings that use a specific value converter. How might I do so?
This isn't realistically acheivable since FrameworkElement provides no way to enumerate the set of binding expressions that currently apply to it.
In order to achieve this you would need to have first collected all the dependency properties that may apply (at least at a per element type but that adds further complications) and then attempt GetBindingExpression on each per element. Real ugly and real slow.
Time to design this requirement out.

Resources