The BusyIndicator inside the Expander does not work - wpf

I want to create an Expander that contains a BusyIndicator and as soon as you click on the Expander, a BusyIndicator will appear until there is content
<Grid>
<Expander Expanded="Expander_OnExpanded">
<syncfusion:SfBusyIndicator x:Name="BusyIndicator">
<ItemsControl x:Name="ItemsControl">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</syncfusion:SfBusyIndicator>
</Expander>
</Grid>
private void Expander_OnExpanded(object sender, RoutedEventArgs e)
{
BusyIndicator.IsBusy = true;
ItemsControl.ItemsSource = new ObservableCollection<string> { "A", "B", "C" };
Thread.Sleep(1000);
BusyIndicator.IsBusy = false;
}

Thread.Sleep blocks the UI thread. Wait asynchronously or perform any long-running operation on a background thread:
private async void Expander_OnExpanded(object sender, RoutedEventArgs e)
{
BusyIndicator.IsBusy = true;
ItemsControl.ItemsSource = new ObservableCollection<string> { "A", "B", "C" };
await Task.Delay(3000);
BusyIndicator.IsBusy = false;
}

Related

ItemContainerGenerator.ContainerFromItem method returns null if item has grouped

In WPF ListBox, I can get the selected item container using the method ItemContainerGenerator.ContainerFromItem(selectedItem) but it is not working when ListBoxItem is grouped.
MainWindow.xaml
<ListBox x:Name="listBox" ItemsSource="{Binding Contacts}" Loaded="cardView1_Loaded" SelectedIndex="0" Width="250" Height="250"
HorizontalAlignment="Center" VerticalAlignment="Center">
<ListBox.GroupStyle>
<GroupStyle/>
</ListBox.GroupStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Name}"/>
<TextBlock Text="{Binding Age}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
MainWindow.xaml.cs
In the loaded method, First I have called this method ItemContainerGenerator.ContainerFromItem(selectedItem) and it returns the container of the selected item because the Listbox item is not grouped. Then I have added grouping for Listbox item. Now, if i called this method it returns null.
public MainWindow()
{
InitializeComponent();
DataContext = new ViewModel();
}
private void cardView1_Loaded(object sender, RoutedEventArgs e)
{
withOutGroup.Text = withOutGroup.Text + listBox.ItemContainerGenerator.ContainerFromItem(listBox.SelectedItem);
ICollectionView collectionView = CollectionViewSource.GetDefaultView(listBox.ItemsSource);
collectionView.GroupDescriptions.Add(new PropertyGroupDescription("Name"));
withGroup.Text = withGroup.Text + listBox.ItemContainerGenerator.ContainerFromItem(listBox.SelectedItem);
}
Sample: ListBox-Testing-Project
How can I get the selected item container if the Listbox item is grouped?
You need to wait to call the ContainerFromItem method until the container has actually been created. This works:
private void cardView1_Loaded(object sender, RoutedEventArgs e)
{
ICollectionView collectionView = CollectionViewSource.GetDefaultView(listBox.ItemsSource);
collectionView.GroupDescriptions.Add(new PropertyGroupDescription("Name"));
Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Loaded,
new Action(() =>
{
var container = listBox.ItemContainerGenerator.ContainerFromItem(listBox.SelectedItem);
//...
}));
}

ContextMenu StaysOpen is not working

I am showing a UserControl inside ContextMenu. Futhermore in that UserControl I am showing a Popup which contains some buttons and datagrid. All the data in Popup loads during runtime.
The problem is ContextMenu ignores the property StaysOpen even though it is set to true.
The Popup does stay open when I set StaysOpen to true in code behind but ContextMenu doesn't.
I tried it with following code:
<UserControl x:Class="UserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<Popup Name="popupState" PlacementTarget="{Binding ElementName=txtSearch}" PopupAnimation="Slide" Placement="Bottom" Focusable="True" AllowsTransparency="True" VerticalAlignment="Top">
<Button HorizontalAlignment="Right" Margin="5" Background="GhostWhite" Name="btnSelectAll" Click="btnSelectAll_Click" Width="30" Height="30">
<my:DataGrid VerticalAlignment="Stretch" MaxHeight="300" VerticalScrollBarVisibility="Auto" RowHeaderWidth="0" Margin="5,5,5,1" Background="White" HorizontalAlignment="Stretch" Name="DGTeamCommunicator" HorizontalContentAlignment="Left" HorizontalGridLinesBrush="#D6D7D6" GridLinesVisibility="None">
<my:DataGridTemplateColumn Width="Auto" MinWidth="30">
<my:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" ContextMenuService.IsEnabled="True" ContextMenuService.HasDropShadow="True">
<Button Name="btnCall" Click="btnCall_Click" ContextMenuService.IsEnabled="True">
</Button>
</StackPanel>
</DataTemplate>
</my:DataGridTemplateColumn.CellTemplate>
</my:DataGridTemplateColumn>
</my:DataGrid>
</Popup>
My requirement is to Prevent the Popup as well as ContextMenu from closing when the buttons in Popup is clicked.
Kindly provide me a solution for this.
The bad news is that this behavior is by design. ContextMenu is defined to display few menus and when one of them is being clicked the ContextMenu internally sets the IsOpen to false.
The good news is that behavior should stay so and for any other customization you should take a Popup instead of ContextMenu. BUT if you MUST use ContextMenu for whatever reason here is a workaround:
<StackPanel>
<Button>
Popup Demo
<Button.ContextMenu>
<local:StaysOpenContextMenu x:Name="ContextMenu1" StaysOpen="True">
<StackPanel>
<TextBox x:Name="TextBox1" Width="100" TextChanged="OnTextChanged"/>
<Popup x:Name="Popup1" Placement="Bottom" PlacementTarget="{Binding ElementName=tbx}" StaysOpen="True">
<Button Content="click me"/>
</Popup>
</StackPanel>
</local:StaysOpenContextMenu>
</Button.ContextMenu>
</Button>
<Button Click="OnClick">Close Popup</Button>
</StackPanel>
You will need a custom ContextMenu to get the job done:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void OnTextChanged(object sender, TextChangedEventArgs e)
{
this.Popup1.IsOpen = true;
}
private void OnClick(object sender, RoutedEventArgs e)
{
this.Popup1.IsOpen = false;
this.ContextMenu1.CloseContextMenu();
}
}
public class StaysOpenContextMenu : ContextMenu
{
private bool mustStayOpen;
static StaysOpenContextMenu()
{
IsOpenProperty.OverrideMetadata(
typeof(StaysOpenContextMenu),
new FrameworkPropertyMetadata(false, null, CoerceIsOpen));
StaysOpenProperty.OverrideMetadata(
typeof(StaysOpenContextMenu),
new FrameworkPropertyMetadata(false, PropertyChanged, CoerceStaysOpen));
}
private static void PropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
StaysOpenContextMenu menu = (StaysOpenContextMenu)d;
menu.mustStayOpen = (bool)e.NewValue;
}
private static object CoerceStaysOpen(DependencyObject d, object basevalue)
{
d.CoerceValue(IsOpenProperty);
return basevalue;
}
private static object CoerceIsOpen(DependencyObject d, object basevalue)
{
StaysOpenContextMenu menu = (StaysOpenContextMenu)d;
if (menu.StaysOpen && menu.mustStayOpen)
{
return true;
}
return basevalue;
}
public void CloseContextMenu()
{
this.mustStayOpen = false;
this.IsOpen = false;
}
}

TreeViewItem with ItemsSource Right-Click doesn't select the Item

<DataTemplate DataType="{x:Type EntityType:FixedDevice}">
<TextBlock Text="{Binding RelativeSource={RelativeSource Self}, Converter={StaticResource NameConverter}}"/>
</DataTemplate>
<TreeView.ItemContainerStyle>
<Style TargetType="TreeViewItem">
<EventSetter Event="PreviewMouseRightButtonUp" Handler="TreeViewItem_RightClick"/>
</Style>
</TreeView.ItemContainerStyle>
<TreeViewItem Header="Data Warehouse">
<TreeViewItem.Items>
<TreeViewItem Header="Platforms">
<TreeViewItem.Items>
<TreeViewItem>
<TreeViewItem.Header>
<TextBlock Text="{Binding RelativeSource={RelativeSource Self},
Path=Parent.Items.Count,
StringFormat=Public ({0})}">
</TextBlock>
</TreeViewItem.Header>
</TreeViewItem.Header>
</TreeViewItem.Items>
</TreeViewItem>
</TreeViewItem.Items>
</TreeViewItem>
private void TreeViewItem_RightClick(object sender, MouseButtonEventArgs e) {
TreeViewItem item = sender as TreeViewItem;
if(item != null) { item.Focus(); item.IsSelected = true; }
e.Handled = true;
}
How come when I right-click, it only selects the top-most node? and not the one I click? Similar for an ItemsSource, which the Item itself is not a TreeViewItem, but a DataTemplate with a TextBlock, how do I select the object in the TreeView visually?
Edit, see below for answer based on #Viv answer.
I ended up having to use e.OriginalSource to retrieve the TextBlock then the TreeViewItem that the Item was in.
private void TreeViewItem_RightClick(object sender, MouseButtonEventArgs e) {
TreeViewItem item = (e.OriginalSource as FrameworkElement).Parent as TreeViewItem;
if(item == null) {
item = e.Source as TreeViewItem;
if(item == null) {
return;
}
}
item.IsSelected = true;
e.Handled = true;
}
It's because what your looking for is e.Source and not sender
try switching your right-click handler to:
private void TreeViewItem_RightClick(object sender, MouseButtonEventArgs e) {
TreeViewItem item = e.Source as TreeViewItem;
if (item == null)
return;
// item.Focus();
item.IsSelected = true;
e.Handled = true;
}
Sample Download

How to make added buttons visible for the selected row in Wpf Datagrid

I have a Wpf Datagrid with edit,update and cancel buttons. Initially edit button is made visible, On click of edit button update and cancel button is made visible.
The issue here is when I click on edit button , update and cancel button are made visible for all the rows in the grid. I want it to be visible only for the selected row in the grid.
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel Name="Stkbuttons">
<Button Name="BtnEdit" Content="Edit" Width="Auto" Click="BtnEdit_Click" Visibility="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=BtnEditVisibility}"></Button>
<Button Name="BtnUpdate" Content="Update" Width="Auto" Click="BtnUpdate_Click" Visibility="{Binding RelativeSource= {RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=BtnUpdateVisibility}"></Button>
<Button Name="BtnCancel" Content="Cancel" Width="Auto" Click="BtnCancel_Click" Visibility="{Binding RelativeSource= {RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=BtnCancelVisibility}"></Button>
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
public static readonly DependencyProperty BtnEditVisibilityProperty = DependencyProperty.Register("BtnEditVisibility", typeof(Visibility), typeof(OrderExecution));
public Visibility BtnEditVisibility
{
get { return (Visibility)GetValue(BtnEditVisibilityProperty); }
set { SetValue(BtnEditVisibilityProperty, value); }
}
public static readonly DependencyProperty BtnUpdateVisibilityProperty = DependencyProperty.Register("BtnUpdateVisibility", typeof(Visibility), typeof(OrderExecution));
public Visibility BtnUpdateVisibility
{
get { return (Visibility)GetValue(BtnUpdateVisibilityProperty); }
set { SetValue(BtnUpdateVisibilityProperty, value); }
}
public static readonly DependencyProperty BtnCancelVisibilityProperty = DependencyProperty.Register("BtnCancelVisibility", typeof(Visibility), typeof(OrderExecution));
public Visibility BtnCancelVisibility
{
get { return (Visibility)GetValue(BtnCancelVisibilityProperty); }
set { SetValue(BtnCancelVisibilityProperty, value); }
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
// By default display editButton
BtnUpdateVisibility = Visibility.Collapsed;
BtnCancelVisibility = Visibility.Collapsed;
}
private void BtnUpdate_Click(object sender, RoutedEventArgs e)
{
BtnEditVisibility = Visibility.Visible;
BtnUpdateVisibility = Visibility.Collapsed;
BtnCancelVisibility = Visibility.Collapsed;
}
private void BtnEdit_Click(object sender, RoutedEventArgs e)
{
BtnEditVisibility = Visibility.Collapsed;
BtnUpdateVisibility = Visibility.Visible;
BtnCancelVisibility = Visibility.Visible;
}
Before enabling your buttons go to the parent of the clicked Edit button and get only his childs buttons (Update - Cancel) and change the visibility for only those two buttons.

how can we access the controls in the Itemtemplate Silverlight

i have a list box. i have an item template with a stack panel in it.
it has a text box and a check box in the item template.
is there a way i can access the check box and enable/disable it on selected index changed?
<UserControl.Resources>
<DataTemplate x:Key="UserApplicationsTemplate">
<StackPanel Orientation="Horizontal"
Margin="2"
ToolTipService.Placement="Mouse"
ToolTipService.ToolTip="{Binding Description, Mode=OneWay}">
<TextBlock Text="{Binding Mode=OneWay}"
TextWrapping="Wrap"
Width="100"
DataContext="{Binding ApplicationName, Mode=OneWay}" />
<CheckBox x:Name="{Binding ApplicationName, Mode=OneWay}"
Margin="5,0,0,0"
Click="IsActive_Clicked"
IsChecked="{Binding IsActive, Mode=OneWay}"
Content="IsActive"/>
</StackPanel>
</DataTemplate>
</UserControl.Resources>
<ListBox x:Name="lstbxUserApplications"
Height="357"
ItemsSource="{Binding Mode=OneWay}"
SelectionMode="Single"
ItemTemplate="{StaticResource UserApplicationsTemplate}" />
Assming you have your ItemsSource binded:
<ListBox x:Name="myList">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{Binding Check, Mode=TwoWay}" />
<TextBlock Text="{Binding Name, Mode=TwoWay}"
Width="100" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Button x:Name="button1"
Content="Uncheck 2"
Click="button1_Click" />
You don't actually need to change the CheckBox.IsChecked property, but the value on your ItemsSource:
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
this.Loaded += new RoutedEventHandler(MainPage_Loaded);
}
void MainPage_Loaded(object sender, RoutedEventArgs e)
{
myList.ItemsSource = ListInfo.getInfo();
}
private void button1_Click(object sender, RoutedEventArgs e)
{
ListInfo item = myList.Items[1] as ListInfo;
item.Check = !item.Check;
}
}
public class ListInfo : INotifyPropertyChanged
{
private string name;
public string Name
{
get
{
return name;
}
set
{
name = value;
NotifyPropertyChange("Name");
}
}
private bool check;
public bool Check
{
get
{
return check;
}
set
{
check = value;
NotifyPropertyChange("Check");
}
}
public static ObservableCollection<ListInfo> getInfo()
{
ObservableCollection<ListInfo> data = new ObservableCollection<ListInfo>();
data.Add(new ListInfo { Name = "Some text 1", Check = true });
data.Add(new ListInfo { Name = "Some text 2", Check = false });
data.Add(new ListInfo { Name = "Some text 3", Check = true });
return data;
}
public void NotifyPropertyChange(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
#endregion
}
If you take a look at the event handler for the Click event on the button, you can see that all I did was get the item and changed the value. This immediately reflects on the UI.
UPDATE: I see that this was not what you asked for. Here are a couple of ideas:
You can have an event handler for your check box:
<ListBox x:Name="myList">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{Binding Check, Mode=TwoWay}"
IsEnabled="True"
Content="{Binding Name, Mode=TwoWay}"
Click="CheckBox_Click" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
And get the reference on the code behind:
private void CheckBox_Click(object sender, RoutedEventArgs e)
{
CheckBox chk = sender as CheckBox;
chk.IsEnabled = false;
}
Of course the problem here is that if you disable the checkbox you lose access to the Click envent.
Another choice is to use the VisualTreeHelper to get reference to your CheckBox when the selection change on the ListBox:
private void myList_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
ListBox list = sender as ListBox;
ListInfo current = list.SelectedItem as ListInfo;
List<CheckBox> checkBoxes = new List<CheckBox>();
getCheckBoxes(list, ref checkBoxes);
foreach (CheckBox checkBox in checkBoxes)
{
if (checkBox.Content.ToString() == current.Name)
{
checkBox.Foreground = new SolidColorBrush(Colors.Red);
}
}
}
public void getCheckBoxes(UIElement parent, ref List<CheckBox> items)
{
int count = VisualTreeHelper.GetChildrenCount(parent);
if (count > 0)
{
for (int i = 0; i < count; i++)
{
UIElement child = VisualTreeHelper.GetChild(parent, i) as UIElement;
if (child.GetType() == typeof(CheckBox))
{
items.Add(child as CheckBox);
}
getCheckBoxes(child, ref items);
}
}
}
This of course is not the best option for performance but you get more flexibility.
Here is a solution using RadioButtons:
http://leeontech.wordpress.com/2009/03/18/creating-radiobuttonlist/
It should be easy enough to change it to checkboxes.

Resources