Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
I have a question regarding running the same application in different "modes".
Basically, I want the app to be editable if you know what you're doing (e.g. you're an admin of sorts) but not if you're just using it.
I was thinking about making a bool/int value and make it hide show elements based on the mode. But is this the correct way? is there a better way to do this?
Thanks in advance!
You're right to have a single setting in the ViewModel that reflects the logical requirement. If there are only two options, it should be a boolean.
You probably have to think carefully about which controls need to be disabled, hidden or read-only. For example, control with a scroll bar shouldn't be disabled or the user won't be able to scroll. Text boxes could be either (read-only allow the user to select and copy, disabled doesn't). Other controls could be disabled, if there's some way that the user can enable them (e.g. a save button that is only enabled once there are changes to save), or hidden if the user will only ever have a read-only view.
You'll most likely need a few ValueConverters to convert the boolean 'IsAdmin' (or whatever) flag to values that the WPF expects. For example you can bind IsEnabled directly, but IsReadOnly will be a converter to invert it. If you want to hide something, you'll need a converter like this:
public class BoolVisiblityInverseConverter: IValueConverter
{
/// <inheritdoc />
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value.GetType() != typeof(bool))
{
throw new ArgumentException("BoolVisiblityInverseConverter can only accept a bool");
}
var val = (bool)value;
return val ? Visibility.Collapsed : Visibility.Visible;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Then you'll need to define it in the Resources section of your XAML
<converters:BoolVisiblityInverseConverter x:Key="BoolVisiblityInverseConverter" />
and bind it to the Visibility property
<Button Visibility="{Binding IsAdmin, Converter={StaticResource BoolVisiblityInverseConverter}}" />
The goal with this method is that the interface between the View and ViewModel is as simple as possible. The VM can decide what mode to use, and the View displays every control in a suitable state.
You can easy do it with Visibility Converter. Place editable control and readonly control in same place.
Xaml:
<Window.Resources>
<myapp:BoolToVisible x:Key="bool2visible"/>
</Window.Resources>
<Grid Margin="10">
<StackPanel>
<CheckBox IsChecked="{Binding Mode}">Mode on</CheckBox>
<StackPanel Margin="10">
<TextBlock Text="{Binding Number}" Visibility="{Binding Mode, Converter={StaticResource bool2visible}, ConverterParameter=1}"/>
<TextBox Text="{Binding Number}" Visibility="{Binding Mode, Converter={StaticResource bool2visible}}"/>
</StackPanel>
</StackPanel>
</Grid>
Bool to visibility converter
public class BoolToVisible:IValueConverter
{
public BoolToVisible()
{
}
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var val=(bool)value;
if (parameter?.ToString() == "1")
{
val=!val;
}
if (val)
{
return Visibility.Visible;
}else
return Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Related
I use in XAML an ItemsControl where and in its ItemsSource I make a Binding for an Enum, thus creating a list of RadRadioButton dynamically, and if someday another item is added to this enumerator my code will already create this new button and show it.
<ItemsControl ItemsSource="{Binding MyEnum}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<telerik:RadRadioButton GroupName="GroupMyEnum">
<TextBlock Text="{Binding Converter={StaticResource EnumDescriptionConverter}}"/>
</telerik:RadRadioButton>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Today I use a converter that takes the description of the Enum and shows instead of the value of the Enum.
But besides that I would like to change the order in which my list of buttons is generated, is this possible?
Example: If my list needs to be generated elsewhere in the interface, it must be generated in a different order than the enumerator was created.
Whether an Enum has the options A, B, C, D. At one point I would like to show as the first option D instead of A.
Was I clear enough?
Define a converter that takes MyEnum, change its order based on the value of converter's parameter and return the new list with the new order (ConverterParameter is optional, do not set it if you don't want to change the order of the list).
public class MyEnumCollectionConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is IEnumerable<MyEnum> input)
{
switch (parameter)
{
case "Case1":
// todo: change the order of input
return input;
case "Case2":
// todo: change the order of input
return input;
}
}
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Define the converter in your app.xaml (or at one of ItemsControl parents) and use it like this..
<ItemsControl ItemsSource="{Binding MyEnum, Converter={StaticResource MyEnumCollectionConverter}, ConverterParameter=Case1}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<telerik:RadRadioButton GroupName="GroupMyEnum">
<TextBlock Text="{Binding Converter={StaticResource EnumDescriptionConverter}}"/>
</telerik:RadRadioButton>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Note that you can do the EnumDescriptionConverter work inside MyEnumCollectionConverter, so your TextBlock can be just
<TextBlock Text="{Binding .}"/>
The first thing that pops to mind is sorting the ItemSource itself. I believe you use Linq sort by calling List.Sort() on the source itself and the list of order on the visual layer should be altered aswell.
More information about this can be found here.
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!
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).
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.