RIA services/DataForm: How to use ReadOnly & Description attributes together - c#

I have several cases where I have a property that I want to declare readonly, but also give some explanation of how it is calculated/set using the [Display(Description="")] attribute. I would like to do this in the metadata, if possible, rather than override in the dataform itself.
Here's an example:
[Display(Description = "Total number of travel hours, calculated as total hrs worked - actual working hrs this month")]
public decimal TravelHours
{
get
{
return this.TotalHrsWorked - this.ActualWorkedHours;
}
}
This won't show the description as a DescriptionViewer when I bind to this property in a DataForm & DataField.
It seems like when I set the [ReadOnly] attribute it hides the DescriptionViewer, and even setting DescriptionViewerVisibility=Visible in the dataform xaml still doesn't change it. Also, any calculated properties (no setter) seem to have this attribute enforced by default. It's kind of annoying, because these are the ones I really want to show the descriptionviewer for.
The only way around it I have found so far is to make the property not readonly and add a dummy setter (for calculated properties). That seems like a kludge.
Is there any way to show the dataform/datafield descriptionviewer on readonly properties?

Yeah,
I encountered same problem before but didn't try to manage.
Display Attribute and , ReadOnly Attribute's are sealed you can't inherit from them. You may wrap them and create another attribute but your dataform doesn't now this attribute.So you can't...
Maybe you can do different things in ReadOnlyTemplate
<dataFormToolkit:DataForm.ReadOnlyTemplate>
<DataTemplate>
<Grid>
<dataFormToolkit:DataField Label="{Binding ReadOnlyLabel,
Converter=ReadOnlyOrNotConverter}" >
<TextBox Text="{Binding Path=ReadOnlyValueEtc, Mode=TwoWay}" />
</dataFormToolkit:DataField>
Hope helps,
Regards!

[Display(Order = 6, Name = "CountryLabel", Description = "CountryDescription",
ResourceType = typeof(EntityDataStrings))]
Where EntityDataStrings is a resource file containing values for "CountryLabel" and "CountryDescription".

Related

UWP Custom Control, Can't Use Binding, only x:Bind, How To Adapt?

I have created a custom control in UWP, but the issue I have exists on Microsoft provided custom controls as well, so I'll use the UWP Community Toolkit OrbitView as an example. The following 3 bindings work:
<Grid>
<TextBlock Text="{Binding MyProperty}"/>
<TextBlock Text="{x:Bind PageViewModel.MyProperty, Mode=OneWay}"/>
<Toolkit:OrbitView MinItemSize="{x:Bind PageViewModel.MyProperty, Mode=OneWay}" />
</Grid>
The standard control (TextBlock) works with either Binding or x:Bind. But if I want to use Binding on the custom control:
<Toolkit:OrbitView MinItemSize="{Binding MyProperty}" />
It does not. Searching here and the web I'm struggling to figure out what's going on and why. The general solution seems to be to just use x:Bind. However I want to put my custom control inside a UserControl because I want the option for it to be loaded from an external Xaml file at runtime using XamlReader. My understanding is you can't use x:Bind in this situation as that needs to be there at compile time. Is there any solution to accomplish what I'm after in UWP?
Ok, well here's why it wasn't working if you're running other code in the setter and how to get it to work.
Here's the proper way to implement a dependency property and have code execute on the setter. This was done in UWP project, since you're question is UWP, but has the exact same principles for all dependency properties of any project type.
public sealed partial class MainPage : Page
{
public MainPage() => InitializeComponent();
public int SomeValue
{
get => (int)GetValue(SomeValueProperty);
set => SetValue(SomeValueProperty, value);
}
public static readonly DependencyProperty SomeValueProperty = //Notice this is static. It's bound to an internal static hash table of some sort; I use to know exactly but forgot.
DependencyProperty.Register(
nameof(SomeValue), /*The name of the property to register against.
* The static version is always the name of the property ended with Property
* i.e. SomeValue property is SomeValueProperty dependency property */
typeof(int), //This is the type used to describe the property.
typeof(MainPage), //This is the type the dependency property relates to.
/* Below this is the magic. It's where we supply the property meta data and can be delivered different ways.
* For this example I will supply only the default value and the event we want to use when the value is changed.
* Note:
* The event we supply is fired ONLY if the value is changed. This event is what we need to use to handle changes in the setter to cover binding operations as well. */
new PropertyMetadata(default(int), /* This is the default value the dependency property will have.
* It can be whatever you decide but make sure it works with the same type or you'll most likely get an error. */
/* This is the event fired when the value changes.
* Note: Dependency properties binding and events always operate on the UI thread. Cross threading will throw exceptions. */
new PropertyChangedCallback((s, e) =>
{
var mainPage = s as MainPage; //The sender of the callback will always be of the type it's from.
/* The values given from the e argument for OldValue and NewValue should be of type int in this example...
* but since we can't gaurantee the property is setup properly before here I always add a check. */
if (e.OldValue is int oldValue) { }
if (e.NewValue is int newValue)
{
/* Now do what you want with the information. This is where you need to do custom work instead of using the setter.
* Note: If you need to work on something in the MainPage remember this is a static event and you'll need to refer to the sender or s value in this case.
* I've converted s to the variable mainPage for easy referencing here. */
mainPage.MyCustomControl.Value = newValue; //Note: The custom control should bind to this as well via XAML making this pointless. I set the value here just for educational purposes.
}
})));
}
A dependency property shouldn't look this scary, and really isn't, but I've added a lot of comments to help you navigate through it a little easier. hopefully this helps :)

Binding to a Binding: Data Binding indirection -or- Metabinding in WPF

No way to explain this issue except by example:
Say you have a custom UserControl with two DependencyPropertys, StatList Stats and string ImportantStat. The job of the user control is to display a table showing all of the values in Stats but with special visual treatment (like a pie chart) of the ImportantStat.
My instinct was to write a block of XAML that looked more or less like:
<PieChart Value="{Binding Path={Binding ImportantStat} }"/>
where the DataContext is prior set to Stats. So, the user passes in ImportantStat = "WinPercentage" and the pie chart binds to the WinPercentage Property of the stat line. But the user can just as easily pick some other Property to emphasize.
The problem (of course, you already know this, educated Stacker) is that you get an error message stating that you can't convert from Binding to string, which is what the outer Binding expects for Path. Though I haven't proven it to myself, I am guessing this is simply because Path is not a DependencyProperty.
So, is there any way to achieve my goal here? Feel free to break my assumptions in that first paragraph. Maybe, for example, ImportantStat can't be a string but must itself be a Binding.
Edit: Attempt #1 Failed
I was hoping that exposing from the code-behind a new DependencyProperty Binding ImportantStatBinding would allow me to rewrite the XAML as:
<PieChart Value="{Binding ImportantStatBinding, RelativeSource=... }"/>
...but to no avail. The indirect Binding is just stuck into Value itself with no attempts to resolve it.
My backup solution, which might be where this is headed, will be to just create the content inside the code-behind where I have access to ImportantStat directly and so can get away with a single Binding.
Far as I know, there is no way to concatenate data bindings in this way, without additional code. To put the problem more simply, we can have data binding (of course) of the form:
A --> B --> C
but you cannot have data binding of the form:
A --> B --> *A (*A indicates the target depends on the value of A)
because the relationships must be fixed.
It seems like it might be possible to create a Converter whose job is to convert a string into an arbitrary value by actually dereferencing a Binding using some additional context and that string as the property path. That sounds messy with type issues, so I chose the only other way I could think of:
I added a new DependencyProperty for the PieChart to the code behind and made sure that I constructed it at the appropriate times, so that the XAML could consume it. It's ugly, but it works. I just feel a little dead inside :) Hope someone finds this useful some day.

Databinding - Lozalized FallbackValue/TargetNullValue etc

In my Windows Phone 8 C#/XAML .NET 4.5 App I'm using databinding from ViewModel, which is working fine.
What I'd like is for a lozalized string from LocalizedResources to be displayed as a content of a button in the following cases:
The value returned by Binding is null
The binding could not be resolved
How could this be achieved?
What I've tried to do is:
(omitted TargetNullValue, since the way to do it is probably going to be the same)
(for presentation purposes, i set the resource to be Applicationtitle)
<Button ... Content="{Binding Something, FallbackValue={Binding Path=LocalizedResources.ApplicationTitle, Source={StaticResource LocalizedStrings}}}" ... />
But what I get is text like System.Windows.Text.Data.Binding...(can't read more since it's out of screen).
Did some googling/"stackoverflowing" and found something with valueconverters for WP7, that got me a bit puzzled.
(And added C# tag because I've got a feeling this is not going to be solved just by adding the right "property" to a tag/value to a "property", although I'd appreciate it to be)
I'm pretty sure you cannot apply binding to the FallbackValue. A very simple workaround is to check for null within your 'Something' property.
private string _something;
public string Something
{
get { return _something ?? AppResources.ApplicationTitle; }
set
{
_something = value;
OnPropertyChanged("Something");
}
}

WinForms DataGridView and PropertyGrid behavior [duplicate]

Let's say I have a property which I want shown in a DataGridView, but not when the same object is shown in a PropertyGrid. I know I can use [Browsable(false)], but that hides it in both views. I can also do a gridView.Columns["blah"].Visible = false;, but this is the opposite of what I want, as it hides in the DataGridView but not in PropertyGrid. Is there some way to do the reverse? (Short of creating a whole new DataTable just to hold the same data minus one field, and rebinding everything to that instead - that's really a kludge way to do things.) Alternatively, I could live with a solution which adds a column to the DataGridView that is not present on the actual class.
it is possible to solve this issue by using the BrowsableAttributes property of a PropertyGrid.
First, create a new attribute like this:
public class PropertyGridBrowsableAttribute : Attribute
{
private bool browsable;
public PropertyGridBrowsableAttribute(bool browsable){
this.browsable = browsable;
}
}
Then add this attribute to all those properties which you want to be shown in your PropertyGrid:
[DisplayName("First Name"), Category("Names"), PropertyGridBrowsable(true)]
public string FirstName {
get { return ... }
set { ... }
}
Then set the BrowsableAttributes property like this:
myPropertyGrid.BrowsableAttributes = new AttributeCollection(
new Attribute[] { new PropertyGridBrowsableAttribute(true) });
This will only show the attributed properties in your property grid and the DataGridView can still access all properties with only a little bit more coding effort.
I would still go with Tergiver and call this behaviour a bug, since the documentation of the Browsable attribute clearly states its use for property windows only.
(Credit goes to user "maro" at http://www.mycsharp.de/wbb2/thread.php?postid=234565)

Setting char properties in Xaml

Perhaps it is something trivial but I am out of ideas...
Originally I wanted to add some features to PasswordBox. Because it is a sealed class, original properties have to be replicated, among them PasswordChar. Looks trivial, but when I started to set PasswordChar in Xaml, I could not get rid of parser exception.
At the end I simply defined a new property
public char MyProperty {get; set; }
and tried to set it in Xaml as follows:
<MyPasswordBox MaxLength="3" Password="xxx" MyProperty="c" />
I am getting an exception with the call stack looking like
at MS.Internal.XcpImports.CheckHResult()
at MS.Internal.XcpImports.ConvertStringToTypedCValue()
at MS.Internal.SilverlightTypeConverter.ConvertFrom()
at MS.Internal.FrameworkCallbacks.ConvertValueToPropertyType()
....
at MS.Internal.FrameworkCallbacks.SetValueToProperty()
at MS.Internal.FrameworkCallbacks.SetPropertyAttribute()
....
at System.Windows.Application.LoadComponent()
....
As far I can read it, the type conversion string -> char fails.
Note that whenever I'll change the type of MyProperty to string (for example), everything works.
Does anybody know how to implement char properties so that they can be set from Xaml?
Working on Windows Phone 7, perhaps that's the problem. (Limited SVL 3)
I can't verify this will work, but you can give it a go. The long form xaml syntax should work ok.
Add the following to your namespace imports
xmlns:sys="clr-namespace:System;assembly=mscorlib"
Then the following should work
<MyPasswordBox MaxLength="3" Password="xxx">
<MyPasswordBox.MyProperty>
<sys:Char>c</sys:Char>
</MyPasswordBox.MyProperty>
</MyPasswordBox>
The other solution is to look into type converters to apply to your property so that it'll convert the string for you. Type Convereters and XAML.

Categories

Resources