Why does only one out of two multibindings work? - c#

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.

Related

Validation Error : value "" could not be Converted xml in WPF ComboBox when Selected Item

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...

Display multiline textbox bound to an array of strings with each element string on a separate line, allowing editing

I have an array of strings where StringArray[0] = "FOR DEPOSIT ONLY", StringArray[1] = "ANY BANK OF ANYTOWN", StringArray[2] = "ACCOUNT #123456789"; there are more array elements, but assume these are the only ones populated.
I need to display these strings in a multiline textbox like this:
FOR DEPOSIT ONLY
ANY BANK OF ANYTOWN
ACCOUNT #123456789
A user should be able to edit the textbox like this:
FOR DEPOSIT ONLY
MY BANK OF MY TOWN
ACCOUNT #987654321
and have the array be saved as follows: StringArray[0] = "FOR DEPOSIT ONLY", StringArray[1] = "My BANK OF MY TOWN", StringArray[2] = "ACCOUNT #987654321"
After looking at this site, I found something like this:
<TextBox TextWrapping="Wrap" AcceptsReturn="True">
<TextBox.Text>
<MultiBinding StringFormat="{}{0}{1}{2}">
<Binding Path="StringArray[0]"/>
<Binding Path="StringArray[1]"/>
<Binding Path="StringArray[2]"/>
<Binding Source="{x:Static System:Enviroment.NewLine}"/>
</MultiBinding>
</TextBox.Text>
</TextBox>
The "System" variable is properly defined at the top of my XAML file.
This code gave me the error "Two-way binding requires Path or XPath". The error appears to be on the "Binding Source" line. What do I need to add to this to make my textbox work;if a path is required on the "Binding Source" line, what would it be? Thanks.
Adding Mode=OneWay to the newline binding should get rid of your warning. That said, your bindings don't put each array element on its own line, but concatenates them. This approach displays what you want:
<TextBox
TextWrapping="Wrap"
AcceptsReturn="True">
<TextBox.Text>
<MultiBinding StringFormat="{}{0}{1}{2}{3}{4}">
<Binding Path="StringArray[0]" ElementName="self" />
<Binding Source="{x:Static system:Environment.NewLine}" Mode="OneWay" />
<Binding Path="StringArray[1]" ElementName="self" />
<Binding Source="{x:Static system:Environment.NewLine}" Mode="OneWay" />
<Binding Path="StringArray[2]" ElementName="self" />
</MultiBinding>
</TextBox.Text>
</TextBox>
As for getting the string array updated, I'm not sure you can do that without a converter. You can throw out the StringFormat and do the following instead:
<TextBox
TextWrapping="Wrap"
AcceptsReturn="True">
<TextBox.Text>
<MultiBinding Converter="{StaticResource MyConverter}">
<Binding Path="StringArray[0]" ElementName="self" />
<Binding Path="StringArray[1]" ElementName="self" />
<Binding Path="StringArray[2]" ElementName="self" />
</MultiBinding>
</TextBox.Text>
</TextBox>
Here I set x:Name="self" on my Window class, which declares the StringArray.
With the converter defined like this:
public sealed class MyConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
return string.Join(Environment.NewLine, values);
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
string stringValue = (string)value;
return stringValue.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
}
}
Reference the converter somewhere in your XAML, e.g.:
<Grid.Resources>
<multiLine:MyConverter x:Key="MyConverter" />
</Grid.Resources>
But: Since there's semantics associated with each line (account type, location, account #) I think you'd be better off using individual text boxes and straight data binding for each element of your data structure.

C# WPF, Datepicker validation

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

WPF ColumnDataPoint Annotation partial visible

I have chart with column series in my application. I'm using solution from this tutorial to add annotation on top of columns:
http://blogs.msdn.com/b/delay/archive/2009/07/27/simple-column-labels-you-can-create-at-home-re-templating-the-silverlight-wpf-data-visualization-columndatapoint-to-add-annotations.aspx
When the bar is really tall the top part of the annotation is only partial visible, or not visible.
I do not know range of my data, so I can not set Maximum value on the vertical Axis.
How to solve this problem?
Like Andre said, the problem is your Margin, so you could use Multibinding to calculate the Margin like so:
<ControlTemplate TargetType="charting:ColumnDataPoint">
<Grid>
<Rectangle Name="clmnRectangle"
Fill="{TemplateBinding Background}"
Stroke="Black"/>
<Grid Background="#aaffffff"
HorizontalAlignment="Center"
VerticalAlignment="Top">
<Grid.Margin>
<MultiBinding Converter="{StaticResource ResourceKey=HeightToMargin}">
<Binding Path="ActualHeight" RelativeSource="{RelativeSource AncestorType={x:Type charting:ColumnDataPoint}}"></Binding>
<Binding Path="ActualHeight" RelativeSource="{RelativeSource AncestorType={x:Type charting:ColumnSeries}}"></Binding>
</MultiBinding>
</Grid.Margin>
<TextBlock Name="tbValue"
Text="{TemplateBinding FormattedDependentValue}"
FontWeight="Bold"
Margin="2"/>
</Grid>
</Grid>
</ControlTemplate>
The Converter could look like:
public class HeightToMarginConverter:IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo ci)
{
double clmnHeight = System.Convert.ToDouble(values[0]);
double chrtHeight = System.Convert.ToDouble(values[1]);
if (chrtHeight - clmnHeight < 20)
{
return new Thickness(0, clmnHeight - chrtHeight + 5, 0, 0);
}
else
{
return new Thickness(0, -20, 0, 0);
}
}
public object[] ConvertBack(object value, Type[] targetType, object parameter, CultureInfo ci)
{
return null;
}
}

Two-way binding requires path or xpath

I want to increase Progress-bar value based on two textbox's Text. I wrote this XAML but there is an error "Two-way binding requires path or xpath" when I do MultiBinding in ProgressBar.Value
<Window.Resources>
<local:Class1 x:Key="ConverterM"/>
</Window.Resources>
<TextBox Height="23" HorizontalAlignment="Left" Margin="157,59,0,0"
Name="textBox1" VerticalAlignment="Top" Width="120" />
<TextBox Height="23" HorizontalAlignment="Left" Margin="157,108,0,0"
Name="textBox2" VerticalAlignment="Top" Width="120" />
<ProgressBar Height="24" HorizontalAlignment="Left" Margin="120,160,0,0"
Name="progressBar1" VerticalAlignment="Top" Width="243" >
<ProgressBar.Value>
<MultiBinding Converter="{StaticResource ConverterM}">
<Binding />
<Binding ElementName="textBox1" Path="Text" />
<Binding ElementName="textBox2" Path="Text" />
</MultiBinding>
</ProgressBar.Value>
</ProgressBar>
Value Converter:
public class Class1 : IMultiValueConverter
{
public object Convert(object[] values,
Type targetType,
object parameter,
System.Globalization.CultureInfo culture)
{
if (values[1] != null && values[2]!=null)
{
if (((string)values[1]).Length==((string)values[2]).Length)
{
return 5.0;
}
}
else
{
return 0.0;
}
}
public object[] ConvertBack(object value,
Type[] targetTypes,
object parameter,
System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
I think that <Binding /> is not necessary. try to delete it and change indexes in converter.
Two-way binding requires path or xpath
This happens when you haven’t set the Path= on binding. By default WPF binding will take the Path= part by default.
To avoid this you need to give Path for each Binding you specify in MultiBinding. here in your case there was an empty binding which has no Path defined thats why you have experience with the above error.
I have came across the same issue but the accepted answer does not say what the error is, So thought of sharing this.

Categories

Resources