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}}" />
Related
I've reached my mental barier and not able to figure it out. I'm sure I'm missing something simple but I'm stuck. The code below is the minimal code required to see my problem but is far away from my production code.
Setting:
I have a WPF window with a DataGrid control that is bound to a business object that includes a collection of assets. For every asset I need to display a user control (SpecialButton) which visibility is determined based on multiple properties of an asset object. When I click on the button (in my example I have an extra button that changes the properties for simplicity) it changes a property of the underlying asset object which should make the control hidden.
Problem
I bind the user control attached property ControlVisibility to the whole asset object {Binding .}
<local:SpecialButton x:Name="buttonOnEachRow" ControlId="{Binding Id}"
ControlVisibility="{Binding ., Converter={StaticResource MyConverter}}"/>
When I change a property of the Asset object PropertyAI expect the MyConverter should run and change the visibility value but it never happen.
What I've tried
I've tried so many things that I even don't remember. The most promising seems to be MultipleBinding but I was not able to figure out how to write the syntax for the ControlVisibility property. I tried some settings on the DataGrid control, changing the way how the user control is updated but no vail.
As a workaround, in my production code, I created a fake property that performs the logic that is currently in the converter and bind the ControlVisibility to the fake property. That works but I have a completely unrelated property in my asset object that is there just because I can't figure out the binding.
The main WPF Window
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows;
namespace MultiBindingProblem
{
public partial class MainWindow : Window, INotifyPropertyChanged
{
public MainWindow()
{
InitializeComponent();
var sut = new BusinessObject() { Caption = "This is the parent object", Assets = new List<Asset>()};
sut.Assets.Add(new Asset() { Name = "Asset 1", Id = 1 });
sut.Assets.Add(new Asset() { Name = "Asset 2", Id = 2 });
sut.Assets.Add(new Asset() { Name = "Asset 3", Id = 3 });
this.DataContext = sut;
}
public event PropertyChangedEventHandler PropertyChanged;
private void BtnCancel_Click(object sender, RoutedEventArgs e)
{
Close();
}
private void BtnChange_Click(object sender, RoutedEventArgs e)
{
((BusinessObject)this.DataContext).Assets[0].PropertyA = true;
//PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Assets"));
}
}
}
XAML
The btnChange is here for simplicity. In my production code the SpecialButton will trigger the property update in my viewmodel
<Window x:Class="MultiBindingProblem.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:MultiBindingProblem"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800" WindowStartupLocation="CenterScreen">
<Window.Resources>
<local:TestConverter x:Key="MyConverter" />
</Window.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.5*" />
<ColumnDefinition Width="0.5*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="50" />
<RowDefinition Height="*" />
<RowDefinition Height="100" />
</Grid.RowDefinitions>
<TextBlock x:Name="lblMainObject" Grid.ColumnSpan="2" Grid.Row="0" FontSize="25"
Text="{Binding Caption}" />
<Button x:Name="btnCancel" Content="Cancel" IsCancel="True" IsDefault="True" Grid.Row="2" Grid.Column="1" Click="BtnCancel_Click" />
<DataGrid x:Name="dgrData" Grid.Row="1" Grid.ColumnSpan="2" AutoGenerateColumns="False" CanUserAddRows="False"
ItemsSource="{Binding Assets, NotifyOnSourceUpdated=True}" >
<DataGrid.Columns>
<DataGridTextColumn Header="Name" Binding="{Binding Name}"/>
<DataGridTemplateColumn Header="Action button" Width="100">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<!--
Here I bind to the whole 'Asset' object to be able to determine if the button should be
visible based on multiple properties. But changing a propety doesn't raise the converter.
I tried use multiple bindings but I was not able to figure out the syntax
-->
<local:SpecialButton x:Name="buttonOnEachRow"
ControlId="{Binding Id}"
ControlVisibility="{Binding ., Converter={StaticResource MyConverter}}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
<Button x:Name="btnChange" Grid.Row="2" Grid.Column="0" Content="Change visibility of the first button" Click="BtnChange_Click" />
</Grid>
</Window>
The user control (SpecialButton)
using System.Windows;
using System.Windows.Controls;
namespace MultiBindingProblem
{
public partial class SpecialButton : UserControl
{
public SpecialButton()
{
InitializeComponent();
}
public static readonly DependencyProperty ControlIdProperty =
DependencyProperty.Register("ControlId", typeof(int),
typeof(SpecialButton));
public int ControlId
{
get { return (int)GetValue(ControlIdProperty); }
set { SetValue(ControlIdProperty, value); }
}
public static readonly DependencyProperty ControlVisibilityProperty =
DependencyProperty.Register("ControlVisibility", typeof(Visibility),
typeof(SpecialButton), new FrameworkPropertyMetadata(Visibility.Visible));
public Visibility ControlVisibility
{
get { return (Visibility)GetValue(ControlVisibilityProperty); }
set { SetValue(ControlVisibilityProperty, value); }
}
private void btnSpecialButton_Click(object sender, RoutedEventArgs e)
{
System.Windows.MessageBox.Show($"The id of the button: {((Button)sender).Tag.ToString()}");
}
}
}
XAML
<UserControl x:Class="MultiBindingProblem.SpecialButton"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:MultiBindingProblem"
mc:Ignorable="d"
d:DesignHeight="45" d:DesignWidth="80"
x:Name="parent">
<Grid>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Stretch" DataContext="{Binding ElementName=parent}">
<Button x:Name="btnSpecialButton" Content="Click Me" Click="btnSpecialButton_Click"
Tag="{Binding ControlId}"
Visibility="{Binding ControlVisibility}" />
</StackPanel>
</Grid>
</UserControl>
TestConverter
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
namespace MultiBindingProblem
{
public class TestConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var asset = value as Asset;
if (asset == null) return Visibility.Hidden;
return !(asset.PropertyA || asset.PropertyB) ? Visibility.Visible : Visibility.Hidden;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
Question
Can I somehow use Multibinding?
Or
How to make the converter run when a single property has changed on the asset object?
You would use a MultiBinding with a multi-value converter like this
<Window.Resources>
<local:MultiBooleanToVisibilityConverter x:Key="MyConverter"/>
</Window.Resources>
<local:SpecialButton ...>
<local:SpecialButton.ControlVisibility>
<MultiBinding Converter="{StaticResource MyConverter}">
<Binding Path="PropertyA"/>
<Binding Path="PropertyB"/>
</MultiBinding>
</local:SpecialButton.ControlVisibility>
</local:SpecialButton>
Your current converter implementation looks like it should return Visible if none of the input properties is true. An equivalent multi-value converter could be this:
public class MultiBooleanToVisibilityConverter : IMultiValueConverter
{
public object Convert(
object[] values, Type targetType, object parameter, CultureInfo culture)
{
bool any = values.Any(v => v is bool && (bool)v);
return any ? Visibility.Hidden : Visibility.Visible;
}
public object[] ConvertBack(
object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}
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}}">
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.
i have five textbox controls in a user control, i want to add a dependency property in such a way
public string MyValue
{
get
{
return Textbox1.Text.Trim() + "." + Textbox2.Text.Trim() + "." + Textbox3.Text.Trim() + "." + Textbox4.Text.Trim() + "|" + Textbox5.Text.Trim();
}
set
{
Textbox1.Text = value.Split('|')[0];
Textbox2.Text = value.Split('|')[1];
Textbox3.Text = value.Split('|')[2];
Textbox4.Text = value.Split('|')[3];
Textbox5.Text = value.Split('|')[4];
}
}
But it is not working. how do i create a dependency property which can be binded directly to a single property. Any help would be grateful.
There is more than one solution:
expose the full value with the property and use an IValueConverter to extract the parts
create five properties, each exposing a part of the full value
Both are MVVM-compliant but the second one may be more transparent by avoiding too much plumbing but you may need more notification (INotifyPropertyChanged) calls.
EDIT: complete implementation
The UserControl:
XAML:
<UserControl x:Class="WpfApplication1.SplitterControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:WpfApplication1"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<UserControl.Resources>
<local:SplitConverter x:Key="splitConverter"></local:SplitConverter>
</UserControl.Resources>
<StackPanel x:Name="root" DataContext="{Binding RelativeSource={RelativeSource AncestorType=UserControl},Path=MyValue,Mode=TwoWay,Converter={StaticResource splitConverter}}">
<TextBox x:Name="Textbox1" Text="{Binding [0],NotifyOnSourceUpdated=True,UpdateSourceTrigger=PropertyChanged}" SourceUpdated="TextBox_SourceUpdated"></TextBox>
<TextBox x:Name="Textbox2" Text="{Binding [1],NotifyOnSourceUpdated=True,UpdateSourceTrigger=PropertyChanged}" SourceUpdated="TextBox_SourceUpdated"></TextBox>
<TextBox x:Name="Textbox3" Text="{Binding [2],NotifyOnSourceUpdated=True,UpdateSourceTrigger=PropertyChanged}" SourceUpdated="TextBox_SourceUpdated"></TextBox>
<TextBox x:Name="Textbox4" Text="{Binding [3],NotifyOnSourceUpdated=True,UpdateSourceTrigger=PropertyChanged}" SourceUpdated="TextBox_SourceUpdated"></TextBox>
<TextBox x:Name="Textbox5" Text="{Binding [4],NotifyOnSourceUpdated=True,UpdateSourceTrigger=PropertyChanged}" SourceUpdated="TextBox_SourceUpdated"></TextBox>
</StackPanel>
</UserControl>
Code behind:
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
namespace WpfApplication1
{
public partial class SplitterControl : UserControl
{
public string MyValue
{
get { return (string)GetValue(MyValueProperty); }
set { SetValue(MyValueProperty, value); }
}
public static readonly DependencyProperty MyValueProperty = DependencyProperty.Register("MyValue", typeof(string), typeof(SplitterControl));
public SplitterControl()
{
InitializeComponent();
}
private void TextBox_SourceUpdated(object sender, DataTransferEventArgs e)
{
root.GetBindingExpression(DataContextProperty).UpdateSource();
}
}
}
The IValueConverter:
using System;
using System.Globalization;
using System.Windows.Data;
namespace WpfApplication1
{
public class SplitConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return (value as string).Split('|');
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return string.Join("|", value as string[]);
}
}
}
And in the parent control, e.g. the MainWindow:
<TextBox x:Name="input" Text="First|Second|Third|Fourth|Fifth"></TextBox>
<local:SplitterControl MyValue="{Binding ElementName=input,Path=Text,Mode=TwoWay}"></local:SplitterControl>
Edit the "input" TextBox to change the full string value and edit each TextBox in the UserControl to change each part.
Very tricky but should do what you want.
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}}