We are using Extended WPF Toolkit in order to implement PropertyGrid.
The default date picking control does not seem to be the WPF DatePicker, but instead a custom control, if I'm not mistaken.
Usually, we are using DatePicker controls in order to select dates. Is it possible to use them, too, for the PropertyGrid control? We need this in order to provide a consistent date format of dd.MM.yyyy and since this property is a date, time should also not be displayed.
Can this be done using Xceed Property Grid?
[Category("General")]
[DisplayName("Date")]
[PropertyOrder(2)]
public DateTime? Date { get; set; }
What you ask for is not so difficult to achive: Xceed PropertyGrid is high customizable and a property editor can be customized by using the ITypeEditor interface and the Editor attribute.
First of all we need to define a custom editor control:
public class DateTimePickerEditor : DateTimePicker, ITypeEditor
{
public DateTimePickerEditor()
{
Format = DateTimeFormat.Custom;
FormatString = "dd.MM.yyyy";
TimePickerVisibility = System.Windows.Visibility.Collapsed;
ShowButtonSpinner = false;
AutoCloseCalendar = true;
}
public FrameworkElement ResolveEditor(PropertyItem propertyItem)
{
Binding binding = new Binding("Value");
binding.Source = propertyItem;
binding.Mode = propertyItem.IsReadOnly ? BindingMode.OneWay : BindingMode.TwoWay;
BindingOperations.SetBinding(this, ValueProperty, binding);
return this;
}
}
All the stuff in the constructor are made for obtaining a specific behavior (i.e. no time controls, a specific date format and so on).
Now we need to set the DateTimePickerEditor as the default editor for the object property (that in our sample is called "Date"):
[Category("General")]
[DisplayName("Date")]
[PropertyOrder(2)]
[Editor(typeof(DateTimePickerEditor), typeof(DateTimePicker))]
public Nullable<DateTime> Date
I hope it helps.
You could also use an XAML only solution using editor templates shown at "Custom Editors with DataTemplates":
https://wpftoolkit.codeplex.com/wikipage?title=PropertyGrid&referringTitle=Home
Using this approach you aren't cluttering your model-classes with attributes of external libraries.
Your formatted input of DateTime-types can be achieved via:
<xctk:PropertyGrid>
<xctk:PropertyGrid.EditorDefinitions>
<xctk:EditorTemplateDefinition>
<xctk:EditorTemplateDefinition.TargetProperties>
<xctk:TargetPropertyType Type="{x:Type sys:DateTime}" />
</xctk:EditorTemplateDefinition.TargetProperties>
<xctk:EditorTemplateDefinition.EditingTemplate>
<DataTemplate>
<xctk:DateTimePicker Value="{Binding Value}" Format="ShortDate" />
</DataTemplate>
</xctk:EditorTemplateDefinition.EditingTemplate>
</xctk:EditorTemplateDefinition>
</xctk:PropertyGrid.EditorDefitions>
</xctk:PropertyGrid>
With namespace sys defined xmlns:sys="clr-namespace:System;assembly=mscorlib"
Related
Hi I want to set the Text property of a Textbox by code behind. At the moment I do using XAML:
<TextBox x:Name="txtFilter" Text="{Binding FiltroFunzioni, Mode=OneWayToSource}" Grid.Row="0" />
As test I did this:
Binding b = new Binding();
b.Mode = BindingMode.OneWayToSource;
b.Path = new PropertyPath("Text"); //??
b.Source = PageViewModel.FiltroFunzioni;
BindingOperations.SetBinding(txtFilter, TextBlock.TextProperty, b);
The variable "FiltroFunzioni" is a string defined as property:
private string _filtroFunzioni = "";
public string FiltroFunzioni
{
get { return _filtroFunzioni; }
set
{
_filtroFunzioni = value;
RaisePropertyChanged("FiltroFunzioni");
_functionsView.Refresh();
}
}
Basically I dunno what kind of value should I set as PropertyPath. Any ideas?
You don't need the PropertyPath here. If you just remove it, your binding should work.
That being said, you should bind in XAML wherever possible.
If your issue is that changes to FiltroFunzioni don't update your textbox, that's because your binding is specifically declared as OneWayToSource: that means that changing the UI changes the source, but changing the source doesn't change the UI. If that isn't what you want, set the Mode to something else, like "TwoWay" - then changes to the source change the UI, AND changes to the UI change the source.
EDIT:
If you really want to bind from your ViewModel instead of just using XAML, TwoWay binding requires utilizing the Path for some reason, when binding through C#. Either of the following solutions work:
b.Source = FiltroFunzioni;
b.Path = new PropertyPath(".");
b.Source = this;
b.Path = new PropertyPath("FiltroFunzioni");
Note that with TwoWay binding you have to either initialize your FiltroFunzioni by setting the TextBox.Text property in your XAML, or setting FiltroFunzioni after the binding was initialized. Otherwise, WPF will immediately override it from the (by default empty) Text in your TextBox.
I try to understand data bindings in WPF and I could already bring some tests to work. But I'm stuck tight now. :(
For better organization I want to split my code into more classes and bind elements of the same Window to different classes (actually to properties of different classes).
I think I have to set the DataContext of my Window to "this" (The window itself) and use the Binding Path to specify the property to use.
DataContext = this;
-
<Label Content="{Binding Path=_printSettings.CopyCount}"/>
So f.e. I want to bind to CopyCount wich is a property returning a string. That property belongs to the instance in the private field _printSettings of the current window. And _printSetting implements the INotifyPropertyChanged and notifies in a twoway principle.
But the label is empty during design and runtime...
I also noticed that no default values are set in the designer in my previous tests. Does anyone know an implementation? If possible without the use of a fallback value.
-MainWindow.xaml.cs
<Label Content="{Binding ElementName=MainWindow,Path=PrintSettings.CopyCount, FallbackValue=[0]}">
-MainWindow.cs
private PrintSettings _printSettings = new PrintSettings();
public PrintSettings PrintSettings {
get {
return _printSettings;
}
}
public MainWindow()
{
DataContext = this;
}
PrintSettings.cs
private int _copyCount = 1;
//Copy count
public string CopyCount
{
get {
return "" + _copyCount;
}
}
-
EDIT:
added more code again
Binding works against/through public properties. _printSettings is not a property. The Visual Studio "Output" window can show any binding errors you have.
_printSettings and CopyCount should be public.
If it doesnt help, then in xaml Set window Name and binding will look like this
<Label Content="{Binding ElementName=YourWindowName,Path=_printSettings.CopyCount}"/>
or
<Label Content="{Binding ElementName=YourWindowName,Path=DataContext._printSettings.CopyCount}"/>
I have a DateTimePicker as follows:
<UserControl
...
xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
...
>
<xctk:DateTimePicker Name="MyDatePicker"
Value="{Binding MyDate, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}"
Format="Custom" FormatString="dd/MM/yyyy HH:mm:ss"
AutoCloseCalendar="True"/>
I'm using IDateErrorInfo on my data model to handle business logic errors; for example:
public class MyViewModel : IDataErrorInfo
{
public string Error
{
get { return null; }
}
public string this[string columnName]
{
get
{
string error = DataValid();
CanExecute = (error == string.Empty);
return error;
}
}
CanExecute is a property which manages whether the user can select to submit the data. This all works well, however, if I simply select the date and mash the keyboard (type random letters), the date is reset to 01/01/01. What I would like to happen is for the date to effectively remain unchanged (that is, as it was before I mashed the keyboard). However, I can't seem to find a place to handle the casting error which obviously is occurring when this happens.
How can I trap this?
(The DateTimePicker control is part of the WPF Extension Kit)
If you don't like the way the control handles errors you can handle errors yourself in a subclass, an example of this in my old question Wpf Datepicker Input modification
I have a WPF expander with a databound item. Im trying to set a bool flag in the databound item in code behind to have teh expander collapse when the bool is set. I set the bool in the databound object but the expander is not reflecting the change and collapsing. Please let me know if you need anymore information.
Had a closer look and it appears im not implementing InotifyPropertyChanged. Reading up on it now but answers specific to my problem would be appreciated.
Here is my XAML:
<Expander Header="{Binding SubSection.SubSectionName}" Expanded="Expander_Expanded" Collapsed="Expander_Collapsed" IsExpanded="{Binding SubSection.Expanded}">
Here is my code behind:
loopSubVM.SubSection.Expanded = false;
Expanded definition:
public class SubSectionViewModel
{
ObservableCollection<MaterialViewModel> _materials = new ObservableCollection<MaterialViewModel>();
ObservableCollection<SubSectionViewModel> _subSections = new ObservableCollection<SubSectionViewModel>();
SubSection _subSection;
SectionViewModel _sectionVM;
public class SubSection
{
string _subSectionName;
object _subSectionValue;
List<GX3MaterialInterface.GX3MaterialInterface.MATERIAL_TYPE> _sectionTypes;
int _currentTypePosition;
List<List<object>> _paramterList;
bool _expanded = false;
Make sure that setting Expanded raises the PropertyChanged event.
Is it possible to attach datatriggers to a style at runtime? I've been through my (non-working) code a few times now and can't seem to find where I've gone wrong.
Here's the method I use to attach the style and trigger:
private void AttachVisibilityTrigger(Control ctrl)
{
Style stl = new System.Windows.Style();
DataTrigger dt = new DataTrigger();
PropertyInfo pi = _entity.GetType().GetProperty(this.SecondaryOptions[ctrl.Name]);
Type controlType = this.GetControlTypeForProperty(ref dt, pi); //gets the control type based on the property name and then sets the value for the DataTrigger for which I want the visibility to be hidden
Binding b = this.GetVisibilityBindingByControlType(controlType); //returns a new Binding with the appropriate Path set that corresponds to the bound property value (e.g IsChecked for CheckBoxes, Text for TextBoxes, SelectedValue for Comboboxes, etc)
b.ElementName = this.SecondaryOptions[ctrl.Name];
dt.Binding = b;
dt.Setters.Add(new Setter(Control.VisibilityProperty, System.Windows.Visibility.Hidden));
stl.Triggers.Add(dt);
ctrl.Style = stl;
}
I'm pretty sure the binding is just broken, i created similar styles in code and they work.
Especially this line looks quite suspicious:
b.ElementName = this.SecondaryOptions[ctrl.Name];
(If you want to bind to the control itself use RelativeSource instead.)
Have you checked the Output window of VisualStudio for binding errors?