I have an application with a UserControl that contains a ListBox. The DataTemplate of the ListBox adds a button to each item. The ListBox is inside a BusyIndicator. If I set IsBusy to true from a command bound to a ListBox item the BusyIndicator does not show. If I set IsBusy from the constructor of the UserControl it does show. I am hoping you can tell me why it doesn't show from the command bound from the button.
Here is the xaml for the UserControl:
<UserControl x:Class="BusyIndicatorIssue.WidgetView" xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation" xmlns:local="clr-namespace:BusyIndicatorIssue" mc:Ignorable="d" d:DesignHeight="450" d:DesignWidth="800"> <UserControl.DataContext> <local:WidgetViewModel/> </UserControl.DataContext> <UserControl.Resources> <local:WidgetView x:Key="topLevelParent"/> <DataTemplate x:Key="WidgetListBoxDataTemplate"> <DockPanel> <telerik:RadPathButton DockPanel.Dock="Right" PathGeometry="{telerik:RadGlyph Glyph=}" Command="{Binding Source={StaticResource topLevelParent}, Path=DataContext.RunLongProcessCommand}" CommandParameter="{Binding}"/> <TextBlock DockPanel.Dock="Left" FontSize="2" VerticalAlignment="Center" Text="{Binding Name}"/> </DockPanel> </DataTemplate> </UserControl.Resources> <telerik:RadBusyIndicator BusyContent="{Binding BusyContent}" IsBusy="{Binding IsBusy}" IsIndeterminate="True"> <telerik:RadListBox x:Name="WidgetListBox" Padding="8" ItemsSource="{Binding Widgets, Mode=TwoWay}" ItemTemplate="{StaticResource WidgetListBoxDataTemplate}"/> </telerik:RadBusyIndicator></UserControl>
Here is the ViewModel code:
using System.Collections.ObjectModel;using System.ComponentModel;using System.Windows;using Telerik.Windows.Controls;namespace BusyIndicatorIssue{ public class WidgetViewModel : ViewModelBase { public WidgetViewModel() { Widgets = new ObservableCollection<Widget> { new Widget("Widget 1"), new Widget("Widget 2"), new Widget("Widget 3"), new Widget("Widget 4"), new Widget("Widget 5"), new Widget("Widget 6"), new Widget("Widget 7"), new Widget("Widget 8"), new Widget("Widget 9") }; RunLongProcessCommand = new DelegateCommand(OnRunLongProcessCommandExecuted); //BusyContent = "Doing Something"; //IsBusy = true; } public DelegateCommand RunLongProcessCommand { get; set; } public ObservableCollection<Widget> Widgets { get; set; } public const string IsBusyPropertyName = "IsBusy"; private bool _isBusy; public bool IsBusy { get => _isBusy; set { if (_isBusy != value) { _isBusy = value; RaisePropertyChanged(); } } } public const string BusyContentPropertyName = "BusyContent"; private string _busyContent = default!; public string BusyContent { get => _busyContent; set { if (_busyContent != value) { _busyContent = value; RaisePropertyChanged(); } } } private void OnRunLongProcessCommandExecuted(object parameter) { var widget = (Widget)parameter; IsBusy = true; BusyContent = $"Doing something with {widget}"; var backgroundWorker = new BackgroundWorker(); backgroundWorker.DoWork += DoWork; backgroundWorker.RunWorkerCompleted += RunWorkerCompleted; _ = MessageBox.Show($"About to do something with {widget.Name}."); backgroundWorker.RunWorkerAsync(widget); } private void DoWork(object sender, DoWorkEventArgs e) { var widget = (Widget)e.Argument; System.Threading.Thread.Sleep(3000); _ = MessageBox.Show($"Done with {widget.Name}."); } private void RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { var backgroundWorker = sender as BackgroundWorker; if (backgroundWorker is not null) { backgroundWorker.DoWork -= DoWork; backgroundWorker.RunWorkerCompleted -= RunWorkerCompleted; InvokeOnUIThread(() => { IsBusy = false; }); } } }}
Here is the MainWindow xaml that hosts the UserControl:
<Window x:Class="BusyIndicatorIssue.MainWindow" xmlns:local="clr-namespace:BusyIndicatorIssue" mc:Ignorable="d" Height="300" Width="400" Title="MainWindow"> <DockPanel> <local:WidgetView DockPanel.Dock="Top" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/> </DockPanel></Window>
This is the simple model I am using for testing:
namespace BusyIndicatorIssue{ public class Widget { public Widget(string name) { Name = name; } public string Name { get; set; } }}
I was able to get the BusyIndicator to show by calling a command bound to a button placed directly in the main content of the UserControl. But I really need this application to have the buttons on each ListItem if possible.
Regards,
Don