I'm building a wp7 app in Silverlight. I have some content that gets loaded asynchronously, and messages that indicate that loading is not yet done. I'd like to have the loading messages disappear as soon as the content's list box is not empty. Is it possible to do this just in XAML? Something like binding the Visibility property to StoryListBox.ItemsSource.IsEmpty?
StoryListBox is populated by having its ItemsSource set to an observable collection after the data is available.
<TextBox x:Name="LoadingMessage" Text="Loading..." Grid.Row="0" />
<ProgressBar x:Name="LoadingProgress" IsIndeterminate="True" Style="{StaticResource PerformanceProgressBar}" />
<ListBox x:Name="StoryListBox" Grid.Row="0" />
Update: I tried the following, but it doesn't work:
<StackPanel x:Name="Loading" Grid.Row="0" Visibility="{Binding StoryListBox.ItemsSource.IsEmpty, Converter={StaticResource visibilityConverter}}">
<TextBox Text="Loading..." />
<ProgressBar IsIndeterminate="True" Style="{StaticResource PerformanceProgressBar}" />
</StackPanel>
<ListBox x:Name="StoryListBox" Grid.Row="1" />
The Loading stack panel never collapses.
You seem to have answered your own question. Yes, you can simply bind the Visibility (or Busy/IsBusy on a BusyIndicator control to some attribute of another control).
If the specific property you want to bind to is not a bindable property, simply bind to the other control and customise the converter to get the member property you want. If you have specific code examples, just post them and I can post a more specific solution.
The usual problem is that the types (for visibility) are incompatible with boolean values, so you need to specifier a converter in the binding. Google for Silverlight VisibilityConvertor (they are a dime a dozen). Here is mine:
namespace Common.ValueConverters
{
using System;
using System.Windows;
using System.Windows.Data;
public class VisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value is bool?)
{
if (string.IsNullOrEmpty((string)parameter))
{
return (value as bool?).Value ? Visibility.Visible : Visibility.Collapsed;
}
else
{
return (value as bool?).Value ? Visibility.Collapsed : Visibility.Visible;
}
}
throw new ArgumentException();
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
A use of the converter would look like:
<Grid Visibility="{Binding ShowDualView, Converter={StaticResource VisibilityConverter}}">
But quite frankly you are better of with a BusyIndicator control bound to an IsBusy property:
<Controls:BusyIndicator IsBusy="{Binding IsBusy}">
Just put it around the controls to you want to have hidden by the busy display.
Related
I have a big lists of objects which are binded to a ListBox. In that list box i am displaying the name of a file and a byte array of an image which is coming form WCF. I would display the files in the listbox depending on the scroll postion, so the file which are not visible from that scroll position to be set as Hidden.
I found on the internet a way which might help me but i cannot see a way that this will work.
I found convertors which should help me, and set up that class as a window resource. When I am opening the app all the items are converted to be visible.
This is the class:
class NullVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return value == null ? Visibility.Hidden : Visibility.Visible;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return value == null ? Visibility.Visible : Visibility.Hidden;
}
}
In Xaml i setup this class as a window Resource and i binded the functionality to the image and name in the Listbox items
<Window.Resources>
<view:NullVisibilityConverter x:Key="NullToVis"/>
</Window.Resources>
<Image Source="{Binding Path=Image}" Visibility="{Binding Path=Image, Converter={StaticResource NullToVis}}" Height="80" Width="80" Grid.Column="0"/>
<StackPanel Grid.Column="1" Visibility="{Binding Path=Image, Converter={StaticResource NullToVis}}" Orientation="Vertical" Width="80" Height="30">
<TextBlock Text="{Binding Path=Name}" Margin="5,1,0,1"/>
</StackPanel>
Does anyone have any idea how this might work?
So I have a ProgressRing and a TextBlock and I am trying to implement this basic hack, which is to display both elements when TextBlock's Text gets assigned a value (anything other than null), else both elements should hide when TextBlock's Text is null.
My Xaml looks like below. TextBlock's Text is binded to MessageForProgressRing and its Visibility is binded to both MessageForProgressRing and TargetNullValue. Same for me ProgressRing:
<StackPanel Panel.ZIndex="100" Grid.Column="1" HorizontalAlignment="Center" VerticalAlignment="Center">
<mahControls:ProgressRing Height="50" IsActive="True" Width="50" Visibility="{Binding MessageForProgressRing, TargetNullValue=Collapsed, FallbackValue=Visible}" Foreground="White" Margin="0,0,0.2,0" />
<TextBlock Text="{Binding MessageForProgressRing}" Visibility="{Binding MessageForProgressRing, TargetNullValue=Collapsed, FallbackValue=Visible}"/>
</StackPanel>
Then, in code behind I just trigger the property and assign it a value on some button event handlers:
private void closeApplicationButtonTask()
{
((CaptureViewModel)DataContext).MessageForProgressRing = "Closing... ";
Application.Current.MainWindow.Close();
}
However, in my ViewModelBase (the parent of all my view models) it pops an error on OnPropertyChanged saying:
Requested value 'Closing...' was not found.
I think I need a converter because Visibility is binded to Closing... right? If yes how can I achieve it?
P.S I couldn't do it in OnPropertyChanged because I don't see the value to assign it. Also I don't think it is a good idea since it gets called big time before, during and after the execution.
I usually prefer to solve this problem by having a boolean property in my view model (e.g. HasMessageForProgressRing or IsProgressRingVisible). It's usually a more general-purpose solution. Then you can use a BooleanToVisibilityConverter.
If you truly want to implement a converter, just create a class that implements IValueConverter. The Convert implementation of this should be a piece of cake for your simple use case. ConvertBack isn't necessary in most cases (and won't be in yours). It would look something like this:
public class NullToCollapsed : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return value != null ? Visibility.Visible : Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
<GroupBox x:Name="groupBox" Header="Operating System" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Height="74" Width="280">
<StackPanel>
<RadioButton GroupName="Os" Content="Windows 7 (64-bit)" IsChecked="True"/>
<RadioButton GroupName="Os" Content="Windows 7 (32-bit)" />
</StackPanel>
</GroupBox>
I have several radio button groups in my application
How can I access which one has been checked in the Code-Behind using C#?
Is it absolutely necessary to use x:Name= on each RadioButton or is there a better way?
Code samples always appreciated
Yes! There is a better way, its called binding. Outside of binding, you are pretty much stuck (I can imagine handling all the checked events separately, and assigning to an enum, but is that really better?)
For radio buttons, you would typically use an enum to represent all the possible values:
public enum OsTypes
{
Windows7_32,
Windows7_64
}
And then bind each of your radio buttons to a global "selected" property on your VM. You need a ValueEqualsConverter for this:
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return value.Equals(parameter);
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return ((bool)value) ? parameter : Binding.DoNothing;
}
And then your radio buttons look like:
<RadioButton Content="Windows 7 32-bit"
IsChecked= "{Binding CurrentOs,
Converter={StaticResource ValueEqualsConverter},
ConverterParameter={x:Static local:OsTypes.Windows7_32}}"
Of course, you have a property in your VM:
public OsTypes CurrentOs {get; set;}
No x:Name, complicated switch statements, or anything else. Nice, clean, and well designed. MVVM works with WPF, use it!
I have a couple of gauges in my app, and I can't figure out how to add a converter to the text binding. I read a couple of guides on msdn but I didn't manage to figure that out (I've been coding for WP8 for just a couple of weeks).
This is is a piece of the gauge:
<gauges:MarkerGaugeIndicator Value="0"
gauges:LinearGaugeRange.IndicatorOffset="35"
x:Name="GaugeBarValore"
IsAnimated="True">
<gauges:MarkerGaugeIndicator.MarkerTemplate>
<DataTemplate>
<Grid Width="73" Height="35" UseLayoutRounding="False" d:LayoutRounding="Auto" Margin="10,-2,0,0">
<TextBlock x:Name="GaugeBarPercent" Text="{Binding}"
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontSize="20"
FontWeight="Thin" Margin="6,4,32,4" Width="35"/>
<Grid.RenderTransform>
<CompositeTransform Rotation="90" TranslateX="49" TranslateY="12" />
</Grid.RenderTransform>
</Grid>
</DataTemplate>
</gauges:MarkerGaugeIndicator.MarkerTemplate>
</gauges:MarkerGaugeIndicator>
The binding itself works, but I can see a lot of decimal numbers while the value moves from a round value to another.
I want to add a converter like this method:
private String double2String(double valore)
{
return Convert.ToString(Math.Round(valore)) + "%";
}
I just don't know where to put this method and how to add this as a converter inside the binding.
Thank you for your help! :)
Sergio
Create a class to hold your Converter method that implements IValueConverter interface, Example class is bellow. You have to implement method Convert and ConvertBack.
public class DoubleToString : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return Math.Round((double)value).ToString() + "%";
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return double.Parse(value as string);
}
}
then add the namespace to your XAML page.
xmlns:convert="clr-namespace:Your_project_name"
Next add your converter as a Resource type i to your XAML page..
<phone:PhoneApplicationPage.Resources>
<convert:DoubleToString x:Key="DoubleConvert" />
</phone:PhoneApplicationPage.Resources>
The x:Key value is the name we are going to call in our binding statement.
Then perform the data binding. I have a simple slider and a textblock with sliders value bound to the textblocks Text property
<StackPanel>
<Slider Name="slider" Maximum="100" Minimum="0" />
<TextBlock Text="{Binding Value, ElementName=slider, Converter={StaticResource DoubleConvert}}" />
</StackPanel>
Define this converter as a resource in your parent view
<UserControl.Resources>
<local:double2String x:Key="convertDouble" />
</UserControl.Resources>
And add it to the binding
<TextBlock x:Name="GaugeBarPercent" Text="{Binding, Converter={StaticResource convertDouble}}"
Don't forget to import the namespace where the converter is defined to your view
xmlns:local="clr-namespace:YOUR_NAMESPACE"
The easier way is to use StringFormat. Like this:
<Label Text="{Binding Path=SomeProperty, StringFormat='{0:F2}%' }"/>
First off, let me state I am an amateur when it comes to wpf. I am trying to create an a collapsing/expanding type action for a wpf button, meaning when a user clicks a button, I would like the button selected to expand a new list of buttons beneath it. This is meant to be the navigation type for the web-enabled application. I would also like to create a collapsing interaction when the button is pressed again on an opened list.
There is a default control for this in WPF, named the Expander. If you want to change the appearance or the animations you could look into templating and styling of WPF. By default this control should meet most of your requirements.
My first idea is to use a ToggleButton and bind its IsChecked property to a the visibility of the element you want to show. You would need a converter then to convert the boolean Checked value to a Visibility value. Here is an example:
<Grid>
<Grid.Resources>
<BoolToVisibilityConverter x:Key="BoolToVisibilityConverter" />
</Grid.Ressources>
<ToggleButton x:Name="toggleButton" Content="Toggle" />
<Grid Visibility={Binding IsChecked, ElementName=toggleButton, Converter={StaticResource BoolToVisibilityConverter}}>
<!-- place your content here -->
</Grid>
</Grid>
The converter is a class implementig IValueConverter:
public class BoolToVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
bool i = value is bool ? (bool) value : false;
return i ? Visibility.Visible : Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Just use a ToggleButton and bind the visibility of the section to its IsChecked state as normally done in the Expander control (which you of course could just use instead).