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

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.

Related

Radio button created as user control binding to observablecollection of enums

Have a user control created with radio button binding to a enum property.
Everything works when one user control is added to main window, but things go awkward when we have more than one user control all are bonded to same enum property. change one of them and all the radio buttons show same value.
How can i bind a radio button in a user control to observable collection of enum?
so that any number of user controls added to main window wil have independent binding.
ViewModel:
public enum SISOModels
{
NoModel,
PredictionOnly,
PredictionAndControl
};
private SISOModels _sisoModel;
public SISOModels sisoModel
{
get
{
return _sisoModel;
}
set
{
_sisoModel = value;
OnPropertyChanged("sisoModel");
}
}
private ObservableCollection<SISOModels> _sisoModelList;
public ObservableCollection<SISOModels> sisoModelList
{
get
{
return _sisoModelList;
}
set
{
_sisoModelList = value;
OnPropertyChanged("sisoModelList");
}
}
View:
<RadioButton x:Name="r1" Content="No Model" FontSize="16" IsChecked= "{Binding Path = sisoModel , Mode=TwoWay, Converter={StaticResource EnumToBooleanConverter}, ConverterParameter={x:Static local:SISOModels.NoModel}}"/>
<RadioButton x:Name="r2" Content="Prediction Only" FontSize="16" IsChecked="{Binding Path = sisoModel, Mode=TwoWay, Converter={StaticResource EnumToBooleanConverter}, ConverterParameter={x:Static local:SISOModels.PredictionOnly}}"/>
<RadioButton x:Name="r3" Content="Prediction And Control" FontSize="16" IsChecked="{Binding Path = sisoModel, Mode=TwoWay, Converter={StaticResource EnumToBooleanConverter}, ConverterParameter={x:Static local:SISOModels.PredictionAndControl}}"/>
this works as i am binding to one enum property but with multiple such user controls added all are binded to same enum property.
if i change it to this:
<RadioButton x:Name="r1" Content="No Model" FontSize="16" IsChecked= "{Binding Path = sisoModelList , Mode=TwoWay, Converter={StaticResource EnumToBooleanConverter}, ConverterParameter={x:Static local:SISOModels.NoModel}}"/>
<RadioButton x:Name="r2" Content="Prediction Only" FontSize="16" IsChecked="{Binding Path = sisoModelList, Mode=TwoWay, Converter={StaticResource EnumToBooleanConverter}, ConverterParameter={x:Static local:SISOModels.PredictionOnly}}"/>
<RadioButton x:Name="r3" Content="Prediction And Control" FontSize="16" IsChecked="{Binding Path = sisoModelList, Mode=TwoWay, Converter={StaticResource EnumToBooleanConverter}, ConverterParameter={x:Static local:SISOModels.PredictionAndControl}}"/>
i get error saying "binding should be a enum"
It's pretty simple. You can use, for example, ItemsControl:
Assuming you have a view model:
enum Enumeration { One, Two, Three }
class ViewModel
{
public ViewModel()
{
this.Collection = new ObservableCollection<Enumeration> { Enumeration.One, Enumeration.Three };
}
public ObservableCollection<Enumeration> Collection { get; private set; }
}
Then add an ItemsControl container:
<Window.Resources>
<local:ViewModel x:Key="viewModel"/>
</Window.Resources>
<Grid DataContext="{StaticResource viewModel}">
<ItemsControl ItemsSource="{Binding Collection}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
You then set your collection as the items source, and your control would be the data template.
In my example, this control is a simple TextBlock, but you can use your custom control here.
EDIT:
There is no problem using converters, too. You just need to use the right Path. By the way, the IsChecked property binding is TwoWay by default, so you don't need to specify it explicitly.
You can replace the ItemsControl with a Grid or any container you like.
<Window.Resources>
<local:ViewModel x:Key="viewModel"/>
<local:EnumToBooleanConverter x:Key="EnumToBooleanConverter"/>
</Window.Resources>
<Grid DataContext="{StaticResource viewModel}">
<ItemsControl ItemsSource="{Binding sisoModelList}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<RadioButton x:Name="r1" Content="No Model" FontSize="16" IsChecked="{Binding Path=., Converter={StaticResource EnumToBooleanConverter}, ConverterParameter={x:Static local:SISOModels.NoModel}}"/>
<RadioButton x:Name="r2" Content="Prediction Only" FontSize="16" IsChecked="{Binding Path=., Converter={StaticResource EnumToBooleanConverter}, ConverterParameter={x:Static local:SISOModels.PredictionOnly}}"/>
<RadioButton x:Name="r3" Content="Prediction And Control" FontSize="16" IsChecked="{Binding Path=., Converter={StaticResource EnumToBooleanConverter}, ConverterParameter={x:Static local:SISOModels.PredictionAndControl}}"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>

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?

How to change data in a Silverlight DataContext Object

I have a datacontext object that displays a list of uploaded files, and number of copies. So far, the user can click an edit icon that is in each row, and retrieve the data in that row, but I do not know how to change any data.
Here is the button event for the 'change details' dialog on the main page:
private void Image_MouseLeftButtonUp_1(object sender, MouseButtonEventArgs e)
{
Image b = sender as Image;
FileReceivedItem fi = b.DataContext as FileReceivedItem;
string fileCopies = fi.fileCopies;
string fileName = fi.FileName;
DetailsWindow detailsDlg = new DetailsWindow(fileCopies, fileName);
detailsDlg.Show();
detailsDlg.Closed += new EventHandler(detailsWnd_Closed);
}
public DetailsWindow detailsDlg;
void detailsWnd_Closed(object sender, EventArgs e)
{
MessageBox.Show("I want to change fileCopies here");
}
The relevant portions of the XAML:
<ListBox ScrollViewer.HorizontalScrollBarVisibility="Hidden" ItemsSource="{StaticResource FileReceivedItem}" Name="filesReceivedList" HorizontalAlignment="Left" Grid.Row="1" Grid.Column="1" Background="White" Margin="12,23,0,0"
VerticalAlignment="Top" Width="411" Height="175" Loaded="filesReceivedList_Loaded">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Width="404" Height="19" Orientation="Horizontal" >
<TextBlock x:Name="ListFileName" Text="{Binding FileName}" Width="283" VerticalAlignment="Center">
<ToolTipService.ToolTip>
<ToolTip Content="{Binding FileName}"></ToolTip>
</ToolTipService.ToolTip>
</TextBlock>
<TextBlock Text="{Binding fileCopies}" Width="50" VerticalAlignment="Center"/>
<TextBlock Text="{Binding FileID}" Width="0" Visibility="Collapsed" VerticalAlignment="Center"/>
<Image Source="images/Edit.png" MouseLeftButtonUp="Image_MouseLeftButtonUp_1" Width="20" Margin="0 0 0 0">
<ToolTipService.ToolTip>
<ToolTip Content="Edit"></ToolTip>
</ToolTipService.ToolTip>
</Image>
<TextBlock Text="" Width="10" />
<Image Source="images/Delete.png" MouseLeftButtonUp="Image_MouseLeftButtonUp" >
<ToolTipService.ToolTip>
<ToolTip Content="Delete"></ToolTip>
</ToolTipService.ToolTip>
</Image>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Let me know if any important pieces of code are missing. I'm not sure how the data source works exactly.
I eventually got it to work. Pretty straightforward. I just haven't used SL in ahwile. This is what I did, although there might be a better way that someone might provide as a better answer:
void detailsWnd_Closed(object sender, EventArgs e)
{
changeFileCopies(detailsDlg.FileName, detailsDlg.nCopies.Text);
}
public void changeFileCopies(string filename, string newCopies)
{
var row = (FileReceivedItem)filesReceivedDataSource.Where(x => x.FileName == filename).FirstOrDefault();
row.fileCopies = newCopies;
filesReceivedList.ItemsSource = null;
this.filesReceivedList.ItemsSource = filesReceivedDataSource;
}

UpdateSourceTrigger for Datacontext in 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

How to access Button programatically if the button is inside using C#

I have few questions as I am usign XAML for the first time.
How do I use the button (BrowseButton) to browse a folder in Harddrive ?
In this case as the button is inside
Can I use the way I have shown below?
Actually first dockpanel will hold the image and some label and the other dockpanel will have tabcontrol in it.
If I have a tabcontrol, How can I add a listview which can increase the tabs during runtime.. and the listview should be available in the runtime also.
How to add a close("X") mark on the top of the tab to close the button
probably I asked a lot of questions, sorry :(
Please help
<Grid>
<DockPanel>
<StackPanel>
<Image Name="imgClientPhoto" HorizontalAlignment="Left" VerticalAlignment="Top" Width="auto" Height="auto" Grid.Column="0" Grid.Row="0" Margin="0"
Source="D:ehtmp_top_left.gif" MinWidth="450" MinHeight="100" Grid.IsSharedSizeScope="True">
</Image>
<Button x:Name="BrowseButton" Margin="0,13.638,30,14.362" Content="Browse" Click="BrowseButton_Click" HorizontalAlignment="Right" Width="111" />
<TextBox x:Name="txtBxBrowseTB" Margin="46,10,146,10" Text="TextBox" TextWrapping="Wrap" TextChanged="BrowseTB_TextChanged"></TextBox>
<Label HorizontalAlignment="Left" Margin="-14,22,0,10" Name="label1" Width="69.75" FontSize="13" VerticalContentAlignment="Top" HorizontalContentAlignment="Center">Path:</Label>
</Grid>
</GroupBox>
</Grid>
</StackPanel>
</DockPanel>
<DockPanel>
<StackPanel Margin="0,158,0,0" HorizontalAlignment="Left" Width="330" Height="557.5" VerticalAlignment="Top">
<TextBox Height="50" Name="textBox1" Width="240" Margin="0,35,0,0" VerticalAlignment="Stretch" HorizontalAlignment="Right" />
<ListBox Height="470" Name="listBox1" Width="332" Background="LightGray" Margin="0,0,0,0" BorderBrush="IndianRed" BorderThickness="3" />
</StackPanel>
<TabControl Height="234" Name="tabControl1" Width="1035" Margin="0,0,0,0">
<TabItem Header="tabItem1" Name="tabItem1">
<Grid Height="144" />
</TabItem>
</TabControl>
</DockPanel>
</Grid>
1) The browse code should be something like this:
private void BrowseButton_Click(object sender, RoutedEventArgs e)
{
System.Windows.Forms.FolderBrowserDialog browse = new System.Windows.Forms.FolderBrowserDialog();
browse.RootFolder= Environment.SpecialFolder.MyDocuments;
browse.SelectedPath = "C:\\InitalFolder\\SomeFolder";
if (browse.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
txtBxBrowseTB.Text = browse.SelectedPath;
}
}
2) I have tried to simplify the xaml. Does this look like something you could go with?:
<Grid>
<Image Name="imgClientPhoto" Margin="0" Height="262" VerticalAlignment="Top" HorizontalAlignment="Left" ></Image>
<StackPanel VerticalAlignment="Stretch" >
<StackPanel VerticalAlignment="Top" Orientation="Horizontal" Height="30">
<Button Name="BrowseButton" Content="Browse" Click="BrowseButton_Click" HorizontalAlignment="Right" Width="111" />
<Label Name="label1" Width="69.75" FontSize="13" VerticalContentAlignment="Center" HorizontalContentAlignment="Right">Path:</Label>
<TextBox Name="txtBxBrowseTB" Width="200" Text="TextBox" VerticalContentAlignment="Center" TextWrapping="Wrap" TextChanged="BrowseTB_TextChanged"></TextBox>
</StackPanel>
<StackPanel>
<StackPanel Orientation="Vertical">
<TextBox Height="50" Name="textBox1" />
<ListBox Height="470" Name="listBox1" Background="LightGray" Margin="0,0,0,0" BorderBrush="IndianRed" BorderThickness="3" MouseLeftButtonUp="listBox1_MouseLeftButtonUp">
<ListBoxItem>User1</ListBoxItem>
<ListBoxItem>User2</ListBoxItem>
<ListBoxItem>User3</ListBoxItem>
<ListBoxItem>User4</ListBoxItem>
</ListBox>
</StackPanel>
<TabControl Name="tabControl1" />
</StackPanel>
</StackPanel>
</Grid>
You can also have a close button in the tab item Header. As many of the content properties in xaml controls, the content can actually be controls, and not necessary just a text.
<TabControl Name="tabControl1" >
<TabItem Name="tabItem1" >
<TabItem.Header>
<StackPanel Orientation="Horizontal">
<Label>TabHeader1</Label>
<Button Height="20" Width="20" FontWeight="Bold" Click="CloseTabButton_Click">X</Button>
</StackPanel>
</TabItem.Header>
<Grid Height="144">
<ListView />
</Grid>
</TabItem>
</TabControl>
3) Here is how you would add the tabs in C# dynamically:
private void listBox1_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
//Get selected item
ListBoxItem item = (ListBoxItem)listBox1.SelectedItem;
string itemText = item.Content.ToString();
//Check if item is already added
foreach (TabItem tItem in tabControl1.Items)
{
if ((string)tItem.Tag == itemText)
{
//Item already added, just activate the tab
tabControl1.SelectedItem = tItem;
return;
}
}
//Build new tab item
TabItem tabItem = new TabItem();
tabItem.Tag = itemText;
//First build the Header content
Label label = new Label();
Button button = new Button();
label.Content = itemText;
button.Content = "X";
button.Height = 20;
button.Width = 20;
button.FontWeight = FontWeights.Bold;
button.Click += CloseTabButton_Click; //Attach the event click method
button.Tag = tabItem; //Reference to the tab item to close in CloseTabButton_Click
StackPanel panel = new StackPanel();
panel.Orientation = Orientation.Horizontal;
panel.Children.Add(label);
panel.Children.Add(button);
tabItem.Header = panel;
//Then build the actual tab content
//If you need only the ListView in here, you don't need a grid
ListView listView = new ListView();
//TODO: Populate the listView with what you need
tabItem.Content = listView;
//Add the finished tabItem to your TabControl
tabControl1.Items.Add(tabItem);
tabControl1.SelectedItem = tabItem; //Activate the tab
}
private void CloseTabButton_Click(object sender, RoutedEventArgs e)
{
//The tab item was set to button.Tag when it was added
Button button = (Button)sender;
TabItem tabItem = (TabItem)button.Tag;
if (tabItem != null)
{
button.Click -= CloseTabButton_Click; //Detach event handler to prevent memory leak
tabControl1.Items.Remove(tabItem);
}
}

Resources