I am using MaterialDesignThemes in my WPF project and I am able to see MaterialDesign styles being used by various WPF controls I am using. In one particular situation, however, I'm having a great bit of difficulty trying to get a DatePicker to use the MaterialDesign styling. When I render DatePickers in a XAML view, it works as expected. The difference is that in the case that it does not work, the date picker is rendered in code behind. Below is my code. Can anyone help?
var dp = new DateControl()
{
Margin = new Thickness(0, 0, _fontSize, 0),
HorizontalAlignment = HorizontalAlignment.Left,
Question = q,
IsReadOnly = IsReadOnly || q.IsReadOnly
};
if (dataValue != null)
{
DateTime dt = DateTime.MinValue;
if (DateTime.TryParse(dataValue, out dt) && dt > DateTime.MinValue)
{
dp.SetSelectedDate((DateTime?)dt);
}
else
{
dp.Text = dataValue;
}
}
if (!IsReadOnly)
dp.AddHandler(DateControl.LostFocusEvent, new RoutedEventHandler(HandleUserResponse));
MaterialDesignThemes.Wpf.ColorZoneAssist.SetMode(dp, ColorZoneMode.PrimaryDark);
return dp;
You should set the Style property of your custom control:
dp.Style = FindResource("MaterialDesignDatePicker") as Style;
MaterialDesignThemes doesn't know what a DateControl is and won't automatically apply any style to such a control. The implicit style that is applied to DatePicker controls is not inherited.
Related
I working on Xamarin project and made custom renderer for my custom control in UWP project. I found how to set the ControlTemplate by using xml code.
XML Way:
var tb = new TextBox(); // or what I do in Xamarin var tb = Control;
var ct = (Controls.ControlTemplate)XamlReader.Load(#"
<ControlTemplate TargetType=""TextBox"" xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation' xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
<Grid>
....
</Grid>
</ControlTemplate>");
tb.Template = ct;
But how I can do the same in code?
var tb = new TextBox(); // or what I do in Xamarin var tb = Control;
var ct = new ControlTemplate();
ct.TargetType = typeof(TextBox);
var grid = new Grid();
ct.VisualTree = grid // This is how it was done in wpf but there is no such option in UWP
tb.Template = ct;
It's not supported in UWP, and I previously found no way to directly set it. As per the MS docs.
ControlTemplate: this is used as the value of the Control.Template
property, which defines the visuals of a control by applying the
template. You almost always define a ControlTemplate as a XAML
resource, using an implicit key TargetType that is the same as a Style
that sets Control.Template with a Setter. You rarely if ever assign a
value for Control.Template directly on a control instance.
Besides possibly delving into reflection, or using the XAMLReader as per your first example, I have never found another way to do it, like you do in WPF.
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"
I have a ListBox and I want to change the appearance of each ListBoxItem based on the index of the previous ListBoxItem in the ListBox.
In order to do that I have created a CustomListBoxItem which inherits from ListBoxItem and have set a Style for it.
Setters.Add(new Setter(ListBoxItem.ContentTemplateProperty, new CustomListBoxItemContentTemplate());
In the constructor of CustomListBoxItemContentTemplate class which inherits from DataTemplate I have a DataTrigger as follows:
DataTrigger dt = new DataTrigger();
dt.Binding = new Binding()
{
RelativeSource = new RelativeSource(RelativeSourceMode.FindAncestor, typeof(CustomListBoxItem), 1),
Mode = BindingMode.OneWay,
UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged,
Converter = new CustomConverter()
};
dt.Value = true;
Triggers.Add(dt);
And finally in the Convert method of the CustomConverter class I have implemented the IValueConverter as follows:
var item = value as CustomBoxItem;
if (item == null)
return false;
/// I get the ItemsControl here
ItemsControl ic = ItemsControl.ItemsControlFromItemContainer(item);
/// and the index of the CustomListBoxItem
int index = ic.ItemContainerGenerator.IndexFromContainer(item);
if (index == 0)
return true;
var previousItem = ic.ItemContainerGenerator.ContainerFromIndex(index - 1) as CustomListBoxItem;
/// ....
I should say every thing works perfectly fine in the first place when the ItemsSource is bound to the source collection but when I add or remove items to the CustomListBox, the DataTrigger does not reevaluate the whole items. it does only for the added items.
I really don't know what the problem is, or maybe my approach is not very good to do the job.
Any help is appreciated. Thanks a lot.
I'm using a Dockpanel via C# & WPF to display 2 user controls
The Left UserControl is a Datagrid with Filters (Called Filter)
The Right UserControl is a Custom Form That will change depending on what type of Data the user is viewing.
I'm setting the Dockpanel via this code
private void SetMasterDock(UIElement MyFilter, UIElement NewViewer)
{
MasterDock.Children.Clear();
DockPanel.SetDock(MyFilter, Dock.Left);
DockPanel.SetDock(NewViewer, Dock.Right);
MasterDock.Children.Add(MyFilter);
MasterDock.Children.Add(NewViewer);
}
All the above works as coded.
Now the Change I'm looking for (If possible)
I'd like to know what / how to enable the User to be able to Adjust the Scaling of the two Usercontrols. so if they wish to see More or less of one side or the other, they can just Click & Slide a Divider bar so they can adjust their view to their personal preferences.
ETA: New Code
MasterDock.Children.Clear();
Grid SplittableGrid = new Grid();
GridSplitter MovableDevider = new GridSplitter(); MovableDevider.Background = Brushes.Blue; MovableDevider.HorizontalAlignment = HorizontalAlignment.Right; MovableDevider.VerticalAlignment = VerticalAlignment.Stretch; MovableDevider.Width = 5;
ColumnDefinition LeftDefinition = new ColumnDefinition(); LeftDefinition.Width = new GridLength(200);
ColumnDefinition RightDefinition = new ColumnDefinition(); RightDefinition.Width = new GridLength(1,GridUnitType.Star);
SplittableGrid.ColumnDefinitions.Add(LeftDefinition);
SplittableGrid.ColumnDefinitions.Add(RightDefinition);
Grid.SetColumn(MyFilter, 0);
Grid.SetColumn(MovableDevider, 0);
Grid.SetColumn(NewViewer, 1);
SplittableGrid.Children.Add(MyFilter);
SplittableGrid.Children.Add(MovableDevider);
SplittableGrid.Children.Add(NewViewer);
DockPanel.SetDock(SplittableGrid, Dock.Left);
MasterDock.Children.Add(SplittableGrid);
in winforms the control you are looking for is the splitcontainer. However in WPF this is done using grid + gridSplitter. both of those controls are in the default toolbox.
I am experimenting with the WPF RichTextBox and notice that I can itterate through the blocks that make up its document by looping through RichTextBox.Document.Blocks.
What is the best way to get the Block that surrounds the caret?
I can get the CaretPosition and the ElementStart and ElementEnd properties of each block but can't see how to compare them because the actual character offsets are not exposed unless I am missing something obvious.
var curCaret = richTextBox1.CaretPosition;
var curBlock = richTextBox1.Document.Blocks.Where(x => x.ContentStart.CompareTo(curCaret) == -1 && x.ContentEnd.CompareTo(curCaret) == 1).FirstOrDefault();
Answer above probably works in WPF RTB but not in Silverlight 4.0. Most likely SL doesn't allow access to the Document protion of the RTB. So you have to do it via Reflection....
Something like this:
Set up a TextSelectionChanged Event Handler
Grab the TextSelection Pointer and find the Start TextPointer
Grab the TextSelection.Start.Parent item
Find out if it is of type paragraph
Parse the Paragraph.Inlines
Look for type of InlineUIContainer you need a cast it accordingly.
In Silverlight5 get the properties to be used to update a toolbar:
private void rtb_SelectionChanged(object sender, RoutedEventArgs e)
{
TextSelection ts = rtb.Selection;
object property;
property = ts.GetPropertyValue(Run.FontWeightProperty);
System.Windows.FontWeight fontWeight = property is System.Windows.FontWeight ? (FontWeight)property : FontWeights.Normal;
property = ts.GetPropertyValue(Run.FontStyleProperty);
System.Windows.FontStyle fontStyle = property is System.Windows.FontStyle ? (FontStyle)property : FontStyles.Normal;
TextDecorationCollection textDecorations = ts.GetPropertyValue(Run.TextDecorationsProperty) as TextDecorationCollection;
bool isUnderlined = textDecorations != null;
double? fontSize = ts.GetPropertyValue(Run.FontSizeProperty) as double?;
SolidColorBrush foreground = ts.GetPropertyValue(Run.ForegroundProperty) as SolidColorBrush;
Color foregroundColor = foreground != null ? foreground.Color : Colors.Black;
System.Diagnostics.Debug.WriteLine("fontweight:{0}, fontStyle:{1}, Underline:{2}, size:{3}, color:{4}",
fontWeight,
fontStyle,
isUnderlined,
fontSize,
foregroundColor);
if (fontSize.HasValue)
SetToolbarFontSize(fontSize.Value);
SetToolbarFontColor(foregroundColor);
}
Paragraph currentParagraph = richTextBox1.CaretPosition.Paragraph;
This code will return a Paragaph object and instead of a Block object but because the blocks in a RichTextBox are typically paragraphs this will not pose any problem.
MS Docs:
The Blocks property is the content property of RichTextBox. It is a collection of Paragraph elements.