BoolToVisibilityConverter inside window.resources - c#

I have a list box that contains a label and a text box that the user can alter. The list box contents are defined in a data template (inside window.resources). I would like to add a border to each item in the list that has been changed using a booltovisibility converter.
I think I'm having trouble because I'm trying to set the converter inside window.resources.
Can somebody please point me in the right direction?
View Model:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.SqlClient;
using System.ComponentModel;
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Controls;
namespace MaintainPersonData
{
public class MaintainPersonViewModel
{
public MaintainPersonViewModel(ObservableCollection<PersonViewModel> personList)
{
}
public INotifyUser Notifier;
private ObservableCollection<PersonViewModel> _personList;
public ObservableCollection<PersonViewModel> PersonList
{
get
{
return _personList;
}
set
{
_personList = value;
OnPropertyChanged("PersonList");
}
}
private bool _changesMade;
public bool ChangesMade
{
get
{
return _changesMade;
}
set
{
_changesMade = value;
OnPropertyChanged("ChangesMade");
}
}
private bool _hasErrors;
public bool HasErrors
{
get { return _hasErrors; }
set
{
_hasErrors = value;
if (!_hasErrors)
{
ErrorMessage = "";
}
OnPropertyChanged("HasErrors");
}
}
Xaml:
<Window.Resources>
<conv:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter"/>
<DataTemplate x:Key="ListBoxItemTemplate">
<Border BorderBrush="LightGreen" BorderThickness="2" Visibility="{Binding ChangesMade, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource BoolToVisibilityConverter}}">
<Grid>
<TextBox x:Name="PersonTextBox" Text="{Binding PersonName, UpdateSourceTrigger=PropertyChanged}"/>
</Grid>
</Border>
</DataTemplate>
</Window.Resources>
<Grid>
<ListBox x:Name="PersonListBox" SelectionMode="Single" KeyboardNavigation.TabNavigation="Continue" ItemTemplate="{StaticResource ListBoxItemTemplate}" ItemsSource="{Binding PersonList}">
<!-- Code to highlight selected item (http://stackoverflow.com/questions/15366806/wpf-setting-isselected-for-listbox-when-textbox-has-focus-without-losing-selec) -->
</ListBox>
<!-- BoolToVisibilityConverter works perfectly here -->
<Label Name="ErrorLabel" Grid.Column="0" Foreground="Red" HorizontalAlignment="Center" VerticalAlignment="Center" Visibility="{Binding HasErrors, Converter={StaticResource BoolToVisibilityConverter}}" >
<TextBlock Text="{Binding ErrorMessage, UpdateSourceTrigger=PropertyChanged}" />
</Label>
</Grid>
</Window>
And Finally, the converter:
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Data;
namespace MaintainRegexData
{
class BoolToVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return (bool)value ? Visibility.Visible : Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}

ChangesMade should be defined per each PersonViewMode It's because right now you will (or will not) add border to all items. Have you checked that Convert method from BoolToVisibilityConverter is invoked? And last thing - there is nothing wrong with setting converter in window resources.

first of all you Bind your ItemsSource to PersonList which it's Type is ObservableCollection<PersonViewModel> where ChangesMade include in MaintainPersonViewModel so you need to place your ChangesMade inside PersonViewModel class and make changes while personName Property changed.
and don't forget what #Frank said about Border.

Related

ComboBox object doesn't display initial value

A ComboBox object with a data binding, when I propram like below, the content doesn't display until a selection operation made.
XAML:
<Window x:Class="Recipe_GUI.ComboboxTest"
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:Recipe_GUI"
xmlns:src="clr-namespace:RecipeLib;assembly=RecipeLib"
mc:Ignorable="d"
Title="ComboboxTest" Height="450" Width="800">
<Window.Resources>
<src:DataType x:Key="DataType"/>
</Window.Resources>
<Grid>
<ComboBox HorizontalAlignment="Left" Margin="125,82,0,0" VerticalAlignment="Top" Width="120"
x:Name="C01"
ItemsSource="{StaticResource ResourceKey=DataType}"
SelectedValue="{Binding Path=DataType}"/>
<!--SelectedValue="{Binding Path=Text, ElementName=T01}"/>-->
<TextBox Text="{Binding ElementName=C01, Path=SelectedIndex}" Margin="125,141,309,249"/>
<TextBox Text="{Binding Path=DataType}" Margin="125,202,309,188" x:Name="T01"/>
</Grid>
</Window>
When I change the code to binding the ComboBox to TextBox "T01"("T01" binding to the same object), the ComboBox initial value displayed as expected. The code and presentation like below.
<ComboBox HorizontalAlignment="Left" Margin="125,82,0,0" VerticalAlignment="Top" Width="120"
x:Name="C01"
ItemsSource="{StaticResource ResourceKey=DataType}"
SelectedValue="{Binding Path=Text, ElementName=T01}"/>
<!--SelectedValue="{Binding Path=DataType}"/>-->
The other related code are like below.
XAML.CS:
using RecipeLib;
using System.Windows;
namespace Recipe_GUI
{
/// <summary>
/// Interaction logic for ComboboxTest.xaml
/// </summary>
public partial class ComboboxTest : Window
{
Param param = new Param();
public ComboboxTest()
{
InitializeComponent();
DataContext = param;
}
}
}
Class Param:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
namespace RecipeLib
{
public class Param : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
private Enum_DataType dataType;
public Enum_DataType DataType
{
get { return dataType; }
set
{
dataType = value;
OnPropertyChanged("DataType");
}
}
public Param()
{
DataType = Enum_DataType.Float;
}
}
}
Enum_DataType and DataType:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.ObjectModel;
namespace RecipeLib
{
public enum Enum_DataType : int
{
Float = 0,
Integer = 1,
Enumeration = 2,
Bitmask = 3,
Time = 4
}
public class DataType : ObservableCollection<string>
{
public DataType() : base()
{
foreach (var item in Enum.GetNames(typeof(Enum_DataType)))
{
Add(item);
}
}
}
}
Please help answer why the first method doesn't work for the initial value, and how to fix? Thank you in advance!
Old Code
<ComboBox HorizontalAlignment="Left" Margin="125,82,0,0"
VerticalAlignment="Top" Width="120"
x:Name="C01"
ItemsSource="{StaticResource ResourceKey=DataType}"
SelectedValue="{Binding Path=DataType}"/>
it's an assumption so if anyone can correct me then please do it.
I believe the ComboBox has a "Text" property and in this case, you are binding an enum so you need a converter to convert the value from enum to string. so I added a converter and it worked.
Additional: each ComboBoxItem has a "Content" property which is a string type so when you choose any of the items the ComboBox "Text" property is set automatically. that's why it works when you select any of the items.
the same logic applies to your code where you bound the text property of Textblock to ComboBox property "SelectedValue"
Updated Code
Here are some modifications I did to your existing code
Converter class
Option: I named it "EnumToStringConverter" but you can name this class whatever you want
public class EnumToStringConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return Enum.GetNames(value.GetType()).ElementAt((int)value);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return Enum.Parse(targetType, value.ToString());
}
}
XAML
<Window.Resources>
<local:DataType x:Key="DataType"/>
<local:EnumToStringConverter x:Key="EnumConverter" />
</Window.Resources>
<ComboBox HorizontalAlignment="Left" Margin="125,82,0,0" VerticalAlignment="Top" Width="120"
x:Name="C01"
ItemsSource="{StaticResource DataType}"
SelectedValue="{Binding DataType, Converter={StaticResource EnumConverter}}" />

How to bind data from One control and Bind to source into a variable WPF, C#

I try to bind a selected value from DataGrid and show into the user on TextBlock.
Then bind it to a variable on the model in the source code
It is a little example code to make it more easy to show the problem here.
my xaml file:
<Window x:Class="WpfAppTest.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:WpfAppTest"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<StackPanel>
<DataGrid x:Name="DGExample" MinWidth="50" SelectionMode="Single" FontSize="30"
ItemsSource="{Binding ExampleList, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}">
</DataGrid>
<TextBlock Name="TBDescription" MinWidth="100" FontSize="30">
<TextBlock.Text>
<MultiBinding StringFormat="{}{0} - {1}">
<Binding Path="Example" Mode="OneWayToSource" UpdateSourceTrigger="PropertyChanged" />
<Binding Path="SelectedItem.X" ElementName="DGExample" Mode="OneWay" UpdateSourceTrigger="PropertyChanged" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
<TextBlock Name="ShowExample" FontSize="30" Text="{Binding Path=Example, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}">
</TextBlock>
</StackPanel>
</Grid>
</Window>
My model example :
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WpfAppTest
{
public class ModelExample : INotifyPropertyChanged
{
public int Example
{
get;
set;
}
public ObservableCollection<ClassExample> ExampleList { get; set; }
public ModelExample()
{
ExampleList = new ObservableCollection<ClassExample>() {
new ClassExample(1,2), new ClassExample(3,4), new ClassExample(5,6)};
}
public event PropertyChangedEventHandler PropertyChanged;
}
}
My Example class :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WpfAppTest
{
public class ClassExample
{
public ClassExample(int x, int y)
{
X = x;
Y = y;
}
public int X{get;set;}
public int Y{ get; set; }
}
}
My fody file :
<?xml version="1.0" encoding="utf-8"?>
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<PropertyChanged />
</Weavers>
I expect to see the value in TBDescription Control to the Example Variable
But the only value stored in Example is 0 only...
The problem with your code is that it never binds value to Example property from TextBlock because its content isn't ever changed. So if you just want to bind selected value of DataGrid to Example do the following. Create converter which converts ClassExample instance to int
public class TestConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
ClassExample obj = value as ClassExample;
if (obj != null)
{
return obj.X;
}
return 0;
}
}
Add converter to Window
<Window.Resources>
<your-namespace:TestConverter x:Key="TestConverter" />
</Window.Resources>
Add binding to SelectedItem in DataGrid
<DataGrid
x:Name="DGExample"
MinWidth="50"
SelectionMode="Single"
FontSize="30"
ItemsSource="{Binding ExampleList, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
SelectedItem="{Binding Example, Mode=OneWayToSource, Converter={StaticResource TestConverter}}">

MultiBinding not working in DataGridTextColumn

I am trying to use a MultiBinding to update a DataGridTextColumn.
<Window x:Class="WPFBench.MultiBindingProblem"
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:WPFBench"
mc:Ignorable="d"
Title="MultiBindingProblem" Height="300" Width="300">
<Window.Resources>
<local:MultiValueConverter x:Key="MultiValueConverter"/>
</Window.Resources>
<Grid>
<DataGrid x:Name="dataGrid" AutoGenerateColumns="False"
ItemsSource="{Binding TableA}" ColumnWidth="100*">
<DataGrid.Columns>
<DataGridTextColumn Header="Value" Binding="{Binding Value}"/>
<DataGridTextColumn Header="MultiValue">
<DataGridTextColumn.Binding>
<MultiBinding Converter="{StaticResource MultiValueConverter}">
<Binding Path="Value"/>
<Binding Path="Value"/>
</MultiBinding>
</DataGridTextColumn.Binding>
</DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>
Here is the converter...
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Data;
namespace WPFBench
{
public class MultiValueConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
return values[0];
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
The code behind...
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
namespace WPFBench
{
/// <summary>
/// Interaction logic for MultiBindingProblem.xaml
/// </summary>
public partial class MultiBindingProblem : Window
{
DataTable _tableA = new DataTable();
public MultiBindingProblem()
{
InitializeComponent();
_tableA.Columns.Add(new DataColumn("Value", typeof(double)));
_tableA.Rows.Add(0.0);
_tableA.Rows.Add(1.0);
_tableA.Rows.Add(2.0);
_tableA.Rows.Add(3.0);
_tableA.Rows.Add(4.0);
DataContext = this;
}
public DataTable TableA
{
get { return _tableA; }
}
}
}
The single binding column is updated. The multivalue converter is called. The multivalue column remains blank. What am I doing wrong?
Assuming that your Value is a value type like an int and not a string, this issue happens because there is no implicit conversion from object to string.
Try returning a
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
return String.Format("{0}", values[0]); // don't return an object values[0];
}
from the Convert method.
Also put a breakpoint and check if values is correctly filled as expected.
Simple demo to prove that this is the correct answer.
Start you window in the question from a button of the main window
private void button_Click(object sender, RoutedEventArgs e)
{
MultiBindingProblem probl = new MultiBindingProblem();
probl.DataContext = new DemoRoughViewModel();
probl.Show();
}
using a simple, rough view model
public class DemoRoughTable
{
public int Value { get; set; } // Notice that it's not a string
}
public class DemoRoughViewModel
{
public List<DemoRoughTable> TableA { get; set; } = new List<DemoRoughTable>()
{
new DemoRoughTable() { Value = 1 }, new DemoRoughTable() { Value = 2 }
};
}
HTH
Your example should work, as long as you convert values[0] to its string representation in the Convert method of IMultiValueConverter (As explained by other answers here). However, your example here is a little strange, because there is no need for a MultiBinding. (I know you are aware of them, since the first column demonstrates a more proper approach).
Anyway, I think you need a MultiBinding for the Binding property of a DataGridTextColumn, when you want to set the Binding dynamically. In this case, you should send the DataContext and the path string, and retrieve its value in a IMultiValueConverter. There is an example here, similar to this situation, in which the Binding changes based on the value in the header of the DataGridTextColumn.
Hope it helps.
What am I doing wrong?
The Binding property of a DataGridTextColumn is supposed to be set to a BindingBase object and not to a data bound value.
If you intend to show a value returned by the converter in the column you should use a DataGridTemplateColumn:
<DataGridTemplateColumn Header="MultiValue">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock>
<TextBlock.Text>
<MultiBinding Converter="{StaticResource MultiValueConverter}">
<Binding Path="Value"/>
<Binding Path="Value"/>
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
Also make sure that you are returning a string from the converter:
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
return values[0].ToString();
}

WPF: ValueConverter (IValueConverter) does not work

I have a Window class, where I have several TextBlock elements which should receive a Background color by a value of a Binding property. The first "Converter binding" works fine and does everything expected. Today I tried to implement another "Converter binding" with another Converter used for it, but it does not work:
(I left out the ConvertBack methods because they are not necessary here):
namespace InsightTool.Gui.Helper {
[ValueConversion(typeof(double), typeof(Brush))]
public class AverageExecutionTimeToColorConverter : IValueConverter {
public object Convert (object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
double val;
double.TryParse(value.ToString(), out val);
if (val >= 10000) {
return Brushes.Red;
} else if (val >= 5000) {
return Brushes.Orange;
} else {
return Brushes.Green;
}
}
}
[ValueConversion(typeof(int), typeof(Brush))]
public class ThreadsAvailableCountToColorConverter : IValueConverter {
public object Convert (object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
int val;
int.TryParse(value.ToString(), out val);
if (val < 100) {
return Brushes.Red;
} else if (val < 200) {
return Brushes.Orange;
} else if (val < 500) {
return Brushes.Yellow;
} else {
return Brushes.Green;
}
}
}
}
In the Window class I used both converts as following:
<Window ...
x:Name="Main"
xmlns:Base="clr-namespace:InsightTool.Gui.Helper">
<Window.Resources>
<Base:ThreadsAvailableCountToColorConverter x:Key="ThreadsAvailableCntConverter"/>
<Base:AverageExecutionTimeToColorConverter x:Key="AvgExecutionTimeConverter"/>
</Window.Resources>
<!-- This one works fine-->
<TextBlock Width="10" Height="10" VerticalAlignment="Center" Background="{Binding ExecutionTimeAverage, Converter={StaticResource AvgExecutionTimeConverter}, ElementName=UCExecutionTimes}"/>
<!-- This one does not work-->
<TextBlock Width="10" Height="10" VerticalAlignment="Center" Background="{Binding ThreadsAvailableCount, Converter={StaticResource ThreadsAvailableCntConverter}, ElementName=Main}"/>
</Window>
Declaration of DependencyProperties:
public partial class UserControlExecutionTimes : UserControl {
public static readonly DependencyProperty ExecutionTimeAverageProperty =
DependencyProperty.Register("ExecutionTimeAverage", typeof(double), typeof(MainWindow), new FrameworkPropertyMetadata(double));
public double ExecutionTimeAverage {
get { return (double)GetValue(ExecutionTimeAverageProperty); }
set { SetValue(ExecutionTimeAverageProperty, value); }
}
}
public partial class MainWindow : Window {
public static readonly DependencyProperty ThreadsAvailableCountProperty = DependencyProperty.Register("ThreadsAvailableCount", typeof(int),
typeof(MainWindow), new FrameworkPropertyMetadata(int));
public int ThreadsAvailableCount {
get { return (int)GetValue(ThreadsAvailableCountProperty); }
set { SetValue(ThreadsAvailableCountProperty, value); }
}
}
Both DependencyProperties are set correctly and their values are displayed in the GUI. What do I miss here?
EDIT:
I also tested the following:
<Window>
<!-- This one works fine-->
<TextBlock Width="10" Height="10" VerticalAlignment="Center" Background="{Binding ThreadsAvailableCount, Converter={StaticResource AvgExecutionTimeConverter}, ElementName=Main}"/>
<!-- This one does not work-->
<TextBlock Width="10" Height="10" VerticalAlignment="Center" Background="{Binding ThreadsAvailableCount, Converter={StaticResource ThreadsAvailableCntConverter}, ElementName=Main}"/>
</Window>
It seems that there is a problem for the Binding to consume the return value of the "new" converter, but I have no clue why.
EDIT2
I check the bindings with Snoop and the result was the following:
The background property of the working converter binding looks like this:
But the background property of the not working converter binding looks this:
Another proof that ThreadsAvailableCount is set correctly (Binding to a Textblock):
It more and more seems to be a mistake in displaying the return value of the ThreadsAvailableCountToColorConverter. That is because in Debug mode, it stops at a breakpoint in the Convert method of the ThreadsAvailableCountToColorConverter. It even reachesreturn in the Convert method successfully.
Ah! Finally solved this. I had the exact same problem. With a TextBlock, with an IValueConverter converting to a Brush.
The binding was working, no errors or output. The value was getting into the IValueConverter code, I could debug right through to the return statement then... nothing!
You've done everything right, but you've automatically imported the wrong Brushes. I do it all the time with WPF.
replace the using statement:
using System.Drawing
with:
using System.Windows.Media
WPF uses System.Windows.Media.Brushes, but it's very easy to import the almost identical System.Drawing.Brushes and not notice. It all looks fine, until WPF gets hold of it and can't actually use it. But it fails 'gracefully' by falling back on the default colour.
I think could be multiple issues look at the 'output window' for binding expression errors.
1) Ensure that the textbox are rendered in separate areas and are not
overlapping.
2) Use relative path to get to the control and use it property in the binding expression
Your convertor looks fine.
Following is my xaml
<Window x:Class="StackOverflowBinding.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:stackOverflowBinding="clr-namespace:StackOverflowBinding"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<stackOverflowBinding:ThreadsAvailableCountToColorConverter x:Key="ThreadsAvailableCntConverter"/>
<stackOverflowBinding:AverageExecutionTimeToColorConverter x:Key="AvgExecutionTimeConverter"/>
</Window.Resources>
<Grid>
<!--<DatePicker
x:Name="newtally"
Text="{Binding CustomerLastTally,Mode=TwoWay}"
Margin="0 0 0 0"
/>-->
<!-- This one works fine-->
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Width="30" Height="30" Text="Break"/>
<TextBlock Grid.Row="1" Grid.Column="0" Width="30" Height="30" VerticalAlignment="Center" Text="Break" Background="{Binding ExecutionTimeAverage, Converter={StaticResource AvgExecutionTimeConverter}, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"/>
<!-- This one does not work-->
<TextBlock Grid.Row="2" Grid.Column="0" Width="30" Height="30" VerticalAlignment="Center" Text="Break" Background ="{Binding ThreadsAvailableCount, Converter={StaticResource ThreadsAvailableCntConverter}, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"/>
</Grid>
</Window>
Following is my code behind
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace StackOverflowBinding
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
// Dependency Property
public static readonly DependencyProperty ExecutionTimeAverageProperty =
DependencyProperty.Register("ExecutionTimeAverage", typeof(DateTime),
typeof(MainWindow), new FrameworkPropertyMetadata(DateTime.Now));
// .NET Property wrapper
public DateTime ExecutionTimeAverage
{
get { return (DateTime)GetValue(ExecutionTimeAverageProperty); }
set { SetValue(ExecutionTimeAverageProperty, value); }
}
// Dependency Property
public static readonly DependencyProperty ThreadsAvailableCountProperty =
DependencyProperty.Register("ThreadsAvailableCount", typeof(int),
typeof(MainWindow), new FrameworkPropertyMetadata(40));
// .NET Property wrapper
public int ThreadsAvailableCount
{
get { return (int)GetValue(ThreadsAvailableCountProperty); }
set { SetValue(ThreadsAvailableCountProperty, value); }
}
}
}
Following is my convertor
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Data;
using System.Windows.Media;
namespace StackOverflowBinding
{
[ValueConversion(typeof(double), typeof(Brush))]
public class AverageExecutionTimeToColorConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
double val;
double.TryParse(value.ToString(), out val);
if (val >= 10000)
{
return Brushes.Red;
}
else if (val >= 5000)
{
return Brushes.Orange;
}
else
{
return Brushes.Green;
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
[ValueConversion(typeof(int), typeof(Brush))]
public class ThreadsAvailableCountToColorConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
int val;
int.TryParse(value.ToString(), out val);
if (val < 100)
{
return Brushes.Red;
}
else if (val < 200)
{
return Brushes.Orange;
}
else if (val < 500)
{
return Brushes.Yellow;
}
else
{
return Brushes.Green;
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}

Unknown property 'Converter' for type 'MS.Internal.Markup.MarkupExtensionParser+UnknownMarkupExtension' encountered while parsing a Markup Extension

I am binding to an ObservableCollection called ScaleFactor to a ComboBox. The value of the ObservableCollection are simply 1, 2, 4 and 8. I want to use an IValueConverter to change these values to x1, x2, x4 and x8.
My MainWindow.xaml
<Window x:Class="TimeLineCanvas.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:timeline="clr-namespace:TimeLineCanvas.UserControls"
xmlns:helper="clr-namespace:TimeLineCanvas.Helpers"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.Resources>
<helper:ZoomConverter x:Key="ZoomConverter" />
</Grid.Resources>
<StackPanel>
<ComboBox ItemsSource="{Binding SSS}" HorizontalAlignment="Left" >
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding, Converter={StaticResource ZoomConverter}}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</StackPanel>
</Grid>
</Window>
And the code behind
using System;
using System.Windows;
using System.ComponentModel;
using System.Collections.ObjectModel;
namespace TimeLineCanvas
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
#region Constructors
public MainWindow()
{
InitializeComponent();
SSS = new ObservableCollection<int>();
SSS.Add(1);
SSS.Add(2);
this.DataContext = this;
}
#endregion
public ObservableCollection<int> SSS { get; set; }
}
}
And the converter
using System;
using System.Windows.Data;
namespace TimeLineCanvas.Helpers
{
public class ZoomConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return "x" + value.ToString();
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
I don't know why this is, I'm not using MarkupExtensions so I don't think this link helps. Can any one shed any light?
Do not use a comma after Binding. This way you call the empty constructor on the Binding object.
{Binding, Converter={StaticResource ZoomConverter}}
should be
{Binding Converter={StaticResource ZoomConverter}}

Categories