The SelectedDateStart needs to be bound to a date value set by another DatePicker. Can I get an example of binding the date in a string in C# to the xaml datePicker SelectedDateStart Property? This is what i have so far for the xaml
<telerik:RadDatePicker IsInputRestrictedToSelectableDates="True"
SelectableDateStart="{Binding Path=SetDepartureStartDate,Mode=TwoWay}"
SelectedDate="{Binding Path=ActualDepartureDateLocal, Mode=TwoWay}"
IsEnabled="{Binding Path=IsActualDepartureDateTimeEditable}"
TabIndex="7" >
</telerik:RadDatePicker>
Figured it out!
SelectableDateStart="{Binding Path=SelectableDate}"
Used a bind and path that is on the date picker below.
<telerik:RadDatePicker
SelectedDate="{Binding Path=ActualDepartureDateLocal, Mode=TwoWay}" IsEnabled="{Binding Path=IsActualDepartureDateTimeEditable}" TabIndex="7" SelectableDateStart="{Binding Path=SelectableDate}" >
<i:Interaction.Behaviors>
<commanding:UpdateBindingSourceWhenRadDateTimeControlTextChanged/>
</i:Interaction.Behaviors>
</telerik:RadDatePicker>
The bind path was then connnected to a DateTime in my cs file. The issue I was having is that the binding wasn't connected to my DataContext for teh cs file and wasn't returning a DateTime but a string. Switched these and it worked!
public DateTime SelectableDate
{
get
{
if (_loadStopToComplete.Actual_Arrival_Local != null)
{
_selectedDate = _loadStopToComplete.Actual_Arrival_Local.Value.Date;
DepartureDate = Convert.ToString(_loadStopToComplete.Actual_Arrival_Local.Value.Date);
}
return _selectedDate;
}
}
I have tried to code this validation,
<ComboBox Name="CmbPlace" DisplayMemberPath="Name"
SelectedValuePath="PlaceId"
materialDesign:ComboBoxAssist.ShowSelectedItem="true"
Width="130" HorizontalContentAlignment="Right" Margin="5"
DropDownOpened="CmbPlace_OnDropDownOpened">
<ComboBox.Text>
<Binding Path="PlaceId">
<Binding.ValidationRules>
<validation:RequireCmbValidation ValidatesOnTargetUpdated="True"/>
</Binding.ValidationRules>
</Binding>
</ComboBox.Text>
for TextBox and another component like this Validation Working as well only for ComboBox I got this Problem
this is my Validation and I know this will be Return ValidationResult.ValidResult successfully
public class RequireCmbValidation: ValidationRule
{
public override ValidationResult Validate(object value, CultureInfo cultureInfo)
{
if (!string.IsNullOrWhiteSpace(value?.ToString()))
if (value.ToString() != "0")
return ValidationResult.ValidResult;
else
return new ValidationResult(false, "Please Select one Item");
return new ValidationResult(false, "Required!");
}
}
I solved my problem
Replace <ComboBox.Text> to <ComboBox.SelectedValue>
after 5 hours... but I hope this will help others...
The context of this example is there are four text boxes that hold a total amount of time. 1 for hours, 1 for minutes, 1 for seconds, and 1 for milliseconds.
There is a fifth text box that holds the total time in just milliseconds. This can be seen in the image below.
I have made an implementation of IMultiValueConverter that should convert 4 TextBox components and the converted value in a property. It should also be able to update the 4 boxes when the property's value changes.
When the user types in the text box that holds the converted output and then that box loses focus, the other 4 text boxes are updated. However, when the property's value is programmatically changed, in this case by a button click, the values in the 4 text boxes are not updated.
How can I make these 4 text boxes update through the converter?
The ultimate goal, in this example, is to store the total time (in milliseconds) in a property and have 5 text boxes updating through bindings when that property is updated.
This is the code for the converter.
using System;
using System.Globalization;
using System.Windows.Data;
namespace MultiBinding_Example
{
public class MultiDoubleToStringConverter : IMultiValueConverter
{
private const double HOURS_TO_MILLISECONDS = 3600000;
private const double MINUTES_TO_MILLISECONDS = 60000;
private const double SECONDS_TO_MILLISECONDS = 1000;
private const string ZERO_STRING = "0";
private object valBuffer = null;
/*
* values[0] is the variable from the view model
* values[1] is hours
* values[2] is the remaining whole minutes
* values[3] is the remaining whole seconds
* values[4] is the remaining whole milliseconds rounded to the nearest millisecond
*/
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
object returnVal = ZERO_STRING;
try
{
if (values != null)
{
double hoursToMilliseconds = (values[1] == null || values[1].ToString() == string.Empty) ? 0 : System.Convert.ToDouble(values[1]) * HOURS_TO_MILLISECONDS;
double minutesToMilliseconds = (values[2] == null || values[2].ToString() == string.Empty) ? 0 : System.Convert.ToDouble(values[2]) * MINUTES_TO_MILLISECONDS;
double secondsToMilliseconds = (values[3] == null || values[3].ToString() == string.Empty) ? 0 : System.Convert.ToDouble(values[3]) * SECONDS_TO_MILLISECONDS;
double totalTime = ((values[4] == null || values[4].ToString() == string.Empty) ? 0 : System.Convert.ToDouble(values[4])) + secondsToMilliseconds + minutesToMilliseconds + hoursToMilliseconds;
returnVal = totalTime.ToString();
if (values[0] == valBuffer)
{
values[0] = returnVal;
}
else
{
valBuffer = returnVal = values[0];
ConvertBack(returnVal, new Type[] { typeof(string), typeof(string), typeof(string), typeof(string), typeof(string) }, parameter, culture);
}
}
}
catch (FormatException) { }
return returnVal;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
try
{
if (value != null && value.ToString() != string.Empty)
{
double timeInMilliseconds = System.Convert.ToDouble(value);
object[] timeValues = new object[5];
timeValues[0] = value;
timeValues[1] = Math.Floor(timeInMilliseconds / HOURS_TO_MILLISECONDS).ToString();
timeValues[2] = Math.Floor((timeInMilliseconds % HOURS_TO_MILLISECONDS) / MINUTES_TO_MILLISECONDS).ToString();
timeValues[3] = Math.Floor((timeInMilliseconds % MINUTES_TO_MILLISECONDS) / SECONDS_TO_MILLISECONDS).ToString();
timeValues[4] = Math.Round(timeInMilliseconds % SECONDS_TO_MILLISECONDS, MidpointRounding.AwayFromZero).ToString();
return timeValues;
}
}
catch (FormatException) { }
return new object[] { ZERO_STRING, ZERO_STRING, ZERO_STRING, ZERO_STRING, ZERO_STRING };
}
}
}
To test this, I have a quite a simple layout that consists of a few Label components, a few TextBox components and a Button.
It looks like this.
The XAML for it is the following.
<Window x:Class="MultiBinding_Example.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:MultiBinding_Example"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.Resources>
<local:MultiDoubleToStringConverter x:Key="multiDoubleToStringConverter"/>
</Window.Resources>
<StackPanel>
<Label Content="Multi Value Converter" HorizontalAlignment="Center" FontSize="35" FontWeight="Bold" Margin="0, 25, 0, 0"/>
<Label Content="Formatted Total Time" FontWeight="Bold" FontSize="24" Margin="20, 10"/>
<Grid Margin="80, 10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="auto"/>
</Grid.ColumnDefinitions>
<TextBox Name="Hours" HorizontalContentAlignment="Right" VerticalContentAlignment="Center" Text="0" Grid.Column="0"/>
<Label Content="Hours" Grid.Column="1" Margin="0, 0, 15, 0"/>
<TextBox Name="Minutes" HorizontalContentAlignment="Right" VerticalContentAlignment="Center" Text="0" Grid.Column="2"/>
<Label Content="Minutes" Grid.Column="3" Margin="0, 0, 15, 0"/>
<TextBox Name="Seconds" HorizontalContentAlignment="Right" VerticalContentAlignment="Center" Text="0" Grid.Column="4"/>
<Label Content="Seconds" Grid.Column="5" Margin="0, 0, 15, 0"/>
<TextBox Name="Milliseconds" HorizontalContentAlignment="Right" VerticalContentAlignment="Center" Text="0" Grid.Column="6"/>
<Label Content="Milliseconds" Grid.Column="7"/>
</Grid>
<Label Content="Unformatted Total Time" FontWeight="Bold" FontSize="24" Margin="20, 10"/>
<Grid Margin="80, 10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="auto"/>
</Grid.ColumnDefinitions>
<TextBox HorizontalContentAlignment="Right" VerticalContentAlignment="Center" Grid.Column="0">
<TextBox.Text>
<MultiBinding Converter="{StaticResource multiDoubleToStringConverter}" Mode="TwoWay">
<Binding Path="TotalTime"/>
<Binding ElementName="Hours" Path="Text"/>
<Binding ElementName="Minutes" Path="Text"/>
<Binding ElementName="Seconds" Path="Text"/>
<Binding ElementName="Milliseconds" Path="Text"/>
</MultiBinding>
</TextBox.Text>
</TextBox>
<Label Content="Milliseconds" Grid.Column="1"/>
</Grid>
<Button Grid.Column="1" Margin="250, 20" Height="50" Content="Random Total Milliseconds" Click="RandomTime_Click"/>
</StackPanel>
</Window>
The code behind is the following.
using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows;
namespace MultiBinding_Example
{
public partial class MainWindow : Window, INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private Random random = new Random();
private string totalTime;
public string TotalTime {
get => totalTime;
set {
totalTime = value;
RaisePropertyChanged();
}
}
public MainWindow()
{
InitializeComponent();
DataContext = this;
UpdateTotalTime();
}
private void RaisePropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
private void RandomTime_Click(object sender, RoutedEventArgs e)
{
UpdateTotalTime();
}
private void UpdateTotalTime()
{
double percent = random.NextDouble();
double time = Math.Floor(percent * random.Next(1000, 100000000));
TotalTime = time.ToString();
}
}
}
This isn't really what a converter is for.
Converters take a set of view model values and convert them to view values for display. Then if the view values change it can convert them back to view model values.
In your case, the view model value is updated through code (not through a change to the view) and so the converter has no reason to run the ConvertBack method (the value is already a view model value!). This is one of several reasons why converters should not have side-effects.
The correct way to do this would be to have TotalTime as a property on the VM (probably as a number or TimeSpan and not a string as you have it) and then do individual converters for each of the pieces. For example:
<TextBox Text="{Binding TotalTime, Converter={StaticResource TimeSecondsConverter}"/>
The main text box would then just be bound to TotalTime. TimeSecondsConverter would probably need to be a multi-value converter in order for ConvertBack to work.
I'm trying to validate date in XAML using validation rules.
<StackPanel Grid.Column="0" Grid.Row="1" Orientation="Horizontal">
<DatePicker Height="25" x:Name="DatePickerDate">
<DatePicker.SelectedDate>
<Binding Path="ViewModel.Date" NotifyOnValidationError="True">
<Binding.ValidationRules>
<validationRules:DatePickerValidationRule/>
</Binding.ValidationRules>
</Binding>
</DatePicker.SelectedDate>
</DatePicker>
</StackPanel>
And Validation rule
public class DatePickerValidationRule : ValidationRule
{
public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo)
{
var date = (DateTime) value;
return date.Date.CompareTo(DateTime.Now) < 0
? new ValidationResult(false, "the date can not be before today")
: new ValidationResult(true, null);
}
}
But when I put breakpoint into validation rule, it never goes there even if I change the Date.
Since I am new to WPF, it would be appreciable if any suggestions or guidance are available here.
Thanks.
Had the same problem and thought I should share my solution:
I had a static minimum date constraint so just specified BlackoutDates
<DatePicker SelectedDate="{Binding StartDate}" Name="DepartureDate">
<DatePicker.BlackoutDates>
<CalendarDateRange Start="1/1/0001" End="12/31/1969"/>
</DatePicker.BlackoutDates>
</DatePicker>
But if you need a more dynamic solution you could consider this solution.
Inside your Save() function
this.DatePickerDate.SelectedDate = this.DatePickerDate.SelectedDate;
This should force the validation rule to validate
I am using a MultiBinding in two different points in my XAML. Here is the code:
<StatusBarItem>
<StackPanel Orientation="Horizontal">
<TextBlock Text="X " />
<TextBlock>
<TextBlock.Text>
<MultiBinding Converter="{StaticResource CoordinateToStringConverter}" TargetNullValue="-">
<Binding Path="ChartMouseX" />
<Binding Path="AxisSettingsViewModel.XAxisSettings.LabelFormat" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
<TextBlock Text=" Y " />
<TextBlock>
<TextBlock.Text>
<MultiBinding Converter="{StaticResource CoordinateToStringConverter}" TargetNullValue="-">
<Binding Path="ChartMouseY" />
<Binding Path="AxisSettingsViewModel.YAxisSettings.LabelFormat" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</StackPanel>
</StatusBarItem>
I am facing a weird issue. The first MultiBinding works perfectly, but the second one is never called. If I comment out the first MultiBinding, the second one starts to work as expected.
Is this some kind of limitation in WPF? Or am I missing something about multibindings?
P.S: The RaisePropertyChanged is correctly invoked. However, in the second binding the converter does not get called at all.
EDIT
Here is the code of the Converter:
using System;
using System.Globalization;
using System.Windows.Data;
namespace LogViewer.Converters
{
public class CoordinateToStringConverter : IMultiValueConverter
{
#region IMultiValueConverter members
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (values != null && values.Length == 2)
{
object value = values[0];
string format = values[1].ToString();
if (value is DateTime)
return ((DateTime)value).ToString(format);
if (value is TimeSpan)
return ((TimeSpan)value).ToString();
if (value is double)
return ((double)value).ToString(format);
}
return null;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
#endregion
}
}
I have analyzed your issue. Which is working fine for me. Nothing wrong with the multibinding.
Have you checked the converter with breakpoint was it called two times. Otherwise your problem is in ChartMouseY and ChartMouseX.