How to get datacontext from stackpanel - c#

I have:
<StackPanel DataContext="{Binding Path =MyContext}">
<TextBox Text="{Binding Path =Content}" x:Name="tbName" IsReadOnly="False">
</TextBox>
<CheckBox x:Name="cboxName" Content="Is null ?" Click="cboxName_Click" IsChecked="{Binding Path=THIS, Converter={StaticResource MyContextToBoolConverter}}">
</CheckBox>
</StackPanel>
public class MyContextToBoolConverter: IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return (value!=null);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return parameter;
}
}
I just only want to get DataContext to checkbox from StackPanel.

You should replace THIS with . or completely remove the Path from the Binding. This will create a binding directly to the DataContext.
IsChecked="{Binding Converter={StaticResource MyContextToBoolConverter}}"

Or try this -
<StackPanel x:Name="StackPanel" DataContext="{Binding Path =MyContext}">
<TextBox Text="{Binding Path =Content}" x:Name="tbName" IsReadOnly="False" />
<CheckBox x:Name="cboxName" Content="Is null ?"
Click="cboxName_Click"
IsChecked="{Binding ElementName=StackPanel, Path=DataContext, Converter={StaticResource MyContextToBoolConverter}}">
</CheckBox>
</StackPanel>

Related

WPF bind enum to combobox

In my WPF UserControl I need to bind an Enum on a ComboBox. This enum is declared locally:
public partial class ViewerDataConfiguration : UserControl
{
private ViewerDataConfigurationViewModel PageViewModel;
public Visibility IsParametriSelected { get; set; }
public IEnumerable<eDatoAlarmMode> EnumAlarmModes {
get
{
return Enum.GetValues(typeof(eDatoAlarmMode)).Cast<eDatoAlarmMode>();
}
}
On the main Grid, where there is a collection bound, I defined a ComboBox as follows:
<TextBox Grid.Column="16" Text="{Binding ConfigObject.Edit.Source}" Style="{StaticResource txtDataStyle2}" Width="30" Visibility="{Binding ConfigObject.Edit, Converter={StaticResource ListaValoriVisibilityConverter}}" HorizontalAlignment="Stretch" TextChanged="Data_TextChanged" />
<Label Grid.Column="17" Content="AlarmMode" Style="{StaticResource labelStyle2}" />
<ComboBox Grid.Column="18" Width="30"
ItemsSource="{Binding Path=EnumAlarmModes, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=local:ViewerDataConfiguration}}"
DisplayMemberPath="Value"
SelectedValuePath="Value" Style="{StaticResource comboUsersStyle}" />
Basically seems that my IEnumerable is not bound correctly. I see the elements but they're blank. Any hint?
You are using DisplayMemberPath and SelectedValuePath attributes, but your collection item type is just a simple string, and want to use this entire instance directly, so you should remove these attributes and it should work as expected.
You also need to change the field to a property as data binding works only on properties, not class fields (although x:Bind in UWP no longer has this limitation):
public IEnumerable<AlarmMode> EnumAlarmModes
{
get
{
return Enum.GetValues(typeof(AlarmMode)).Cast<AlarmMode>();
}
}
If you want to display enum values instead of names, create a value converter:
public class EnumValueConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return (int)value;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
And then use it in the ItemTemplate:
<ComboBox Grid.Column="18" Width="100"
ItemsSource="{Binding Path=EnumAlarmModes}">
<ComboBox.Resources>
<local:EnumValueConverter x:Key="EnumValueConverter" />
</ComboBox.Resources>
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Converter={StaticResource EnumValueConverter}}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
For this to work you also have to add a xmlns:local declaration to your Window:
xmlns:local="clr-namespace:NamespaceOfConverter"

C# - WPF - Binding a List<int> to be printed in a StatusBar?

I have the following in xaml:
<StatusBarItem Content="{Binding CorrectGuesses}" Height="30" VerticalAlignment="Top" HorizontalContentAlignment="Center" />
Here, CorrectGuesses is a List<int>. I'd like the code to output the actual numbers in the list to the statusbar, but right now it only shows (Collection). What do I need to do so that the StatusBarItem's Content will be the items in the list? Thank you!
Add a Converter , so that it prints all the numbers.
namespace AppConverters
public class List2StringConverter : IValueConverter
{
public object Convert(object value, Type targetType,
object parameter, CultureInfo culture)
{
List<int> listNumbers = value as List<int>;
// separator : , - / ... or white space
return string.join("separator",listNumbers);
}
public object ConvertBack(object value, Type targetType,
object parameter, CultureInfo culture)
{
// To Do
}
}
in your xaml page add this line to your window tag as schema:
xmlns:app="clr-namespace:AppConverters"
also add :
<Window.Resources>
<app:List2StringConverter x:Key="L2StringConverter"/>
</Window.Resources>
then use it as follows :
<StatusBarItem Content="{Binding CorrectGuesses,Converter={StaticResource L2StringConverter}}" Height="30" VerticalAlignment="Top" HorizontalContentAlignment="Center" />
<StatusBarItem Height="30" VerticalAlignment="Top" HorizontalContentAlignment="Center">
<ItemsControl ItemsSource="{Binding CorrectGuesses}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StatusBarItem>

Using ObjectDataProvider inside HierarchicalDataTemplate

I want to add items of my class treeviewitem to a TreeView.
And I want to bind the ItemSource of this TreeViewItem to a method of itself !
I am trying to use the ObjectDataProvider for this.. See my XAML:
<Grid Background="#FFE5E5E5">
<Grid.Resources>
<HierarchicalDataTemplate DataType="{x:Type myNs:treeviewitem}">
<HierarchicalDataTemplate.Resources>
<ObjectDataProvider x:Key="getItems"
MethodName="GetItems"
ObjectInstance="{Binding RelativeSource={RelativeSource Self}}" />
</HierarchicalDataTemplate.Resources>
<HierarchicalDataTemplate.ItemsSource>
<Binding Source="{StaticResource getItems}" />
</HierarchicalDataTemplate.ItemsSource>
<StackPanel Orientation="Horizontal">
<TextBlock Margin="5,0,0,0"
Text="{Binding Name}" />
</StackPanel>
</HierarchicalDataTemplate>
</Grid.Resources>
<TreeView x:Name="guiTreeview"
HorizontalAlignment="Left"
Width="200" />
</Grid>
But binding to an ObjectInstance isnt possible!
How is it possible to get the current object instance "into" the ObjectDataProvider?
What would be the right way of doint this?
And NO, its not possible to use a Property ..
I have done it now with a ValueConverter.
XAML:
<Grid Background="#FFE5E5E5">
<Grid.Resources>
<HierarchicalDataTemplate DataType="{x:Type myNs:MyItem}" ItemsSource="{Binding RelativeSource={RelativeSource Self}, Converter={myNs:GetItemsConverter}}" >
<StackPanel Orientation="Horizontal">
<TextBlock Margin="5,0,0,0" Text="{Binding Name}" />
</StackPanel>
</HierarchicalDataTemplate>
</Grid.Resources>
<TreeView x:Name="guiTreeview" HorizontalAlignment="Left" Width="200" />
</Grid>
Converter:
public abstract class BaseConverter : MarkupExtension
{
public override object ProvideValue(IServiceProvider serviceProvider)
{
return this;
}
}
public class GetItemsConverter : BaseConverter, IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
var tvi = value as TreeViewItem;
if (tvi == null) return null;
var myitem = tvi.DataContext as MyItem;
if (myitem == null) return null;
return myitem.GetItems();
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return null;
}
}

WPF ListView with group of RadioButtons and select default value

Today I have a problem with selected default CheckBox. But First i show my code:
<ScrollViewer>
<ListView ItemsSource="{Binding itemsSource, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}">
<ListView.ItemTemplate>
<DataTemplate>
<Expander IsExpanded="True">
<Expander.Header>
<Label Content="{Binding AttrName, Mode=OneWay}" />
</Expander.Header>
<ListView Margin="20, 0, 0, 0" ItemsSource="{Binding subItemSource}" BorderBrush="Transparent" >
<ListView.ItemTemplate>
<DataTemplate>
<RadioButton GroupName="{Binding DataContext.AttrName, RelativeSource={RelativeSource AncestorType=ItemsControl}}"
Content="{Binding}"
<!-- What should I bind to to get item checked? -->
IsChecked={}/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Expander>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ScrollViewer>
So i have a nested binding where in CheckBoxes I bind GroupName to parent data context. My itemsSource contains the following properties:
int DefaultValue { get; set; }
List<int> subItemSource { get; set; }
And all I want now is to mark RadioButton when actual binding value is equal to DefaultValue. How should I do this? Should I write validator?
I'll start by writing a converter class
class ElementComparer : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return values[0] == values[1];
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
then declare the converter as a resource where l: is your namespace to converter
<l:ElementComparer x:Key="ElementComparer"/>
then in your data template
<DataTemplate>
<RadioButton GroupName="{Binding DataContext.AttrName, RelativeSource={RelativeSource AncestorType=ItemsControl}}"
Content="{Binding}"
<RadioButton.IsChecked>
<MultiBinding Converter="{StaticResource ElementComparer}" Mode="OneWay">
<Binding Path="DataContext.DefaultValue" RelativeSource="{RelativeSource AncestorType=ItemsControl}"/>
<Binding />
</MultiBinding>
</RadioButton.IsChecked>
provided the datacontext of the ItemsControl is containing the property for default value to compare with, the trick is to compare the selected item of the list to the current item to detect if it is default item, and will return true from converter and hence radio will be checked

WPF converter to update in real time background colour of textbox on text change

I have two textboxes for the firstname and second name of a user and I have created a converter to change the background colour of the textbox when the text equals a specific string. The problem I am having is that the textbox will only update at run time and doesn't update when I change the text is the textbox.
XAML:
<TextBox x:Name="forenameTextBox" Grid.Column="1" HorizontalAlignment="Left" Height="23" Margin="3" Grid.Row="1"
Background="{Binding Staff,Converter ={StaticResource StaffNameToBackgroundColourConverter1}}"
Text="{Binding Staff.Forename, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}" VerticalAlignment="Center" Width="120"/>
<Label Content="Surname:" Grid.Column="0" HorizontalAlignment="Left" Margin="3" Grid.Row="2" VerticalAlignment="Center"/>
<TextBox x:Name="surnameTextBox" Grid.Column="1" HorizontalAlignment="Left" Height="23" Margin="3" Grid.Row="2"
Background="{Binding Staff,Converter={StaticResource StaffNameToBackgroundColourConverter1}}"
Text="{Binding Staff.Surname, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}" VerticalAlignment="Center" Width="120"/>
Converter code:
public class StaffNameToBackgroundColourConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var staff = (Staff) value;
if (staff.Forename == "Donald" && staff.Surname == "Duck")
{
return "Yellow";
}
else
{
return "White";
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return value;
}
}
Correct text input:
Wrong text input - no change:
You need to add UpdateSourceTrigger=PropertyChanged to your Binding:
<TextBox x:Name="forenameTextBox" Grid.Column="1" HorizontalAlignment="Left"
Height="23" Margin="3" Grid.Row="1" Background="{Binding Staff,
UpdateSourceTrigger=PropertyChanged, Converter ={StaticResource
StaffNameToBackgroundColourConverter1}}" Text="{Binding Staff.Forename,
Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"
VerticalAlignment="Center" Width="120"/>
<TextBox x:Name="surnameTextBox" Grid.Column="1" HorizontalAlignment="Left" Height="23"
Margin="3" Grid.Row="2" Background="{Binding Staff,
UpdateSourceTrigger=PropertyChanged, Converter={StaticResource
StaffNameToBackgroundColourConverter1}}" Text="{Binding Staff.Surname, Mode=TwoWay,
NotifyOnValidationError=true, ValidatesOnExceptions=true}"
VerticalAlignment="Center" Width="120"/>
This will update the binding source as the user types each letter. You can find out more from the Binding.UpdateSourceTrigger Property page at MSDN.
You should return some brush object than colors to background like below
public class StaffNameToBackgroundColourConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo
culture)
{
var staff = (Staff)value;
if (staff.Forename == "Donald" && staff.Surname == "Duck")
{
return new SolidColorBrush(Colors.Yellow);
}
else
{
return new SolidColorBrush(Colors.White);
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return value;
}
}
First, you added the UpdateSourceTrigger=PropertyChanged to the wrong binding. You have to add it to the binding of the Text property.
Second, you bound the Text property to Staff.Forename but the Background to Staff. The Background property doesn't know that Staff has changed when you write in Staff.Forename. You have to raise the PropertyChanged event for the Staff property when you write in the Staff.Forename property. Same for Staff.Surname.

Categories