I have a slider with maximum value of video's time in seconds (1 minute = 60 seconds, so if the video is 60 seconds length, the maximum value of the slider will be 60).
When I drag the Thumb, there's ThumbTooltip that shows the current value I am hovering.
I want to change that text so instead of displaying int, it will display time 1 will be 00:01 and so on...
I tried to play with the style of the Slider with no luck.
Will appreciate your help.
Slider has ThumbToolTipValueConverter property. You need to create class which implements IValueConverter interface. In that the Convert method will help you to convert the default slider value to your customized value. See the below code.
XAML
<Page.Resources>
<local:SliderValueConverter x:Key="SliderValueConverter"/>
</Page.Resources>
<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
<Slider Maximum="60" Value="40" Height="100" Width="300" ThumbToolTipValueConverter="{StaticResource SliderValueConverter}" />
</Grid>
SliderValueConverter.cs
public class SliderValueConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
var seconds = System.Convert.ToInt32(value);
return string.Format("{0:00}:{1:00}", (seconds / 60) % 60, seconds % 60);
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
throw new NotImplementedException();
}
}
Related
I have ran into a issue with the converters... They are not triggering once the bound collection is updated although they trigger when the collection is first populated. I would like to have them fire whenever there is a change in the collection.
So far I have built a simple converter:
public class TableConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
VM.Measurement t = ((VM.Measurement)((TextBlock)value).DataContext);
if (t.Delta != null)
{
if (Math.Abs((double)t.Delta) < t.Tol)
return "Green";
else
return "Red";
}
else
return "Red";
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
which is linked to a style
<conv:TableConverter x:Key="styleConvStr"/>
<Style x:Key="CellStyleSelectorTol" TargetType="syncfusion:GridCell">
<Setter Property="Background" Value="{Binding RelativeSource={RelativeSource Self}, Path=Content, Converter={StaticResource styleConvStr}}" />
</Style>
Which is used in this DataGrid
<syncfusion:SfDataGrid x:Name="CheckGrid" BorderBrush="White" Grid.Row="1" Grid.Column="1" AllowEditing="True" ItemsSource="{Binding ChecksList, Mode=TwoWay}" Background="White" SnapsToDevicePixels="False"
ColumnSizer="None" AllowResizingColumns="False" AllowTriStateSorting="True" AllowDraggingColumns="False" CurrentCellEndEdit="CheckGrid_CurrentCellEndEdit" AutoGenerateColumns="False"
NavigationMode="Cell" HeaderRowHeight="30" RowHeight="21" GridPasteOption="None" Margin="20 10 10 10" AllowGrouping="True" SelectedItem="{Binding SelectedLine, Mode=TwoWay}"
SelectionUnit="Row" SelectionMode="Single" RowSelectionBrush="#CBACCB" VirtualizingPanel.IsVirtualizing="True" Visibility="Visible">
<syncfusion:GridTextColumn Width="100" ColumnSizer="SizeToCells" AllowEditing="True" MappingName="Measured" CellStyle="{StaticResource CellStyleSelectorTol}" HeaderText="Measured" TextAlignment="Center" AllowFiltering="False" FilterBehavior="StringTyped"/>
The VM contains an Observable Collection which implements NotifyPropertyChanged all the way down to the Measurement Class. The properties fire up nicely so it is not a binding issue.
private ObservableCollection<Measurement> _checkList = new ObservableCollection<Measurement>();
public ObservableCollection<Measurement> ChecksList
{
get
{
return _checkList;
}
set
{
_checkList = value;
NotifyPropertyChanged();
}
}
Any help with this would be greatly appreciated.
Thanks
EDIT:
Here is the code that updates the collection. Apologies for it being quite messy. Lineitem is the selected line for which Measured and Delta are updated. These are properly displayed in the grid once modified.
public void NewMeasurement(VM.Measurement measurementShell)
{
using (VMEntity DB = new VMEntity())
{
var Check = CheckSets.Where(x => x.ID == SelectedLine.ID).First();
if (Check.Measurement == null)
{
Check.Measurement = measurementShell.Index;
var Lineitem = ChecksList.Where(x => x.ID == SelectedLine.ID).First();
var measurement = DB.Measurements.Where(x => x.Index == Check.Measurement).First();
Lineitem.Measured = (double)measurement.measurement1;
Lineitem.Delta = Lineitem.Measured - Lineitem.Target;
OK, it looks like the problem is that you are changing properties of the cell content item (LineItem, in the NewMeasurement() method), but it's still the same object, so the cell's content doesn't change. The cell's Content is the source for the binding. If that doesn't change, the binding won't wake up and update the target. You're raising PropertyChanged, but this particular binding has no way of knowing you want it to listen to this object for those property changes. Easy enough fix: We'll start telling it exactly what to listen for.
Fortunately the solution means simplifying some of your code. Passing a UI control into a value converter is exotic and not necessary.
What you care about in the converter is Measurement.Delta and Measurement.Tol. When either one changes, the Binding should update its target. You don't want to do that in a clever way. You just want a Binding for each one. That's a Binding's job.
So tell the Binding that you care about those properties, and rewrite the converter to accept both of them as parameters.
<Style x:Key="CellStyleSelectorTol" TargetType="syncfusion:GridCell">
<Setter
Property="Background"
>
<Setter.Value>
<MultiBinding Converter="{StaticResource styleConvStr}">
<Binding Path="Delta" />
<Binding Path="Tol" />
</MultiBinding>
</Setter.Value>
</Setter>
</Style>
Converter:
public class TableConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
// I'm inferring that Measurement.Delta is Nullable<double>; if that's
// not the case, change accordingly. Is it Object instead?
double? delta = (double?)values[0];
double tol = (double)values[1];
if (delta.HasValue && Math.Abs(delta.Value) < tol)
{
return "Green";
}
return "Red";
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
I want to bind Value of a Slider to a Content of a Label. The value of the slider sets a timespan. The value of the slider is a timespan in minutes (value 5 = 5 minutes).
This is my XAML for the Label:
<Label
Content="{Binding Value, ElementName=sld_Timespan}"
ContentStringFormat="{}{0:HH:mm}"
/>
I can bind them. The values are correct. But the format is wrong.
For ContentStringFormat i tried different settings, like on this (TextBlock in Silverlight) or this (TextBlock Multibinding) site. I also took the data binding dialog and set the StringFormat to {0:G} (you can choose this from a ComboBox) or other settings.
I only get a value "formatted" as double, like "1" or "13.423523423".
I also tried TextBlock. The same problem.
What is wrong with my XAML code?
After the comment of Clemens i understood what was wrong. I wrote a simple Converter:
public class DoubleToTimespanConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return TimeSpan.FromMinutes((double)value).ToString(#"hh\:mm\:ss");
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
And added to my XAML:
<UserControl.Resources>
<!--local is my local namespace-->
<local:DoubleToTimespanConverter x:Key="converter"/>
</UserControl.Resources>
And i could easily set "converter" as my converter.
I am developing an Windows Store app using C# and XAML and am working on a user input page. I use an IValueConverter that converts my bound data into currency formatted string instead of just showing a decimal.
When the user navigates to the page, the converter works fine and the TextBox text shows up with a currency format. However, when the user changes the TextBox.Text value and then the TextBox loses focus, the converter does not change it into a nice currency format again, it just stays formatted as it was entered by the user.
As far as I can tell, there is no StringFormat to use like in WPF, so how do I get the TextBox to display the currency format again after the user edits the value?
My converter:
public object Convert(object value, Type targetType, object parameter, string language)
{
if (parameter == null)
return ((decimal)value).ToString();
return String.Format((string)parameter, (decimal)value);
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
decimal decVal = 0M;
decimal.TryParse((string)value, out decVal);
return decVal;
}
My XAML:
<Grid x:Name="InputGrid">
...
<Border>
<TextBox Text="{Binding MyValue, ConverterParameter='{}{0:c}', Converter={StaticResource DecimalValueConverter}, Mode=TwoWay}"
</Border>
....
</Grid>
InputGrid.DataContext = MyValueClassInstance set in the code-behind
Does your converter work both ways? I suspect that if it doesn't - the TwoWay binding gets broken.
What if you do this:
<TextBox Text="{Binding MyValue, UpdateSourceTrigger=PropertyChanged, ConverterParameter='{}{0:c}', Converter={StaticResource DecimalValueConverter}, Mode=TwoWay}"
I have objects stored in a database that I am displaying in a GridView. I am binding each of their properties from the database. The color property is stored as a Hex value.
I am trying to bind this hex value using a converter function as shown below and just returning Red every time for now.
It seems to be working but it eventually returns the following error:
The program '[5548] TranslatorService.Example.exe: Managed (v4.0.30319)' has exited with code -1073741189 (0xc000027b).
Can anyone tell me what I am doing wrong?
The code-behind:
public class StringToColorConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, String language)
{
return Colors.Red;
}
public object ConvertBack(object value, Type targetType, object parameter, String language)
{
throw new NotImplementedException();
}
}
The XAML:
<Grid.Background>
<SolidColorBrush Color="{Binding Path=ColorHex, Converter={StaticResource ColorConverter}}" />
</Grid.Background>
Thank you
In my experience you need to assing a Brush, not a Color:
SolidColorBrush mySolidColorBrush = new SolidColorBrush();
mySolidColorBrush.Color = Color.FromArgb(255, 255, 0, 0);
or
mySolidColorBrush.Color = Color.Red;
The problem seems to be resolved after recompiling.
In your posted converter code, you are returning Color.Red, so no matter what value is, you'll get Red every time.
I currently use the following method to set the colour of my Row Background.
XAML
<Style TargetType="{x:Type xcdg:DataRow}">
<Setter Property="Background">
<Setter.Value>
<MultiBinding Converter="{StaticResource colorConverter}">
<Binding RelativeSource="{RelativeSource Self}" Path="IsSelected"/>
<Binding BindsDirectlyToSource="True" />
</MultiBinding>
</Setter.Value>
</Setter>
</Style>
C#
public class ColourConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
var isRowSelected = (bool)values[0];
var myInstance = (MyClass) values[1];
// Return default
if (isRowSelected || myInstance == null)
return DependencyProperty.UnsetValue;
// Get the check for the current field
return GetColour(myInstance) ?? DependencyProperty.UnsetValue;
}
private static SolidColorBrush GetColour(MyClass myInstance)
{
if (heartbeat == null)
{
return null;
}
// Is it more two minutes old?
return (myInstance.CreatedDateTime + TimeSpan.FromMinutes(2) < Clock.UtcNow())
? Brushes.LightPink
: Brushes.LightGreen;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException(this.GetType().Name + " cannot convert back");
}
}
The problem is that this Converter is only called on population of the DataRow with new values. What I really need is some sort of callback to change the colour after a certain time or to have the Converter reevaluated periodically.
The colour update doesn't have to be instant, just within a few seconds. If I have a callback for each row then I'd need as many threads to match (They are created and hence expire (which changes their colour) at different times), with ~1000 rows this doesn't seem like an efficient option.
The other option is to poll the rows on one thread periodically and reevaluate the converter on each iteration (Every 5 seconds?). I think this is likely the way to go but I don't know how to go about it in WPF.
Perhaps there's another approach or built in support for such a task?
Thanks in advance!
Should be possible to get the BindingExpression from the DataRow and simply call UpdateSource/UpdateTarget manually as many times as you need...
BindingExpression binding = Control.GetBindingExpression(DataRow.BackgroundProperty)
binding.UpdateSource;
Don't forget to also change the UpdateSourceTrigger property on the binding.