Silverlight BusyIndicator - silverlight

Is there a way to not show the BusyIndicator when it is not busy (IsBusy='false')? After I added the silverlight BusyIndicator into my UserControl it uses a large area so all other controls are moved down and the GUI looks not good anymore. I need it is hided when it's no busy and shows up when it's busy.
Thanks for help.
CK

I would use a standard BooleanToVisiblityConverter and bind the Visibilty to the IsBusy property like such:
<Grid Height="500" Width="500" Background="Blue">
<Grid.Resources>
<Converters:BoolToVisConverter x:Key="BoolToVis"/>
</Grid.Resources>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<StackPanel Width="75">
<ToggleButton x:Name="BusyButton" Content="Toggle Busy State"/>
<ToggleButton x:Name="ProgressButton" Content="Toggle ProgressButton State"/>
</StackPanel>
<toolkit:BusyIndicator Grid.Row="1" IsBusy="{Binding IsChecked, ElementName=BusyButton}"
Visibility="{Binding IsBusy, RelativeSource={RelativeSource Self}}"/>
<ProgressBar Grid.Row="2" Width="120" Height="10" Margin="4 2" VerticalAlignment="Center" IsIndeterminate="True"
Visibility="{Binding IsChecked, ElementName=ProgressButton, Converter={StaticResource BoolToVis}}"/>
</Grid>
I've provided both a BusyIndicator as well as ProgressBar is this example so you can see both in action.
The BooleanToVisibilityConverter is pretty standard and is implemented as such:
public class BoolToVisConverter : IValueConverter
{
#region IValueConverter Members
public virtual object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value == null) return Visibility.Collapsed;
return (bool)value == true ? Visibility.Visible : Visibility.Collapsed;
}
public virtual object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
#endregion
}

Related

WPF binding to an observable collection with hash key as index

The following code:
<UserControl x:Class="MyProgram.Views.MyControlContainer"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:MyProgram.Views"
xmlns:common_model="clr-namespace:MyProgram.Models;assembly=CommonTitan"
mc:Ignorable="d"
>
<Grid Background="White">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<local:MyControl x:Name="MyControl1" DataContext="{Binding MyControlCollection[8]}" Grid.Row="0" Grid.Column="0"/>
<local:MyControl x:Name="MyControl2" DataContext="{Binding MyControlCollection[9]}" Grid.Row="0" Grid.Column="1"/>
<local:MyControl x:Name="MyControl3" DataContext="{Binding MyControlCollection[10]}" Grid.Row="0" Grid.Column="2"/>
</Grid>
</UserControl>
Appropriately (as far as i can tell) binds me to the items that i specify in a collection. In real use it will use an observable dictionary and those indexes are hash values that i won't be able to hand code in. Is it possible to pass in the 2 known parameters into some sort of converter in order to get the hash? or even pass in the 2 values to the converter which will end up returning the item out of the observable dictionary?
You can pass 2 known value as converter parameters, for example:
<local:MyControl x:Name="MyControl1" DataContext="{Binding MyControlCollection, Converter={StaticResource CollectionConverter}, ConverterParameters='8.9'}" />
And in your converter class you can use it here, parse the parameter as string:
public class CollectionConverter: IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (parameter != null)
{
string[] param = (parameter as string).split('.');
if (int.Parse(param[0]) == 8)
return (value as ObservableCollection)[8];
else
return (value as ObservableCollection)[0];
}
return null;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new InvalidOperationException("cannot cast the value");
}
}

WPF MarkupExtension binding error

refers to implementing a multilanguage interface now I have a problem. I have a grid where its ItemSource it's a Dictionary<string, string>: I can't give the key value as parameter of the markup extension because I have the following exception
A 'Binding' cannot be set on the 'Value1' property of type 'TranslateMarkupExtension'.
A 'Binding' can only be set on a DependencyProperty of a DependencyObject.
This is the xaml where I use the markup extension:
<ItemsControl ItemsSource="{Binding MyDictionary}" Grid.Row="0">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid Margin="10">
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<Label Content="{TranslateMarkup Value1 = {Binding Path = Key}}" Grid.Column="0" />
<TextBox Tag="{Binding Key, Mode=OneWay}" Text="{Binding Value, Mode=OneWay}" Width="200" Height="46" VerticalContentAlignment="Center" Grid.Column="1" LostFocus="TextBox_OnLostFocus" />
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
I can't find any workaround..I need the dictionary as item source because the label will show the key and the textbox the corresponding value..I tried also replacing the dictionary with a list of object but the problem still remains.
Does anyone have a good hint? Thanks in advance.
As suggested by Ed Plunkett, the solution is the ValueConverter.
So the label is know this:
<Label Content="{Binding Key, Converter={StaticResource MultiLangConverter}}" Grid.Column="0" />
where my ValueConverter is the following:
public class StringToMultiLangConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var stringValue = (string) value;
if (string.IsNullOrEmpty(stringValue))
return string.Empty;
string multiLang = LangTranslator.GetString(stringValue);
return multiLang ?? value;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return DependencyProperty.UnsetValue;
}
}
Thanks for the help!

WPF binding TextBox and ObservableDictionary<Int64,String> (display String by Id)

Each item of my Employee's list has Post property. This property is Int64 type. Also, I have some ObservableDictionary<Int64,String> as static property. Each Employe must display the String value by its key.
DataTemplate for Employe item (I deleted the superfluous):
<DataTemplate x:Key="tmpEmploye">
<Border BorderThickness="3" BorderBrush="Gray" CornerRadius="5">
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding Path=Post}"/>
</StackPanel>
</Border>
</DataTemplate>
But this code displayed the Int64 value, not the String. String for getting static dictionary:
"{Binding Source={x:Static app:Program.Data}, Path=Posts}"
I know how solve it problem for ComboBox, but I don't know for TextBlock. For ComboBox I wrote it (it is works fine):
<ComboBox x:Name="cboPost" x:FieldModifier="public" Grid.Row="4" Grid.Column="1" HorizontalAlignment="Stretch"
VerticalAlignment="Stretch" Margin="2" Grid.ColumnSpan="2"
ItemsSource="{Binding Source={x:Static app:Program.Data}, Path=Posts}" DisplayMemberPath="Value"
SelectedValuePath="Key"
SelectedValue="{Binding Path=Post, Mode=TwoWay}">
</ComboBox>
But how can I solve it for TextBlock?
mmmmm, I'm sure I have developed something for this scenario before but I can't remember or find anything related!
IMO you can use a converter, so you pass your Post (Int64) to the converter and it returns the string value from the dictionary, although it must be a better solution.
[ValueConversion(typeof(Int64), typeof(string))]
public class PostToStringConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
// validation code, etc
return (from p in YourStaticDictionary where p.Key == Convert.ToInt64(value) select p.Value).FirstOrDefault();
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
}
}
XAML:
<Window ...
xmlns:l="clr-namespace:YourConverterNamespace"
...>
<Window.Resources>
<l:PostToStringConverter x:Key="converter" />
</Window.Resources>
<Grid>
<TextBlock Text="{Binding Post, Converter={StaticResource converter}}" />
</Grid>
</Window>

Binding a Silverlight TabControl to a complex object using a converter

I am trying to bind my data to a tab control. I have got the headers displaying fine but I'm not sure how I get the content of the tabs to bind correctly based on my item template shown below.
I think I'm missing something when I'm creating the tab item but I'm not sure how to bind my MyCustomObject to each of the TabItem's.
XAML:
<sdk:TabControl ItemsSource="{Binding Singles,Converter={StaticResource TabConverter}}">
<sdk:TabControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</sdk:TabControl.ItemsPanel>
<sdk:TabControl.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBox Text="{Binding Converter={StaticResource RoundNumberConverter}}" Margin="2" />
<ListBox x:Name="Matches" ItemsSource="{Binding}" Margin="2">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200" />
<ColumnDefinition Width="200" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Text="{Binding Converter={StaticResource SeedingConverter}, ConverterParameter=true}" Margin="2" />
<TextBlock Grid.Row="1" Grid.Column="0" Text="{Binding Converter={StaticResource SeedingConverter}, ConverterParameter=false}" Margin="2" />
<TextBlock Grid.Row="0" Grid.Column="1" Text="{Binding Path=Player1Name}" Margin="2" />
<TextBlock Grid.Row="1" Grid.Column="1" Text="{Binding Path=Player2Name}" Margin="2" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
</DataTemplate>
</sdk:TabControl.ItemTemplate>
</sdk:TabControl>
Converter:
public class TabConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
IEnumerable<IGrouping<string, MyCustomObject>> source = value as IEnumerable<IGrouping<string, MyCustomObject>>;
if (source != null)
{
var controlTemplate = (ControlTemplate)parameter;
List<TabItem> result = new List<TabItem>();
foreach (IGrouping<string, MyCustomObject> tab in source)
{
result.Add(new TabItem()
{
Header = tab.Key,
DataContext = tab //not sure this is right?
});
}
return result;
}
return null;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
You're most of the way there, the following works for me:
Strip out your DataTemplate and drop its contents straight into a new UserControl, for the example here, lets call it MatchesView.
Then in your TabConverter, amend the contents of the foreach loop to something like the following:
TabItem tabitem = new TabItem();
tabitem.Header = tab.Key;
MatchesView tabview = new MatchesView();
tabview.DataContext = parameter;
tabitem.Content = tabview;
result.Add(tabitem);
Note: this requires that you pass your ViewModel to the TabConverter as a parameter, eg:
<sdk:TabControl SelectedItem="{Binding YourSelectedObject}" ItemsSource="{Binding YourCollectionObject, Converter={StaticResource TabConverter}, ConverterParameter={StaticResource YourViewModel}, Mode=TwoWay}" />
Then, as you have your ViewModel in each instance of the new control, adjust your binding accordingly!
Note that the trick is that you have a separate binding for the single instance of the Selected object
checking your problem I think there is no support for that. The WPF's TabItem contains ItemTemplate & ContentTemplate. The first is the template for the Header, the second is the template for the "body". In silverlight we still have no ContentTemplate. Haven't seen an official statement yet, but this guy says it won't be supported till SL5.

WPF binding IValueConverter and the width of another control

The following code worked fine. There was an error elsewhere in the code. Still, the advice given is good.
I am trying to bind the Width of a TextBox to a percentage of the Width of a parent control. I know I can accomplish something similar by simply setting a Margin, but I was wondering why this doesn't work.
First, I set a reference to an IValueConverter in the resources collection of my user control:
<UserControl.Resources>
<local:TextBoxWidthConverter x:Key="txtWidthConv" />
</UserControl.Resources>
In the main xaml, I have the following:
<StackPanel Name="parentPanel" Width="300">
<ScrollViewer HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Hidden" Name="scroller" Width="{Binding Width,
ElementName=parentPanel, Converter={StaticResource txtWidthConv}}">
<StackPanel Orientation="Horizontal">
<TextBox></TextBox>
</StackPanel>
</ScrollViewer>
</StackPanel>
The ivalueconverter looks like this:
public class TextBoxWidthConverter : IValueConverter
{
#region IValueConverter Members
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
double result = (double)value;
if (!Double.IsNaN(result))
{
result = result * .25;
}
else
{
result = 100D;
}
return result;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new System.NotImplementedException("Not implemented.");
}
#endregion
}
Setting the width property does nothing here, let alone setting the IValueConverter. I would expect the ScrollViewer to be 1/4 the width of the parent StackPanel.
Set the ScrollViewer's HorizontalAlignment to something other than Stretch.
Also, you should bind to the ActualWidth property.
Let the layout system work for you instead of fighting it. Grid will automatically handle relative sizing:
<StackPanel Name="parentPanel" Width="300">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="3*" />
</Grid.ColumnDefinitions>
<ScrollViewer HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Hidden" Name="scroller">
<StackPanel Orientation="Horizontal">
<TextBox></TextBox>
</StackPanel>
</ScrollViewer>
</Grid>
</StackPanel>

Resources