UpdateSourceTrigger for Datacontext in Silverlight - silverlight

Hi
I am working on a MVVM Silverlight app and i use UpdateSourceTrigger Property of TextBox to update the bindingexpression in runtime as follows:
.xaml.cs:
BindingExpression beID = txtEmpID.GetBindingExpression(TextBox.TextProperty);
beID.UpdateSource();
BindingExpression beAge = txtAge.GetBindingExpression(TextBox.TextProperty);
beAge.UpdateSource();
.xaml:
<Grid x:Name="LayoutRoot"
Background="White"
DataContext="{Binding Source={StaticResource keyEMPVM},
UpdateSourceTrigger=Explicit}">
//<Grid.RowDefinitions>
//<Grid.ColumnDefinitions>
<sdk:Label Grid.Row="2"
Grid.Column="1"
Target="{Binding ElementName=txtEmpID}" />
<TextBox x:Name="txtEmpID"
Grid.Row="2"
Grid.Column="2"
Style="{StaticResource ContentTextBoxStyle}"
Text="{Binding emp.ID, Mode=TwoWay, ValidatesOnExceptions=True,
ValidatesOnDataErrors=True, NotifyOnValidationError=True, UpdateSourceTrigger=Explicit}" />
<sdk:Label Grid.Row="4"
Grid.Column="1"
Target="{Binding ElementName=txtAge}" />
<TextBox x:Name="txtAge"
Grid.Row="4"
Grid.Column="2"
Style="{StaticResource ContentTextBoxStyle}"
Text="{Binding emp.Age, Mode=TwoWay, ValidatesOnExceptions=True,
ValidatesOnDataErrors=True, NotifyOnValidationError=True, UpdateSourceTrigger=Explicit}" />
<Button x:Name="btnSubmit"
Grid.Row="6"
Grid.Column="1"
Grid.ColumnSpan="2"
Style="{StaticResource ContentButtonStyle}"
Content="Submit"
Command="{Binding Path=UpdateEmployee}"
CommandParameter="{Binding emp.ID}" />
In this case i m doing the bindingexpressions manually for each textbox.. Is there a way by which i can do this bindingexpressions for all the textbox controls inside the grid at a single instance.

If you want to update each TextBox in a Grid, you can use this code:
private void LayoutRoot_KeyDown(object sender, KeyEventArgs e)
{
var grid = (Grid)sender;
foreach (var tb in GetChildren<TextBox>(grid))
{
var be = tb.GetBindingExpression(TextBox.TextProperty);
if(be != null) be.UpdateSource();
}
}
public IEnumerable<T> GetChildren<T>(DependencyObject d) where T:DependencyObject
{
var count = VisualTreeHelper.GetChildrenCount(d);
for(int i = 0; i < count; i++)
{
var c = VisualTreeHelper.GetChild(d, i);
if (c is T)
yield return (T)c;
foreach (var c1 in GetChildren<T>(c))
yield return c1;
}
}
Where KeyDown event is just an example.
Perhaps recursion isn't the best way to solve the problem, but it's the easiest way

Related

Element visibility tied to radiobutton group selection causes the group to freeze

I have a data bound RadioButton group in which one RadioButton (Replace) controls the visibility of another element.
When I select the Replace button the group becomes unresponsive. Interestingly, so does the form Cancel button. However, the OK button, which is implemented as a command continues to function (The Cancel button is just implemented as IsCancel="true").
<Border x:Name="pnlOptions" Margin="10" Background="AliceBlue" BorderThickness="2" CornerRadius="25">
<GroupBox TextElement.FontSize="14" TextElement.FontWeight="Bold" >
<StackPanel Orientation="Vertical">
<RadioButton GroupName="grpOptions" Margin="10,10,0,0" IsChecked="{Binding Path=SegmentSplitOption, Converter={StaticResource EnumRadioButtonConverter}, ConverterParameter={x:Static model:eSegmentSplitOption.Replace},Mode=TwoWay}">Replace original segment.</local:RadioButton>
<RadioButton GroupName="grpOptions" Margin="10,10,0,0" IsChecked="{Binding Path=SegmentSplitOption, Converter={StaticResource EnumRadioButtonConverter}, ConverterParameter={x:Static model:eSegmentSplitOption.Start},Mode=TwoWay}">Place at Start.</local:RadioButton>
<RadioButton GroupName="grpOptions" Margin="10,10,0,0" IsChecked="{Binding Path=SegmentSplitOption, Converter={StaticResource EnumRadioButtonConverter}, ConverterParameter={x:Static model:eSegmentSplitOption.Finish},Mode=TwoWay}">Place at End.</local:RadioButton>
<RadioButton GroupName="grpOptions" Margin="10,10,0,10" IsChecked="{Binding Path=SegmentSplitOption, Converter={StaticResource EnumRadioButtonConverter}, ConverterParameter={x:Static model:eSegmentSplitOption.Mid},Mode=TwoWay}">Place at Drop Location.</local:RadioButton>
</StackPanel>
</GroupBox>
</Border>
<StackPanel Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="3" Orientation="Horizontal" Visibility="{Binding DurationVisibility}">
<Label>Duration</Label>
<local:TextBox Grid.Row="2" Grid.Column="1" x:Name="txtDuration" Width="80" HorizontalAlignment="Left" VerticalAlignment="Bottom" FontSize="14"
Text="{Binding Path=DurationMinutes, Converter={StaticResource DecimalHoursConverter}, Mode=TwoWay}" Style="{StaticResource GeneralTextBoxStyle}"/>
<Label Grid.Row="2" Grid.Column="2">(hh.dd)</Label>
</StackPanel>
private eSegmentSplitOption _SegmentSplitOption;
public eSegmentSplitOption SegmentSplitOption
{
get { return _SegmentSplitOption; }
set
{
if (_SegmentSplitOption != value)
{
_SegmentSplitOption = value;
NotifyPropertyChanged("SegmentSplitOption");
NotifyPropertyChanged("DurationVisibility");
}
}
}
public Visibility DurationVisibility
{
get { return _SegmentSplitOption == eSegmentSplitOption.Replace || _SegmentSplitOption == eSegmentSplitOption.NotSet ? Visibility.Collapsed : Visibility.Visible; }
}
The problem lay elsewhere in the CmdOK_CanExecute function which had the following code:
e.CanExecute = _SegmentSplitOption == eSegmentSplitOption.Replace || _DurationMinutes.HasValue && _DurationMinutes.Value > 0;
if (wPrevCanExecute != e.CanExecute && e.CanExecute)
{
Application.Current.Dispatcher.Invoke(new Action(() =>
{
btnOK.Focus();
}));
}
The intent was to set focus to the OK button when the command became able to execute. Why this should lock the radio buttons and the Cancel button is still a mystery.

ListPicker issue in WindowsPhone8

Am using a list picker in a WindowsPhone App,I am not able to load the selected element in the list picker,the selected value shows the first item which was loaded during the page load,But the value we get in selection changed event is the correct one.Plz help me
XAML :
<Grid.Resources>
<DataTemplate x:Name="picker">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}" Margin="0 0 0 0" FontSize="25" FontFamily="{StaticResource PhoneFontFamilyLight}"/>
</StackPanel>
</DataTemplate>
<DataTemplate x:Name="PickerFullModeItemTemplate">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}" Margin="0 0 0 0" FontSize="18" FontFamily="{StaticResource PhoneFontFamilyLight}"/>
</StackPanel>
</DataTemplate>
</Grid.Resources>
<toolkit:ListPicker ItemTemplate="{StaticResource PickerFullModeItemTemplate}" FullModeItemTemplate="{StaticResource PickerFullModeItemTemplate}" x:Name="list_city" Grid.Row="3" Grid.Column="5" Grid.ColumnSpan="2" VerticalAlignment="Top" SelectionChanged="list_city_SelectionChanged" Height="170" Grid.RowSpan="1" Margin="12,12,12,0" />
C# :
private void list_city_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
int i = list_city.SelectedIndex;
string val = lst_cities[i]; //list of cities
}
Try this! It might work,
private void list_city_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
int i = (sender as ListBox).SelectedIndex;
string val = lst_cities[i];
}
You need to bind the SelectedItem property of the ListBox to a property in your ViewModel using TwoWay databinding. If your property has the correct selected item you want when the ListBox loads then it will have the correct selection.

Set Grid background color programmatically in Silverlight

I have a Data template
<DataTemplate x:Key="ConnectorItemFactory">
<Button Style="{StaticResource TextOnlyActionTileButtonStyle}" Margin="0,0,5,0"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Stretch"
Content="{Binding}"
ContentTemplate="{StaticResource TileTemplate}"
Command="{StaticResource NavigationCommand}"
CommandParameter="{Binding}"
Height="156"
Width="156"
>
<i:Interaction.Behaviors>
<UICommon:XboxBehavior VuiBinding="{Binding VuiTitle}"/>
</i:Interaction.Behaviors>
</Button>
</DataTemplate>
as a ContentTemplate it is used another data template
<DataTemplate x:Key="TileTemplate">
<Grid VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Background="{StaticResource ActionButtonBackgroundBrush}">
<StackPanel Orientation="Vertical" HorizontalAlignment="Left" VerticalAlignment="Bottom" Margin="7,7,7,4">
<Controls:TrimmedTextBlock Text="{Binding Title}" Style="{StaticResource TextOnlyTileTitleStyle}" TextWrapping="Wrap" />
<Controls:TrimmedTextBlock Text="{Binding Converter={StaticResource SubtitleTextFormatter}}" Style="{StaticResource TextOnlyTileSubtitleStyle}"/>
</StackPanel>
</Grid>
</DataTemplate>
I'm using a TemplateFactory to load the content template
public class GridTemplateFactory : ModelViewTemplateFactory
{
protected override void OnContentChanged(object oldContent, object newContent)
{
base.OnContentChanged(oldContent, newContent);
var dataTemplate = Application.Current.Resources["ConnectorItemFactory"] as DataTemplate;
// var grid = ((Button)dataTemplate.LoadContent()).ContentTemplate.LoadContent();
// ((Grid)grid).Background = new SolidColorBrush(Colors.Orange);
// ((Button)dataTemplate.LoadContent()).ContentTemplate.LoadContent().SetValue(Grid.BackgroundProperty, new SolidColorBrush(Colors.Orange));
this.ContentTemplate = dataTemplate;
}
}
In the OnContentChanged method I want to change the Grid background color from the TileTemplate data template.
I tried to do it like in commented code above, but it doesn't work. How can I change the color here?

Bind listbox to ObservableCollection

I cannot find an answer I can work with for this problem.
I have an ObservableCollection
this is myClass:
public class myClass
{
public string name;
public int[] dimensions = new int[2];
}
This is the code that sets ObservableCollection:
public class roomBuilder
{
private ObservableCollection<myClass> rooms;
public roomBuilder() //constructor
{
string roomName;
int[] dimensions = new int[2];
myClass newRoom = new myClass();
rooms = new ObservableCollection<room>();
roomName = "Hall";
dimensions[0] = 10;
dimensions[1] = 12;
newRoom.name = roomName;
newRoom.dimensions = dimensions;
rooms.Add(newRoom);
roomListBox.DataContext = rooms;
}
the XAML for this is:
<ListBox Canvas.Left="-1" Canvas.Top="47" Height="419" Name="roomListBox" Width="481" BorderThickness="1" BorderBrush="GhostWhite" ItemsSource="{Binding}" DataContext="{Binding}">
<ListBox.ItemTemplate >
<DataTemplate >
<StackPanel Orientation="Vertical" Margin="1" Name="verstack" >
<StackPanel Orientation="Horizontal" Margin="1" KeyDown="StackPanel_KeyDown" >
<TextBox Text="{Binding Path=name}" IsReadOnly="False" FontFamily="Courier New" FontSize="22" Height="65" VerticalAlignment="Top" TextAlignment="Center"/>
<TextBox Name="xDimension" Text="{Binding Mode=TwoWay, Path=dimensions[0] }" Width="70" Height="65" VerticalAlignment="Top" IsReadOnly="False" FontFamily="Courier New" Margin="2,0,1,0" FontSize="22" MaxLength="3" InputScope="TelephoneNumber" TextAlignment="Center" />
<TextBlock Name="separator" Text=":" FontSize="32" FontWeight="ExtraBold" Margin="1,4,1,0" />
<TextBox Name="yDimension" Text="{Binding Mode=TwoWay, Path=dimensions[1] }" Width="70" Height="65" VerticalAlignment="Top" IsReadOnly="False" FontFamily="Courier New" Margin="1,0,2,0" FontSize="22" MaxLength="3" InputScope="TelephoneNumber" TextAlignment="Center"/>
I havent closed the Xaml off here , there's a load more underneath it, when I run this nothing is displayed and I just don't know what the problem is, I've been hammering away at it for 2 days, please someone help
Rooms needs to be a public property that you bind to.
public ObservableCollection<myClass> rooms
{
get { return ........

Binding not triggering Action<>

I have some code like this
this is a custom datagrid which displays hierarchical data which should close and open.
<UserControl.DataContext>
<loc:Def1 x:Name="initdef1"/>
</UserControl.DataContext>
<Grid x:Name="LayoutRoot" HorizontalAlignment="Center" VerticalAlignment="Center" >
<data:DataGrid x:Name="_dataGrid" AutoGenerateColumns="False"
ItemsSource="{Binding Display, Mode=OneWay}"
SelectionMode="Extended" >
<data:DataGrid.Columns>
<data:DataGridTemplateColumn Header="Col1">
<data:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" >
<CheckBox IsChecked="{Binding IsExpanded, Mode=TwoWay}" Margin="{Binding Path=Level, Converter={StaticResource ConvertToThickness}}"/>
<TextBlock Text="{Binding Cells[0]}" Margin="4" />
</StackPanel>
</DataTemplate>
</data:DataGridTemplateColumn.CellTemplate>
</data:DataGridTemplateColumn>
<data:DataGridTextColumn Header="Col2" Binding="{Binding Cells[1]}" />
</data:DataGrid.Columns>
</data:DataGrid>
with this is def1
this class has the actual logic for all the processing and loading and mapping the data to the grid.
public Def1()
{
_columns = new List<ColumnDef>();
_source = new ObservableCollection<Def2>();
Def2.RowExpanding += new Action<Def2>(RowDef_RowExpanding);
Def2.RowCollapsing += new Action<Def2>(RowDef_RowCollapsing);
}
void RowDef_RowExpanding(Def2 row)
{
foreach (RowDef child in row.Children)
child.IsVisible = true;
OnPropertyChanged("Display");
}
void RowDef_RowCollapsing(Def2 row)
{
foreach (Def2 child in row.Children)
{
if (row.IsExpanded.HasValue && row.IsExpanded.Value)
RowDef_RowCollapsing(child);
child.IsVisible = false;
}
OnPropertyChanged("Display");
}
and this in def2
this class has the logic on how should the rows behave.
public bool? IsExpanded
{
get { return _isExpanded; }
set
{
if (_isExpanded != value)
{
_isExpanded = value;
if (_isExpanded.Value)
{
if (RowDef.RowExpanding != null)
RowDef.RowExpanding(this);
}
else
{
if (RowDef.RowCollapsing != null)
RowDef.RowCollapsing(this);
}
}
}
}
The thing is when the checkbox is checked or unchecked nothing happens.
Ok I found the answer from a similar post wpf 4.0 datagrid template column two-way binding problem
So I changed the code to
<CheckBox IsChecked="{Binding Mode=TwoWay, Path=IsExpanded, UpdateSourceTrigger=PropertyChanged}" Margin="{Binding Path=Level, Converter={StaticResource ConvertToThickness}}" Checked="CheckBox_Checked" Unchecked="CheckBox_Unchecked" x:Name="checkbox1"/>
Now it works.
But can anybody explain why i needed to set UpdateSourceTrigger=PropertyChanged ?
It's not always required.
Thanks

Resources